comparison js/jquery-ui.js @ 47:886f43b26ee2 extractapp

move/remove develop folder
author Zoe Hong <zhong@mpiwg-berlin.mpg.de>
date Tue, 17 Mar 2015 10:54:13 +0100
parents
children
comparison
equal deleted inserted replaced
46:b3ca5d2b4d3f 47:886f43b26ee2
1 /*! jQuery UI - v1.11.3 - 2015-02-12
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.3
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.3",
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.3
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.3
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.3",
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.3
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.3
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.3",
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 down = toShow.length &&
2057 ( !toHide.length || ( toShow.index() < toHide.index() ) ),
2058 animate = this.options.animate || {},
2059 options = down && animate.down || animate,
2060 complete = function() {
2061 that._toggleComplete( data );
2062 };
2063
2064 if ( typeof options === "number" ) {
2065 duration = options;
2066 }
2067 if ( typeof options === "string" ) {
2068 easing = options;
2069 }
2070 // fall back from options to animation in case of partial down settings
2071 easing = easing || options.easing || animate.easing;
2072 duration = duration || options.duration || animate.duration;
2073
2074 if ( !toHide.length ) {
2075 return toShow.animate( this.showProps, duration, easing, complete );
2076 }
2077 if ( !toShow.length ) {
2078 return toHide.animate( this.hideProps, duration, easing, complete );
2079 }
2080
2081 total = toShow.show().outerHeight();
2082 toHide.animate( this.hideProps, {
2083 duration: duration,
2084 easing: easing,
2085 step: function( now, fx ) {
2086 fx.now = Math.round( now );
2087 }
2088 });
2089 toShow
2090 .hide()
2091 .animate( this.showProps, {
2092 duration: duration,
2093 easing: easing,
2094 complete: complete,
2095 step: function( now, fx ) {
2096 fx.now = Math.round( now );
2097 if ( fx.prop !== "height" ) {
2098 adjust += fx.now;
2099 } else if ( that.options.heightStyle !== "content" ) {
2100 fx.now = Math.round( total - toHide.outerHeight() - adjust );
2101 adjust = 0;
2102 }
2103 }
2104 });
2105 },
2106
2107 _toggleComplete: function( data ) {
2108 var toHide = data.oldPanel;
2109
2110 toHide
2111 .removeClass( "ui-accordion-content-active" )
2112 .prev()
2113 .removeClass( "ui-corner-top" )
2114 .addClass( "ui-corner-all" );
2115
2116 // Work around for rendering bug in IE (#5421)
2117 if ( toHide.length ) {
2118 toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className;
2119 }
2120 this._trigger( "activate", null, data );
2121 }
2122 });
2123
2124
2125 /*!
2126 * jQuery UI Menu 1.11.3
2127 * http://jqueryui.com
2128 *
2129 * Copyright jQuery Foundation and other contributors
2130 * Released under the MIT license.
2131 * http://jquery.org/license
2132 *
2133 * http://api.jqueryui.com/menu/
2134 */
2135
2136
2137 var menu = $.widget( "ui.menu", {
2138 version: "1.11.3",
2139 defaultElement: "<ul>",
2140 delay: 300,
2141 options: {
2142 icons: {
2143 submenu: "ui-icon-carat-1-e"
2144 },
2145 items: "> *",
2146 menus: "ul",
2147 position: {
2148 my: "left-1 top",
2149 at: "right top"
2150 },
2151 role: "menu",
2152
2153 // callbacks
2154 blur: null,
2155 focus: null,
2156 select: null
2157 },
2158
2159 _create: function() {
2160 this.activeMenu = this.element;
2161
2162 // Flag used to prevent firing of the click handler
2163 // as the event bubbles up through nested menus
2164 this.mouseHandled = false;
2165 this.element
2166 .uniqueId()
2167 .addClass( "ui-menu ui-widget ui-widget-content" )
2168 .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
2169 .attr({
2170 role: this.options.role,
2171 tabIndex: 0
2172 });
2173
2174 if ( this.options.disabled ) {
2175 this.element
2176 .addClass( "ui-state-disabled" )
2177 .attr( "aria-disabled", "true" );
2178 }
2179
2180 this._on({
2181 // Prevent focus from sticking to links inside menu after clicking
2182 // them (focus should always stay on UL during navigation).
2183 "mousedown .ui-menu-item": function( event ) {
2184 event.preventDefault();
2185 },
2186 "click .ui-menu-item": function( event ) {
2187 var target = $( event.target );
2188 if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
2189 this.select( event );
2190
2191 // Only set the mouseHandled flag if the event will bubble, see #9469.
2192 if ( !event.isPropagationStopped() ) {
2193 this.mouseHandled = true;
2194 }
2195
2196 // Open submenu on click
2197 if ( target.has( ".ui-menu" ).length ) {
2198 this.expand( event );
2199 } else if ( !this.element.is( ":focus" ) && $( this.document[ 0 ].activeElement ).closest( ".ui-menu" ).length ) {
2200
2201 // Redirect focus to the menu
2202 this.element.trigger( "focus", [ true ] );
2203
2204 // If the active item is on the top level, let it stay active.
2205 // Otherwise, blur the active item since it is no longer visible.
2206 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
2207 clearTimeout( this.timer );
2208 }
2209 }
2210 }
2211 },
2212 "mouseenter .ui-menu-item": function( event ) {
2213 // Ignore mouse events while typeahead is active, see #10458.
2214 // Prevents focusing the wrong item when typeahead causes a scroll while the mouse
2215 // is over an item in the menu
2216 if ( this.previousFilter ) {
2217 return;
2218 }
2219 var target = $( event.currentTarget );
2220 // Remove ui-state-active class from siblings of the newly focused menu item
2221 // to avoid a jump caused by adjacent elements both having a class with a border
2222 target.siblings( ".ui-state-active" ).removeClass( "ui-state-active" );
2223 this.focus( event, target );
2224 },
2225 mouseleave: "collapseAll",
2226 "mouseleave .ui-menu": "collapseAll",
2227 focus: function( event, keepActiveItem ) {
2228 // If there's already an active item, keep it active
2229 // If not, activate the first item
2230 var item = this.active || this.element.find( this.options.items ).eq( 0 );
2231
2232 if ( !keepActiveItem ) {
2233 this.focus( event, item );
2234 }
2235 },
2236 blur: function( event ) {
2237 this._delay(function() {
2238 if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
2239 this.collapseAll( event );
2240 }
2241 });
2242 },
2243 keydown: "_keydown"
2244 });
2245
2246 this.refresh();
2247
2248 // Clicks outside of a menu collapse any open menus
2249 this._on( this.document, {
2250 click: function( event ) {
2251 if ( this._closeOnDocumentClick( event ) ) {
2252 this.collapseAll( event );
2253 }
2254
2255 // Reset the mouseHandled flag
2256 this.mouseHandled = false;
2257 }
2258 });
2259 },
2260
2261 _destroy: function() {
2262 // Destroy (sub)menus
2263 this.element
2264 .removeAttr( "aria-activedescendant" )
2265 .find( ".ui-menu" ).addBack()
2266 .removeClass( "ui-menu ui-widget ui-widget-content ui-menu-icons ui-front" )
2267 .removeAttr( "role" )
2268 .removeAttr( "tabIndex" )
2269 .removeAttr( "aria-labelledby" )
2270 .removeAttr( "aria-expanded" )
2271 .removeAttr( "aria-hidden" )
2272 .removeAttr( "aria-disabled" )
2273 .removeUniqueId()
2274 .show();
2275
2276 // Destroy menu items
2277 this.element.find( ".ui-menu-item" )
2278 .removeClass( "ui-menu-item" )
2279 .removeAttr( "role" )
2280 .removeAttr( "aria-disabled" )
2281 .removeUniqueId()
2282 .removeClass( "ui-state-hover" )
2283 .removeAttr( "tabIndex" )
2284 .removeAttr( "role" )
2285 .removeAttr( "aria-haspopup" )
2286 .children().each( function() {
2287 var elem = $( this );
2288 if ( elem.data( "ui-menu-submenu-carat" ) ) {
2289 elem.remove();
2290 }
2291 });
2292
2293 // Destroy menu dividers
2294 this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
2295 },
2296
2297 _keydown: function( event ) {
2298 var match, prev, character, skip,
2299 preventDefault = true;
2300
2301 switch ( event.keyCode ) {
2302 case $.ui.keyCode.PAGE_UP:
2303 this.previousPage( event );
2304 break;
2305 case $.ui.keyCode.PAGE_DOWN:
2306 this.nextPage( event );
2307 break;
2308 case $.ui.keyCode.HOME:
2309 this._move( "first", "first", event );
2310 break;
2311 case $.ui.keyCode.END:
2312 this._move( "last", "last", event );
2313 break;
2314 case $.ui.keyCode.UP:
2315 this.previous( event );
2316 break;
2317 case $.ui.keyCode.DOWN:
2318 this.next( event );
2319 break;
2320 case $.ui.keyCode.LEFT:
2321 this.collapse( event );
2322 break;
2323 case $.ui.keyCode.RIGHT:
2324 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
2325 this.expand( event );
2326 }
2327 break;
2328 case $.ui.keyCode.ENTER:
2329 case $.ui.keyCode.SPACE:
2330 this._activate( event );
2331 break;
2332 case $.ui.keyCode.ESCAPE:
2333 this.collapse( event );
2334 break;
2335 default:
2336 preventDefault = false;
2337 prev = this.previousFilter || "";
2338 character = String.fromCharCode( event.keyCode );
2339 skip = false;
2340
2341 clearTimeout( this.filterTimer );
2342
2343 if ( character === prev ) {
2344 skip = true;
2345 } else {
2346 character = prev + character;
2347 }
2348
2349 match = this._filterMenuItems( character );
2350 match = skip && match.index( this.active.next() ) !== -1 ?
2351 this.active.nextAll( ".ui-menu-item" ) :
2352 match;
2353
2354 // If no matches on the current filter, reset to the last character pressed
2355 // to move down the menu to the first item that starts with that character
2356 if ( !match.length ) {
2357 character = String.fromCharCode( event.keyCode );
2358 match = this._filterMenuItems( character );
2359 }
2360
2361 if ( match.length ) {
2362 this.focus( event, match );
2363 this.previousFilter = character;
2364 this.filterTimer = this._delay(function() {
2365 delete this.previousFilter;
2366 }, 1000 );
2367 } else {
2368 delete this.previousFilter;
2369 }
2370 }
2371
2372 if ( preventDefault ) {
2373 event.preventDefault();
2374 }
2375 },
2376
2377 _activate: function( event ) {
2378 if ( !this.active.is( ".ui-state-disabled" ) ) {
2379 if ( this.active.is( "[aria-haspopup='true']" ) ) {
2380 this.expand( event );
2381 } else {
2382 this.select( event );
2383 }
2384 }
2385 },
2386
2387 refresh: function() {
2388 var menus, items,
2389 that = this,
2390 icon = this.options.icons.submenu,
2391 submenus = this.element.find( this.options.menus );
2392
2393 this.element.toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length );
2394
2395 // Initialize nested menus
2396 submenus.filter( ":not(.ui-menu)" )
2397 .addClass( "ui-menu ui-widget ui-widget-content ui-front" )
2398 .hide()
2399 .attr({
2400 role: this.options.role,
2401 "aria-hidden": "true",
2402 "aria-expanded": "false"
2403 })
2404 .each(function() {
2405 var menu = $( this ),
2406 item = menu.parent(),
2407 submenuCarat = $( "<span>" )
2408 .addClass( "ui-menu-icon ui-icon " + icon )
2409 .data( "ui-menu-submenu-carat", true );
2410
2411 item
2412 .attr( "aria-haspopup", "true" )
2413 .prepend( submenuCarat );
2414 menu.attr( "aria-labelledby", item.attr( "id" ) );
2415 });
2416
2417 menus = submenus.add( this.element );
2418 items = menus.find( this.options.items );
2419
2420 // Initialize menu-items containing spaces and/or dashes only as dividers
2421 items.not( ".ui-menu-item" ).each(function() {
2422 var item = $( this );
2423 if ( that._isDivider( item ) ) {
2424 item.addClass( "ui-widget-content ui-menu-divider" );
2425 }
2426 });
2427
2428 // Don't refresh list items that are already adapted
2429 items.not( ".ui-menu-item, .ui-menu-divider" )
2430 .addClass( "ui-menu-item" )
2431 .uniqueId()
2432 .attr({
2433 tabIndex: -1,
2434 role: this._itemRole()
2435 });
2436
2437 // Add aria-disabled attribute to any disabled menu item
2438 items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
2439
2440 // If the active item has been removed, blur the menu
2441 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
2442 this.blur();
2443 }
2444 },
2445
2446 _itemRole: function() {
2447 return {
2448 menu: "menuitem",
2449 listbox: "option"
2450 }[ this.options.role ];
2451 },
2452
2453 _setOption: function( key, value ) {
2454 if ( key === "icons" ) {
2455 this.element.find( ".ui-menu-icon" )
2456 .removeClass( this.options.icons.submenu )
2457 .addClass( value.submenu );
2458 }
2459 if ( key === "disabled" ) {
2460 this.element
2461 .toggleClass( "ui-state-disabled", !!value )
2462 .attr( "aria-disabled", value );
2463 }
2464 this._super( key, value );
2465 },
2466
2467 focus: function( event, item ) {
2468 var nested, focused;
2469 this.blur( event, event && event.type === "focus" );
2470
2471 this._scrollIntoView( item );
2472
2473 this.active = item.first();
2474 focused = this.active.addClass( "ui-state-focus" ).removeClass( "ui-state-active" );
2475 // Only update aria-activedescendant if there's a role
2476 // otherwise we assume focus is managed elsewhere
2477 if ( this.options.role ) {
2478 this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
2479 }
2480
2481 // Highlight active parent menu item, if any
2482 this.active
2483 .parent()
2484 .closest( ".ui-menu-item" )
2485 .addClass( "ui-state-active" );
2486
2487 if ( event && event.type === "keydown" ) {
2488 this._close();
2489 } else {
2490 this.timer = this._delay(function() {
2491 this._close();
2492 }, this.delay );
2493 }
2494
2495 nested = item.children( ".ui-menu" );
2496 if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
2497 this._startOpening(nested);
2498 }
2499 this.activeMenu = item.parent();
2500
2501 this._trigger( "focus", event, { item: item } );
2502 },
2503
2504 _scrollIntoView: function( item ) {
2505 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
2506 if ( this._hasScroll() ) {
2507 borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
2508 paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
2509 offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
2510 scroll = this.activeMenu.scrollTop();
2511 elementHeight = this.activeMenu.height();
2512 itemHeight = item.outerHeight();
2513
2514 if ( offset < 0 ) {
2515 this.activeMenu.scrollTop( scroll + offset );
2516 } else if ( offset + itemHeight > elementHeight ) {
2517 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
2518 }
2519 }
2520 },
2521
2522 blur: function( event, fromFocus ) {
2523 if ( !fromFocus ) {
2524 clearTimeout( this.timer );
2525 }
2526
2527 if ( !this.active ) {
2528 return;
2529 }
2530
2531 this.active.removeClass( "ui-state-focus" );
2532 this.active = null;
2533
2534 this._trigger( "blur", event, { item: this.active } );
2535 },
2536
2537 _startOpening: function( submenu ) {
2538 clearTimeout( this.timer );
2539
2540 // Don't open if already open fixes a Firefox bug that caused a .5 pixel
2541 // shift in the submenu position when mousing over the carat icon
2542 if ( submenu.attr( "aria-hidden" ) !== "true" ) {
2543 return;
2544 }
2545
2546 this.timer = this._delay(function() {
2547 this._close();
2548 this._open( submenu );
2549 }, this.delay );
2550 },
2551
2552 _open: function( submenu ) {
2553 var position = $.extend({
2554 of: this.active
2555 }, this.options.position );
2556
2557 clearTimeout( this.timer );
2558 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
2559 .hide()
2560 .attr( "aria-hidden", "true" );
2561
2562 submenu
2563 .show()
2564 .removeAttr( "aria-hidden" )
2565 .attr( "aria-expanded", "true" )
2566 .position( position );
2567 },
2568
2569 collapseAll: function( event, all ) {
2570 clearTimeout( this.timer );
2571 this.timer = this._delay(function() {
2572 // If we were passed an event, look for the submenu that contains the event
2573 var currentMenu = all ? this.element :
2574 $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
2575
2576 // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
2577 if ( !currentMenu.length ) {
2578 currentMenu = this.element;
2579 }
2580
2581 this._close( currentMenu );
2582
2583 this.blur( event );
2584 this.activeMenu = currentMenu;
2585 }, this.delay );
2586 },
2587
2588 // With no arguments, closes the currently active menu - if nothing is active
2589 // it closes all menus. If passed an argument, it will search for menus BELOW
2590 _close: function( startMenu ) {
2591 if ( !startMenu ) {
2592 startMenu = this.active ? this.active.parent() : this.element;
2593 }
2594
2595 startMenu
2596 .find( ".ui-menu" )
2597 .hide()
2598 .attr( "aria-hidden", "true" )
2599 .attr( "aria-expanded", "false" )
2600 .end()
2601 .find( ".ui-state-active" ).not( ".ui-state-focus" )
2602 .removeClass( "ui-state-active" );
2603 },
2604
2605 _closeOnDocumentClick: function( event ) {
2606 return !$( event.target ).closest( ".ui-menu" ).length;
2607 },
2608
2609 _isDivider: function( item ) {
2610
2611 // Match hyphen, em dash, en dash
2612 return !/[^\-\u2014\u2013\s]/.test( item.text() );
2613 },
2614
2615 collapse: function( event ) {
2616 var newItem = this.active &&
2617 this.active.parent().closest( ".ui-menu-item", this.element );
2618 if ( newItem && newItem.length ) {
2619 this._close();
2620 this.focus( event, newItem );
2621 }
2622 },
2623
2624 expand: function( event ) {
2625 var newItem = this.active &&
2626 this.active
2627 .children( ".ui-menu " )
2628 .find( this.options.items )
2629 .first();
2630
2631 if ( newItem && newItem.length ) {
2632 this._open( newItem.parent() );
2633
2634 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
2635 this._delay(function() {
2636 this.focus( event, newItem );
2637 });
2638 }
2639 },
2640
2641 next: function( event ) {
2642 this._move( "next", "first", event );
2643 },
2644
2645 previous: function( event ) {
2646 this._move( "prev", "last", event );
2647 },
2648
2649 isFirstItem: function() {
2650 return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
2651 },
2652
2653 isLastItem: function() {
2654 return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
2655 },
2656
2657 _move: function( direction, filter, event ) {
2658 var next;
2659 if ( this.active ) {
2660 if ( direction === "first" || direction === "last" ) {
2661 next = this.active
2662 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
2663 .eq( -1 );
2664 } else {
2665 next = this.active
2666 [ direction + "All" ]( ".ui-menu-item" )
2667 .eq( 0 );
2668 }
2669 }
2670 if ( !next || !next.length || !this.active ) {
2671 next = this.activeMenu.find( this.options.items )[ filter ]();
2672 }
2673
2674 this.focus( event, next );
2675 },
2676
2677 nextPage: function( event ) {
2678 var item, base, height;
2679
2680 if ( !this.active ) {
2681 this.next( event );
2682 return;
2683 }
2684 if ( this.isLastItem() ) {
2685 return;
2686 }
2687 if ( this._hasScroll() ) {
2688 base = this.active.offset().top;
2689 height = this.element.height();
2690 this.active.nextAll( ".ui-menu-item" ).each(function() {
2691 item = $( this );
2692 return item.offset().top - base - height < 0;
2693 });
2694
2695 this.focus( event, item );
2696 } else {
2697 this.focus( event, this.activeMenu.find( this.options.items )
2698 [ !this.active ? "first" : "last" ]() );
2699 }
2700 },
2701
2702 previousPage: function( event ) {
2703 var item, base, height;
2704 if ( !this.active ) {
2705 this.next( event );
2706 return;
2707 }
2708 if ( this.isFirstItem() ) {
2709 return;
2710 }
2711 if ( this._hasScroll() ) {
2712 base = this.active.offset().top;
2713 height = this.element.height();
2714 this.active.prevAll( ".ui-menu-item" ).each(function() {
2715 item = $( this );
2716 return item.offset().top - base + height > 0;
2717 });
2718
2719 this.focus( event, item );
2720 } else {
2721 this.focus( event, this.activeMenu.find( this.options.items ).first() );
2722 }
2723 },
2724
2725 _hasScroll: function() {
2726 return this.element.outerHeight() < this.element.prop( "scrollHeight" );
2727 },
2728
2729 select: function( event ) {
2730 // TODO: It should never be possible to not have an active item at this
2731 // point, but the tests don't trigger mouseenter before click.
2732 this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
2733 var ui = { item: this.active };
2734 if ( !this.active.has( ".ui-menu" ).length ) {
2735 this.collapseAll( event, true );
2736 }
2737 this._trigger( "select", event, ui );
2738 },
2739
2740 _filterMenuItems: function(character) {
2741 var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
2742 regex = new RegExp( "^" + escapedCharacter, "i" );
2743
2744 return this.activeMenu
2745 .find( this.options.items )
2746
2747 // Only match on items, not dividers or other content (#10571)
2748 .filter( ".ui-menu-item" )
2749 .filter(function() {
2750 return regex.test( $.trim( $( this ).text() ) );
2751 });
2752 }
2753 });
2754
2755
2756 /*!
2757 * jQuery UI Autocomplete 1.11.3
2758 * http://jqueryui.com
2759 *
2760 * Copyright jQuery Foundation and other contributors
2761 * Released under the MIT license.
2762 * http://jquery.org/license
2763 *
2764 * http://api.jqueryui.com/autocomplete/
2765 */
2766
2767
2768 $.widget( "ui.autocomplete", {
2769 version: "1.11.3",
2770 defaultElement: "<input>",
2771 options: {
2772 appendTo: null,
2773 autoFocus: false,
2774 delay: 300,
2775 minLength: 1,
2776 position: {
2777 my: "left top",
2778 at: "left bottom",
2779 collision: "none"
2780 },
2781 source: null,
2782
2783 // callbacks
2784 change: null,
2785 close: null,
2786 focus: null,
2787 open: null,
2788 response: null,
2789 search: null,
2790 select: null
2791 },
2792
2793 requestIndex: 0,
2794 pending: 0,
2795
2796 _create: function() {
2797 // Some browsers only repeat keydown events, not keypress events,
2798 // so we use the suppressKeyPress flag to determine if we've already
2799 // handled the keydown event. #7269
2800 // Unfortunately the code for & in keypress is the same as the up arrow,
2801 // so we use the suppressKeyPressRepeat flag to avoid handling keypress
2802 // events when we know the keydown event was used to modify the
2803 // search term. #7799
2804 var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
2805 nodeName = this.element[ 0 ].nodeName.toLowerCase(),
2806 isTextarea = nodeName === "textarea",
2807 isInput = nodeName === "input";
2808
2809 this.isMultiLine =
2810 // Textareas are always multi-line
2811 isTextarea ? true :
2812 // Inputs are always single-line, even if inside a contentEditable element
2813 // IE also treats inputs as contentEditable
2814 isInput ? false :
2815 // All other element types are determined by whether or not they're contentEditable
2816 this.element.prop( "isContentEditable" );
2817
2818 this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
2819 this.isNewMenu = true;
2820
2821 this.element
2822 .addClass( "ui-autocomplete-input" )
2823 .attr( "autocomplete", "off" );
2824
2825 this._on( this.element, {
2826 keydown: function( event ) {
2827 if ( this.element.prop( "readOnly" ) ) {
2828 suppressKeyPress = true;
2829 suppressInput = true;
2830 suppressKeyPressRepeat = true;
2831 return;
2832 }
2833
2834 suppressKeyPress = false;
2835 suppressInput = false;
2836 suppressKeyPressRepeat = false;
2837 var keyCode = $.ui.keyCode;
2838 switch ( event.keyCode ) {
2839 case keyCode.PAGE_UP:
2840 suppressKeyPress = true;
2841 this._move( "previousPage", event );
2842 break;
2843 case keyCode.PAGE_DOWN:
2844 suppressKeyPress = true;
2845 this._move( "nextPage", event );
2846 break;
2847 case keyCode.UP:
2848 suppressKeyPress = true;
2849 this._keyEvent( "previous", event );
2850 break;
2851 case keyCode.DOWN:
2852 suppressKeyPress = true;
2853 this._keyEvent( "next", event );
2854 break;
2855 case keyCode.ENTER:
2856 // when menu is open and has focus
2857 if ( this.menu.active ) {
2858 // #6055 - Opera still allows the keypress to occur
2859 // which causes forms to submit
2860 suppressKeyPress = true;
2861 event.preventDefault();
2862 this.menu.select( event );
2863 }
2864 break;
2865 case keyCode.TAB:
2866 if ( this.menu.active ) {
2867 this.menu.select( event );
2868 }
2869 break;
2870 case keyCode.ESCAPE:
2871 if ( this.menu.element.is( ":visible" ) ) {
2872 if ( !this.isMultiLine ) {
2873 this._value( this.term );
2874 }
2875 this.close( event );
2876 // Different browsers have different default behavior for escape
2877 // Single press can mean undo or clear
2878 // Double press in IE means clear the whole form
2879 event.preventDefault();
2880 }
2881 break;
2882 default:
2883 suppressKeyPressRepeat = true;
2884 // search timeout should be triggered before the input value is changed
2885 this._searchTimeout( event );
2886 break;
2887 }
2888 },
2889 keypress: function( event ) {
2890 if ( suppressKeyPress ) {
2891 suppressKeyPress = false;
2892 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
2893 event.preventDefault();
2894 }
2895 return;
2896 }
2897 if ( suppressKeyPressRepeat ) {
2898 return;
2899 }
2900
2901 // replicate some key handlers to allow them to repeat in Firefox and Opera
2902 var keyCode = $.ui.keyCode;
2903 switch ( event.keyCode ) {
2904 case keyCode.PAGE_UP:
2905 this._move( "previousPage", event );
2906 break;
2907 case keyCode.PAGE_DOWN:
2908 this._move( "nextPage", event );
2909 break;
2910 case keyCode.UP:
2911 this._keyEvent( "previous", event );
2912 break;
2913 case keyCode.DOWN:
2914 this._keyEvent( "next", event );
2915 break;
2916 }
2917 },
2918 input: function( event ) {
2919 if ( suppressInput ) {
2920 suppressInput = false;
2921 event.preventDefault();
2922 return;
2923 }
2924 this._searchTimeout( event );
2925 },
2926 focus: function() {
2927 this.selectedItem = null;
2928 this.previous = this._value();
2929 },
2930 blur: function( event ) {
2931 if ( this.cancelBlur ) {
2932 delete this.cancelBlur;
2933 return;
2934 }
2935
2936 clearTimeout( this.searching );
2937 this.close( event );
2938 this._change( event );
2939 }
2940 });
2941
2942 this._initSource();
2943 this.menu = $( "<ul>" )
2944 .addClass( "ui-autocomplete ui-front" )
2945 .appendTo( this._appendTo() )
2946 .menu({
2947 // disable ARIA support, the live region takes care of that
2948 role: null
2949 })
2950 .hide()
2951 .menu( "instance" );
2952
2953 this._on( this.menu.element, {
2954 mousedown: function( event ) {
2955 // prevent moving focus out of the text field
2956 event.preventDefault();
2957
2958 // IE doesn't prevent moving focus even with event.preventDefault()
2959 // so we set a flag to know when we should ignore the blur event
2960 this.cancelBlur = true;
2961 this._delay(function() {
2962 delete this.cancelBlur;
2963 });
2964
2965 // clicking on the scrollbar causes focus to shift to the body
2966 // but we can't detect a mouseup or a click immediately afterward
2967 // so we have to track the next mousedown and close the menu if
2968 // the user clicks somewhere outside of the autocomplete
2969 var menuElement = this.menu.element[ 0 ];
2970 if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
2971 this._delay(function() {
2972 var that = this;
2973 this.document.one( "mousedown", function( event ) {
2974 if ( event.target !== that.element[ 0 ] &&
2975 event.target !== menuElement &&
2976 !$.contains( menuElement, event.target ) ) {
2977 that.close();
2978 }
2979 });
2980 });
2981 }
2982 },
2983 menufocus: function( event, ui ) {
2984 var label, item;
2985 // support: Firefox
2986 // Prevent accidental activation of menu items in Firefox (#7024 #9118)
2987 if ( this.isNewMenu ) {
2988 this.isNewMenu = false;
2989 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
2990 this.menu.blur();
2991
2992 this.document.one( "mousemove", function() {
2993 $( event.target ).trigger( event.originalEvent );
2994 });
2995
2996 return;
2997 }
2998 }
2999
3000 item = ui.item.data( "ui-autocomplete-item" );
3001 if ( false !== this._trigger( "focus", event, { item: item } ) ) {
3002 // use value to match what will end up in the input, if it was a key event
3003 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
3004 this._value( item.value );
3005 }
3006 }
3007
3008 // Announce the value in the liveRegion
3009 label = ui.item.attr( "aria-label" ) || item.value;
3010 if ( label && $.trim( label ).length ) {
3011 this.liveRegion.children().hide();
3012 $( "<div>" ).text( label ).appendTo( this.liveRegion );
3013 }
3014 },
3015 menuselect: function( event, ui ) {
3016 var item = ui.item.data( "ui-autocomplete-item" ),
3017 previous = this.previous;
3018
3019 // only trigger when focus was lost (click on menu)
3020 if ( this.element[ 0 ] !== this.document[ 0 ].activeElement ) {
3021 this.element.focus();
3022 this.previous = previous;
3023 // #6109 - IE triggers two focus events and the second
3024 // is asynchronous, so we need to reset the previous
3025 // term synchronously and asynchronously :-(
3026 this._delay(function() {
3027 this.previous = previous;
3028 this.selectedItem = item;
3029 });
3030 }
3031
3032 if ( false !== this._trigger( "select", event, { item: item } ) ) {
3033 this._value( item.value );
3034 }
3035 // reset the term after the select event
3036 // this allows custom select handling to work properly
3037 this.term = this._value();
3038
3039 this.close( event );
3040 this.selectedItem = item;
3041 }
3042 });
3043
3044 this.liveRegion = $( "<span>", {
3045 role: "status",
3046 "aria-live": "assertive",
3047 "aria-relevant": "additions"
3048 })
3049 .addClass( "ui-helper-hidden-accessible" )
3050 .appendTo( this.document[ 0 ].body );
3051
3052 // turning off autocomplete prevents the browser from remembering the
3053 // value when navigating through history, so we re-enable autocomplete
3054 // if the page is unloaded before the widget is destroyed. #7790
3055 this._on( this.window, {
3056 beforeunload: function() {
3057 this.element.removeAttr( "autocomplete" );
3058 }
3059 });
3060 },
3061
3062 _destroy: function() {
3063 clearTimeout( this.searching );
3064 this.element
3065 .removeClass( "ui-autocomplete-input" )
3066 .removeAttr( "autocomplete" );
3067 this.menu.element.remove();
3068 this.liveRegion.remove();
3069 },
3070
3071 _setOption: function( key, value ) {
3072 this._super( key, value );
3073 if ( key === "source" ) {
3074 this._initSource();
3075 }
3076 if ( key === "appendTo" ) {
3077 this.menu.element.appendTo( this._appendTo() );
3078 }
3079 if ( key === "disabled" && value && this.xhr ) {
3080 this.xhr.abort();
3081 }
3082 },
3083
3084 _appendTo: function() {
3085 var element = this.options.appendTo;
3086
3087 if ( element ) {
3088 element = element.jquery || element.nodeType ?
3089 $( element ) :
3090 this.document.find( element ).eq( 0 );
3091 }
3092
3093 if ( !element || !element[ 0 ] ) {
3094 element = this.element.closest( ".ui-front" );
3095 }
3096
3097 if ( !element.length ) {
3098 element = this.document[ 0 ].body;
3099 }
3100
3101 return element;
3102 },
3103
3104 _initSource: function() {
3105 var array, url,
3106 that = this;
3107 if ( $.isArray( this.options.source ) ) {
3108 array = this.options.source;
3109 this.source = function( request, response ) {
3110 response( $.ui.autocomplete.filter( array, request.term ) );
3111 };
3112 } else if ( typeof this.options.source === "string" ) {
3113 url = this.options.source;
3114 this.source = function( request, response ) {
3115 if ( that.xhr ) {
3116 that.xhr.abort();
3117 }
3118 that.xhr = $.ajax({
3119 url: url,
3120 data: request,
3121 dataType: "json",
3122 success: function( data ) {
3123 response( data );
3124 },
3125 error: function() {
3126 response([]);
3127 }
3128 });
3129 };
3130 } else {
3131 this.source = this.options.source;
3132 }
3133 },
3134
3135 _searchTimeout: function( event ) {
3136 clearTimeout( this.searching );
3137 this.searching = this._delay(function() {
3138
3139 // Search if the value has changed, or if the user retypes the same value (see #7434)
3140 var equalValues = this.term === this._value(),
3141 menuVisible = this.menu.element.is( ":visible" ),
3142 modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
3143
3144 if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
3145 this.selectedItem = null;
3146 this.search( null, event );
3147 }
3148 }, this.options.delay );
3149 },
3150
3151 search: function( value, event ) {
3152 value = value != null ? value : this._value();
3153
3154 // always save the actual value, not the one passed as an argument
3155 this.term = this._value();
3156
3157 if ( value.length < this.options.minLength ) {
3158 return this.close( event );
3159 }
3160
3161 if ( this._trigger( "search", event ) === false ) {
3162 return;
3163 }
3164
3165 return this._search( value );
3166 },
3167
3168 _search: function( value ) {
3169 this.pending++;
3170 this.element.addClass( "ui-autocomplete-loading" );
3171 this.cancelSearch = false;
3172
3173 this.source( { term: value }, this._response() );
3174 },
3175
3176 _response: function() {
3177 var index = ++this.requestIndex;
3178
3179 return $.proxy(function( content ) {
3180 if ( index === this.requestIndex ) {
3181 this.__response( content );
3182 }
3183
3184 this.pending--;
3185 if ( !this.pending ) {
3186 this.element.removeClass( "ui-autocomplete-loading" );
3187 }
3188 }, this );
3189 },
3190
3191 __response: function( content ) {
3192 if ( content ) {
3193 content = this._normalize( content );
3194 }
3195 this._trigger( "response", null, { content: content } );
3196 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
3197 this._suggest( content );
3198 this._trigger( "open" );
3199 } else {
3200 // use ._close() instead of .close() so we don't cancel future searches
3201 this._close();
3202 }
3203 },
3204
3205 close: function( event ) {
3206 this.cancelSearch = true;
3207 this._close( event );
3208 },
3209
3210 _close: function( event ) {
3211 if ( this.menu.element.is( ":visible" ) ) {
3212 this.menu.element.hide();
3213 this.menu.blur();
3214 this.isNewMenu = true;
3215 this._trigger( "close", event );
3216 }
3217 },
3218
3219 _change: function( event ) {
3220 if ( this.previous !== this._value() ) {
3221 this._trigger( "change", event, { item: this.selectedItem } );
3222 }
3223 },
3224
3225 _normalize: function( items ) {
3226 // assume all items have the right format when the first item is complete
3227 if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
3228 return items;
3229 }
3230 return $.map( items, function( item ) {
3231 if ( typeof item === "string" ) {
3232 return {
3233 label: item,
3234 value: item
3235 };
3236 }
3237 return $.extend( {}, item, {
3238 label: item.label || item.value,
3239 value: item.value || item.label
3240 });
3241 });
3242 },
3243
3244 _suggest: function( items ) {
3245 var ul = this.menu.element.empty();
3246 this._renderMenu( ul, items );
3247 this.isNewMenu = true;
3248 this.menu.refresh();
3249
3250 // size and position menu
3251 ul.show();
3252 this._resizeMenu();
3253 ul.position( $.extend({
3254 of: this.element
3255 }, this.options.position ) );
3256
3257 if ( this.options.autoFocus ) {
3258 this.menu.next();
3259 }
3260 },
3261
3262 _resizeMenu: function() {
3263 var ul = this.menu.element;
3264 ul.outerWidth( Math.max(
3265 // Firefox wraps long text (possibly a rounding bug)
3266 // so we add 1px to avoid the wrapping (#7513)
3267 ul.width( "" ).outerWidth() + 1,
3268 this.element.outerWidth()
3269 ) );
3270 },
3271
3272 _renderMenu: function( ul, items ) {
3273 var that = this;
3274 $.each( items, function( index, item ) {
3275 that._renderItemData( ul, item );
3276 });
3277 },
3278
3279 _renderItemData: function( ul, item ) {
3280 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
3281 },
3282
3283 _renderItem: function( ul, item ) {
3284 return $( "<li>" ).text( item.label ).appendTo( ul );
3285 },
3286
3287 _move: function( direction, event ) {
3288 if ( !this.menu.element.is( ":visible" ) ) {
3289 this.search( null, event );
3290 return;
3291 }
3292 if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
3293 this.menu.isLastItem() && /^next/.test( direction ) ) {
3294
3295 if ( !this.isMultiLine ) {
3296 this._value( this.term );
3297 }
3298
3299 this.menu.blur();
3300 return;
3301 }
3302 this.menu[ direction ]( event );
3303 },
3304
3305 widget: function() {
3306 return this.menu.element;
3307 },
3308
3309 _value: function() {
3310 return this.valueMethod.apply( this.element, arguments );
3311 },
3312
3313 _keyEvent: function( keyEvent, event ) {
3314 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
3315 this._move( keyEvent, event );
3316
3317 // prevents moving cursor to beginning/end of the text field in some browsers
3318 event.preventDefault();
3319 }
3320 }
3321 });
3322
3323 $.extend( $.ui.autocomplete, {
3324 escapeRegex: function( value ) {
3325 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
3326 },
3327 filter: function( array, term ) {
3328 var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
3329 return $.grep( array, function( value ) {
3330 return matcher.test( value.label || value.value || value );
3331 });
3332 }
3333 });
3334
3335 // live region extension, adding a `messages` option
3336 // NOTE: This is an experimental API. We are still investigating
3337 // a full solution for string manipulation and internationalization.
3338 $.widget( "ui.autocomplete", $.ui.autocomplete, {
3339 options: {
3340 messages: {
3341 noResults: "No search results.",
3342 results: function( amount ) {
3343 return amount + ( amount > 1 ? " results are" : " result is" ) +
3344 " available, use up and down arrow keys to navigate.";
3345 }
3346 }
3347 },
3348
3349 __response: function( content ) {
3350 var message;
3351 this._superApply( arguments );
3352 if ( this.options.disabled || this.cancelSearch ) {
3353 return;
3354 }
3355 if ( content && content.length ) {
3356 message = this.options.messages.results( content.length );
3357 } else {
3358 message = this.options.messages.noResults;
3359 }
3360 this.liveRegion.children().hide();
3361 $( "<div>" ).text( message ).appendTo( this.liveRegion );
3362 }
3363 });
3364
3365 var autocomplete = $.ui.autocomplete;
3366
3367
3368 /*!
3369 * jQuery UI Button 1.11.3
3370 * http://jqueryui.com
3371 *
3372 * Copyright jQuery Foundation and other contributors
3373 * Released under the MIT license.
3374 * http://jquery.org/license
3375 *
3376 * http://api.jqueryui.com/button/
3377 */
3378
3379
3380 var lastActive,
3381 baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
3382 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",
3383 formResetHandler = function() {
3384 var form = $( this );
3385 setTimeout(function() {
3386 form.find( ":ui-button" ).button( "refresh" );
3387 }, 1 );
3388 },
3389 radioGroup = function( radio ) {
3390 var name = radio.name,
3391 form = radio.form,
3392 radios = $( [] );
3393 if ( name ) {
3394 name = name.replace( /'/g, "\\'" );
3395 if ( form ) {
3396 radios = $( form ).find( "[name='" + name + "'][type=radio]" );
3397 } else {
3398 radios = $( "[name='" + name + "'][type=radio]", radio.ownerDocument )
3399 .filter(function() {
3400 return !this.form;
3401 });
3402 }
3403 }
3404 return radios;
3405 };
3406
3407 $.widget( "ui.button", {
3408 version: "1.11.3",
3409 defaultElement: "<button>",
3410 options: {
3411 disabled: null,
3412 text: true,
3413 label: null,
3414 icons: {
3415 primary: null,
3416 secondary: null
3417 }
3418 },
3419 _create: function() {
3420 this.element.closest( "form" )
3421 .unbind( "reset" + this.eventNamespace )
3422 .bind( "reset" + this.eventNamespace, formResetHandler );
3423
3424 if ( typeof this.options.disabled !== "boolean" ) {
3425 this.options.disabled = !!this.element.prop( "disabled" );
3426 } else {
3427 this.element.prop( "disabled", this.options.disabled );
3428 }
3429
3430 this._determineButtonType();
3431 this.hasTitle = !!this.buttonElement.attr( "title" );
3432
3433 var that = this,
3434 options = this.options,
3435 toggleButton = this.type === "checkbox" || this.type === "radio",
3436 activeClass = !toggleButton ? "ui-state-active" : "";
3437
3438 if ( options.label === null ) {
3439 options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html());
3440 }
3441
3442 this._hoverable( this.buttonElement );
3443
3444 this.buttonElement
3445 .addClass( baseClasses )
3446 .attr( "role", "button" )
3447 .bind( "mouseenter" + this.eventNamespace, function() {
3448 if ( options.disabled ) {
3449 return;
3450 }
3451 if ( this === lastActive ) {
3452 $( this ).addClass( "ui-state-active" );
3453 }
3454 })
3455 .bind( "mouseleave" + this.eventNamespace, function() {
3456 if ( options.disabled ) {
3457 return;
3458 }
3459 $( this ).removeClass( activeClass );
3460 })
3461 .bind( "click" + this.eventNamespace, function( event ) {
3462 if ( options.disabled ) {
3463 event.preventDefault();
3464 event.stopImmediatePropagation();
3465 }
3466 });
3467
3468 // Can't use _focusable() because the element that receives focus
3469 // and the element that gets the ui-state-focus class are different
3470 this._on({
3471 focus: function() {
3472 this.buttonElement.addClass( "ui-state-focus" );
3473 },
3474 blur: function() {
3475 this.buttonElement.removeClass( "ui-state-focus" );
3476 }
3477 });
3478
3479 if ( toggleButton ) {
3480 this.element.bind( "change" + this.eventNamespace, function() {
3481 that.refresh();
3482 });
3483 }
3484
3485 if ( this.type === "checkbox" ) {
3486 this.buttonElement.bind( "click" + this.eventNamespace, function() {
3487 if ( options.disabled ) {
3488 return false;
3489 }
3490 });
3491 } else if ( this.type === "radio" ) {
3492 this.buttonElement.bind( "click" + this.eventNamespace, function() {
3493 if ( options.disabled ) {
3494 return false;
3495 }
3496 $( this ).addClass( "ui-state-active" );
3497 that.buttonElement.attr( "aria-pressed", "true" );
3498
3499 var radio = that.element[ 0 ];
3500 radioGroup( radio )
3501 .not( radio )
3502 .map(function() {
3503 return $( this ).button( "widget" )[ 0 ];
3504 })
3505 .removeClass( "ui-state-active" )
3506 .attr( "aria-pressed", "false" );
3507 });
3508 } else {
3509 this.buttonElement
3510 .bind( "mousedown" + this.eventNamespace, function() {
3511 if ( options.disabled ) {
3512 return false;
3513 }
3514 $( this ).addClass( "ui-state-active" );
3515 lastActive = this;
3516 that.document.one( "mouseup", function() {
3517 lastActive = null;
3518 });
3519 })
3520 .bind( "mouseup" + this.eventNamespace, function() {
3521 if ( options.disabled ) {
3522 return false;
3523 }
3524 $( this ).removeClass( "ui-state-active" );
3525 })
3526 .bind( "keydown" + this.eventNamespace, function(event) {
3527 if ( options.disabled ) {
3528 return false;
3529 }
3530 if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) {
3531 $( this ).addClass( "ui-state-active" );
3532 }
3533 })
3534 // see #8559, we bind to blur here in case the button element loses
3535 // focus between keydown and keyup, it would be left in an "active" state
3536 .bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() {
3537 $( this ).removeClass( "ui-state-active" );
3538 });
3539
3540 if ( this.buttonElement.is("a") ) {
3541 this.buttonElement.keyup(function(event) {
3542 if ( event.keyCode === $.ui.keyCode.SPACE ) {
3543 // TODO pass through original event correctly (just as 2nd argument doesn't work)
3544 $( this ).click();
3545 }
3546 });
3547 }
3548 }
3549
3550 this._setOption( "disabled", options.disabled );
3551 this._resetButton();
3552 },
3553
3554 _determineButtonType: function() {
3555 var ancestor, labelSelector, checked;
3556
3557 if ( this.element.is("[type=checkbox]") ) {
3558 this.type = "checkbox";
3559 } else if ( this.element.is("[type=radio]") ) {
3560 this.type = "radio";
3561 } else if ( this.element.is("input") ) {
3562 this.type = "input";
3563 } else {
3564 this.type = "button";
3565 }
3566
3567 if ( this.type === "checkbox" || this.type === "radio" ) {
3568 // we don't search against the document in case the element
3569 // is disconnected from the DOM
3570 ancestor = this.element.parents().last();
3571 labelSelector = "label[for='" + this.element.attr("id") + "']";
3572 this.buttonElement = ancestor.find( labelSelector );
3573 if ( !this.buttonElement.length ) {
3574 ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
3575 this.buttonElement = ancestor.filter( labelSelector );
3576 if ( !this.buttonElement.length ) {
3577 this.buttonElement = ancestor.find( labelSelector );
3578 }
3579 }
3580 this.element.addClass( "ui-helper-hidden-accessible" );
3581
3582 checked = this.element.is( ":checked" );
3583 if ( checked ) {
3584 this.buttonElement.addClass( "ui-state-active" );
3585 }
3586 this.buttonElement.prop( "aria-pressed", checked );
3587 } else {
3588 this.buttonElement = this.element;
3589 }
3590 },
3591
3592 widget: function() {
3593 return this.buttonElement;
3594 },
3595
3596 _destroy: function() {
3597 this.element
3598 .removeClass( "ui-helper-hidden-accessible" );
3599 this.buttonElement
3600 .removeClass( baseClasses + " ui-state-active " + typeClasses )
3601 .removeAttr( "role" )
3602 .removeAttr( "aria-pressed" )
3603 .html( this.buttonElement.find(".ui-button-text").html() );
3604
3605 if ( !this.hasTitle ) {
3606 this.buttonElement.removeAttr( "title" );
3607 }
3608 },
3609
3610 _setOption: function( key, value ) {
3611 this._super( key, value );
3612 if ( key === "disabled" ) {
3613 this.widget().toggleClass( "ui-state-disabled", !!value );
3614 this.element.prop( "disabled", !!value );
3615 if ( value ) {
3616 if ( this.type === "checkbox" || this.type === "radio" ) {
3617 this.buttonElement.removeClass( "ui-state-focus" );
3618 } else {
3619 this.buttonElement.removeClass( "ui-state-focus ui-state-active" );
3620 }
3621 }
3622 return;
3623 }
3624 this._resetButton();
3625 },
3626
3627 refresh: function() {
3628 //See #8237 & #8828
3629 var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" );
3630
3631 if ( isDisabled !== this.options.disabled ) {
3632 this._setOption( "disabled", isDisabled );
3633 }
3634 if ( this.type === "radio" ) {
3635 radioGroup( this.element[0] ).each(function() {
3636 if ( $( this ).is( ":checked" ) ) {
3637 $( this ).button( "widget" )
3638 .addClass( "ui-state-active" )
3639 .attr( "aria-pressed", "true" );
3640 } else {
3641 $( this ).button( "widget" )
3642 .removeClass( "ui-state-active" )
3643 .attr( "aria-pressed", "false" );
3644 }
3645 });
3646 } else if ( this.type === "checkbox" ) {
3647 if ( this.element.is( ":checked" ) ) {
3648 this.buttonElement
3649 .addClass( "ui-state-active" )
3650 .attr( "aria-pressed", "true" );
3651 } else {
3652 this.buttonElement
3653 .removeClass( "ui-state-active" )
3654 .attr( "aria-pressed", "false" );
3655 }
3656 }
3657 },
3658
3659 _resetButton: function() {
3660 if ( this.type === "input" ) {
3661 if ( this.options.label ) {
3662 this.element.val( this.options.label );
3663 }
3664 return;
3665 }
3666 var buttonElement = this.buttonElement.removeClass( typeClasses ),
3667 buttonText = $( "<span></span>", this.document[0] )
3668 .addClass( "ui-button-text" )
3669 .html( this.options.label )
3670 .appendTo( buttonElement.empty() )
3671 .text(),
3672 icons = this.options.icons,
3673 multipleIcons = icons.primary && icons.secondary,
3674 buttonClasses = [];
3675
3676 if ( icons.primary || icons.secondary ) {
3677 if ( this.options.text ) {
3678 buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
3679 }
3680
3681 if ( icons.primary ) {
3682 buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
3683 }
3684
3685 if ( icons.secondary ) {
3686 buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
3687 }
3688
3689 if ( !this.options.text ) {
3690 buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );
3691
3692 if ( !this.hasTitle ) {
3693 buttonElement.attr( "title", $.trim( buttonText ) );
3694 }
3695 }
3696 } else {
3697 buttonClasses.push( "ui-button-text-only" );
3698 }
3699 buttonElement.addClass( buttonClasses.join( " " ) );
3700 }
3701 });
3702
3703 $.widget( "ui.buttonset", {
3704 version: "1.11.3",
3705 options: {
3706 items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"
3707 },
3708
3709 _create: function() {
3710 this.element.addClass( "ui-buttonset" );
3711 },
3712
3713 _init: function() {
3714 this.refresh();
3715 },
3716
3717 _setOption: function( key, value ) {
3718 if ( key === "disabled" ) {
3719 this.buttons.button( "option", key, value );
3720 }
3721
3722 this._super( key, value );
3723 },
3724
3725 refresh: function() {
3726 var rtl = this.element.css( "direction" ) === "rtl",
3727 allButtons = this.element.find( this.options.items ),
3728 existingButtons = allButtons.filter( ":ui-button" );
3729
3730 // Initialize new buttons
3731 allButtons.not( ":ui-button" ).button();
3732
3733 // Refresh existing buttons
3734 existingButtons.button( "refresh" );
3735
3736 this.buttons = allButtons
3737 .map(function() {
3738 return $( this ).button( "widget" )[ 0 ];
3739 })
3740 .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
3741 .filter( ":first" )
3742 .addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
3743 .end()
3744 .filter( ":last" )
3745 .addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
3746 .end()
3747 .end();
3748 },
3749
3750 _destroy: function() {
3751 this.element.removeClass( "ui-buttonset" );
3752 this.buttons
3753 .map(function() {
3754 return $( this ).button( "widget" )[ 0 ];
3755 })
3756 .removeClass( "ui-corner-left ui-corner-right" )
3757 .end()
3758 .button( "destroy" );
3759 }
3760 });
3761
3762 var button = $.ui.button;
3763
3764
3765 /*!
3766 * jQuery UI Datepicker 1.11.3
3767 * http://jqueryui.com
3768 *
3769 * Copyright jQuery Foundation and other contributors
3770 * Released under the MIT license.
3771 * http://jquery.org/license
3772 *
3773 * http://api.jqueryui.com/datepicker/
3774 */
3775
3776
3777 $.extend($.ui, { datepicker: { version: "1.11.3" } });
3778
3779 var datepicker_instActive;
3780
3781 function datepicker_getZindex( elem ) {
3782 var position, value;
3783 while ( elem.length && elem[ 0 ] !== document ) {
3784 // Ignore z-index if position is set to a value where z-index is ignored by the browser
3785 // This makes behavior of this function consistent across browsers
3786 // WebKit always returns auto if the element is positioned
3787 position = elem.css( "position" );
3788 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
3789 // IE returns 0 when zIndex is not specified
3790 // other browsers return a string
3791 // we ignore the case of nested elements with an explicit value of 0
3792 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
3793 value = parseInt( elem.css( "zIndex" ), 10 );
3794 if ( !isNaN( value ) && value !== 0 ) {
3795 return value;
3796 }
3797 }
3798 elem = elem.parent();
3799 }
3800
3801 return 0;
3802 }
3803 /* Date picker manager.
3804 Use the singleton instance of this class, $.datepicker, to interact with the date picker.
3805 Settings for (groups of) date pickers are maintained in an instance object,
3806 allowing multiple different settings on the same page. */
3807
3808 function Datepicker() {
3809 this._curInst = null; // The current instance in use
3810 this._keyEvent = false; // If the last event was a key event
3811 this._disabledInputs = []; // List of date picker inputs that have been disabled
3812 this._datepickerShowing = false; // True if the popup picker is showing , false if not
3813 this._inDialog = false; // True if showing within a "dialog", false if not
3814 this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
3815 this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
3816 this._appendClass = "ui-datepicker-append"; // The name of the append marker class
3817 this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
3818 this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
3819 this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
3820 this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
3821 this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
3822 this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
3823 this.regional = []; // Available regional settings, indexed by language code
3824 this.regional[""] = { // Default regional settings
3825 closeText: "Done", // Display text for close link
3826 prevText: "Prev", // Display text for previous month link
3827 nextText: "Next", // Display text for next month link
3828 currentText: "Today", // Display text for current month link
3829 monthNames: ["January","February","March","April","May","June",
3830 "July","August","September","October","November","December"], // Names of months for drop-down and formatting
3831 monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
3832 dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
3833 dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
3834 dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
3835 weekHeader: "Wk", // Column header for week of the year
3836 dateFormat: "mm/dd/yy", // See format options on parseDate
3837 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
3838 isRTL: false, // True if right-to-left language, false if left-to-right
3839 showMonthAfterYear: false, // True if the year select precedes month, false for month then year
3840 yearSuffix: "" // Additional text to append to the year in the month headers
3841 };
3842 this._defaults = { // Global defaults for all the date picker instances
3843 showOn: "focus", // "focus" for popup on focus,
3844 // "button" for trigger button, or "both" for either
3845 showAnim: "fadeIn", // Name of jQuery animation for popup
3846 showOptions: {}, // Options for enhanced animations
3847 defaultDate: null, // Used when field is blank: actual date,
3848 // +/-number for offset from today, null for today
3849 appendText: "", // Display text following the input box, e.g. showing the format
3850 buttonText: "...", // Text for trigger button
3851 buttonImage: "", // URL for trigger button image
3852 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
3853 hideIfNoPrevNext: false, // True to hide next/previous month links
3854 // if not applicable, false to just disable them
3855 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
3856 gotoCurrent: false, // True if today link goes back to current selection instead
3857 changeMonth: false, // True if month can be selected directly, false if only prev/next
3858 changeYear: false, // True if year can be selected directly, false if only prev/next
3859 yearRange: "c-10:c+10", // Range of years to display in drop-down,
3860 // either relative to today's year (-nn:+nn), relative to currently displayed year
3861 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
3862 showOtherMonths: false, // True to show dates in other months, false to leave blank
3863 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
3864 showWeek: false, // True to show week of the year, false to not show it
3865 calculateWeek: this.iso8601Week, // How to calculate the week of the year,
3866 // takes a Date and returns the number of the week for it
3867 shortYearCutoff: "+10", // Short year values < this are in the current century,
3868 // > this are in the previous century,
3869 // string value starting with "+" for current year + value
3870 minDate: null, // The earliest selectable date, or null for no limit
3871 maxDate: null, // The latest selectable date, or null for no limit
3872 duration: "fast", // Duration of display/closure
3873 beforeShowDay: null, // Function that takes a date and returns an array with
3874 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
3875 // [2] = cell title (optional), e.g. $.datepicker.noWeekends
3876 beforeShow: null, // Function that takes an input field and
3877 // returns a set of custom settings for the date picker
3878 onSelect: null, // Define a callback function when a date is selected
3879 onChangeMonthYear: null, // Define a callback function when the month or year is changed
3880 onClose: null, // Define a callback function when the datepicker is closed
3881 numberOfMonths: 1, // Number of months to show at a time
3882 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
3883 stepMonths: 1, // Number of months to step back/forward
3884 stepBigMonths: 12, // Number of months to step back/forward for the big links
3885 altField: "", // Selector for an alternate field to store selected dates into
3886 altFormat: "", // The date format to use for the alternate field
3887 constrainInput: true, // The input is constrained by the current date format
3888 showButtonPanel: false, // True to show button panel, false to not show it
3889 autoSize: false, // True to size the input for the date format, false to leave as is
3890 disabled: false // The initial disabled state
3891 };
3892 $.extend(this._defaults, this.regional[""]);
3893 this.regional.en = $.extend( true, {}, this.regional[ "" ]);
3894 this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
3895 this.dpDiv = datepicker_bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
3896 }
3897
3898 $.extend(Datepicker.prototype, {
3899 /* Class name added to elements to indicate already configured with a date picker. */
3900 markerClassName: "hasDatepicker",
3901
3902 //Keep track of the maximum number of rows displayed (see #7043)
3903 maxRows: 4,
3904
3905 // TODO rename to "widget" when switching to widget factory
3906 _widgetDatepicker: function() {
3907 return this.dpDiv;
3908 },
3909
3910 /* Override the default settings for all instances of the date picker.
3911 * @param settings object - the new settings to use as defaults (anonymous object)
3912 * @return the manager object
3913 */
3914 setDefaults: function(settings) {
3915 datepicker_extendRemove(this._defaults, settings || {});
3916 return this;
3917 },
3918
3919 /* Attach the date picker to a jQuery selection.
3920 * @param target element - the target input field or division or span
3921 * @param settings object - the new settings to use for this date picker instance (anonymous)
3922 */
3923 _attachDatepicker: function(target, settings) {
3924 var nodeName, inline, inst;
3925 nodeName = target.nodeName.toLowerCase();
3926 inline = (nodeName === "div" || nodeName === "span");
3927 if (!target.id) {
3928 this.uuid += 1;
3929 target.id = "dp" + this.uuid;
3930 }
3931 inst = this._newInst($(target), inline);
3932 inst.settings = $.extend({}, settings || {});
3933 if (nodeName === "input") {
3934 this._connectDatepicker(target, inst);
3935 } else if (inline) {
3936 this._inlineDatepicker(target, inst);
3937 }
3938 },
3939
3940 /* Create a new instance object. */
3941 _newInst: function(target, inline) {
3942 var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
3943 return {id: id, input: target, // associated target
3944 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
3945 drawMonth: 0, drawYear: 0, // month being drawn
3946 inline: inline, // is datepicker inline or not
3947 dpDiv: (!inline ? this.dpDiv : // presentation div
3948 datepicker_bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
3949 },
3950
3951 /* Attach the date picker to an input field. */
3952 _connectDatepicker: function(target, inst) {
3953 var input = $(target);
3954 inst.append = $([]);
3955 inst.trigger = $([]);
3956 if (input.hasClass(this.markerClassName)) {
3957 return;
3958 }
3959 this._attachments(input, inst);
3960 input.addClass(this.markerClassName).keydown(this._doKeyDown).
3961 keypress(this._doKeyPress).keyup(this._doKeyUp);
3962 this._autoSize(inst);
3963 $.data(target, "datepicker", inst);
3964 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
3965 if( inst.settings.disabled ) {
3966 this._disableDatepicker( target );
3967 }
3968 },
3969
3970 /* Make attachments based on settings. */
3971 _attachments: function(input, inst) {
3972 var showOn, buttonText, buttonImage,
3973 appendText = this._get(inst, "appendText"),
3974 isRTL = this._get(inst, "isRTL");
3975
3976 if (inst.append) {
3977 inst.append.remove();
3978 }
3979 if (appendText) {
3980 inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
3981 input[isRTL ? "before" : "after"](inst.append);
3982 }
3983
3984 input.unbind("focus", this._showDatepicker);
3985
3986 if (inst.trigger) {
3987 inst.trigger.remove();
3988 }
3989
3990 showOn = this._get(inst, "showOn");
3991 if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
3992 input.focus(this._showDatepicker);
3993 }
3994 if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
3995 buttonText = this._get(inst, "buttonText");
3996 buttonImage = this._get(inst, "buttonImage");
3997 inst.trigger = $(this._get(inst, "buttonImageOnly") ?
3998 $("<img/>").addClass(this._triggerClass).
3999 attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
4000 $("<button type='button'></button>").addClass(this._triggerClass).
4001 html(!buttonImage ? buttonText : $("<img/>").attr(
4002 { src:buttonImage, alt:buttonText, title:buttonText })));
4003 input[isRTL ? "before" : "after"](inst.trigger);
4004 inst.trigger.click(function() {
4005 if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
4006 $.datepicker._hideDatepicker();
4007 } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
4008 $.datepicker._hideDatepicker();
4009 $.datepicker._showDatepicker(input[0]);
4010 } else {
4011 $.datepicker._showDatepicker(input[0]);
4012 }
4013 return false;
4014 });
4015 }
4016 },
4017
4018 /* Apply the maximum length for the date format. */
4019 _autoSize: function(inst) {
4020 if (this._get(inst, "autoSize") && !inst.inline) {
4021 var findMax, max, maxI, i,
4022 date = new Date(2009, 12 - 1, 20), // Ensure double digits
4023 dateFormat = this._get(inst, "dateFormat");
4024
4025 if (dateFormat.match(/[DM]/)) {
4026 findMax = function(names) {
4027 max = 0;
4028 maxI = 0;
4029 for (i = 0; i < names.length; i++) {
4030 if (names[i].length > max) {
4031 max = names[i].length;
4032 maxI = i;
4033 }
4034 }
4035 return maxI;
4036 };
4037 date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
4038 "monthNames" : "monthNamesShort"))));
4039 date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
4040 "dayNames" : "dayNamesShort"))) + 20 - date.getDay());
4041 }
4042 inst.input.attr("size", this._formatDate(inst, date).length);
4043 }
4044 },
4045
4046 /* Attach an inline date picker to a div. */
4047 _inlineDatepicker: function(target, inst) {
4048 var divSpan = $(target);
4049 if (divSpan.hasClass(this.markerClassName)) {
4050 return;
4051 }
4052 divSpan.addClass(this.markerClassName).append(inst.dpDiv);
4053 $.data(target, "datepicker", inst);
4054 this._setDate(inst, this._getDefaultDate(inst), true);
4055 this._updateDatepicker(inst);
4056 this._updateAlternate(inst);
4057 //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
4058 if( inst.settings.disabled ) {
4059 this._disableDatepicker( target );
4060 }
4061 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
4062 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
4063 inst.dpDiv.css( "display", "block" );
4064 },
4065
4066 /* Pop-up the date picker in a "dialog" box.
4067 * @param input element - ignored
4068 * @param date string or Date - the initial date to display
4069 * @param onSelect function - the function to call when a date is selected
4070 * @param settings object - update the dialog date picker instance's settings (anonymous object)
4071 * @param pos int[2] - coordinates for the dialog's position within the screen or
4072 * event - with x/y coordinates or
4073 * leave empty for default (screen centre)
4074 * @return the manager object
4075 */
4076 _dialogDatepicker: function(input, date, onSelect, settings, pos) {
4077 var id, browserWidth, browserHeight, scrollX, scrollY,
4078 inst = this._dialogInst; // internal instance
4079
4080 if (!inst) {
4081 this.uuid += 1;
4082 id = "dp" + this.uuid;
4083 this._dialogInput = $("<input type='text' id='" + id +
4084 "' style='position: absolute; top: -100px; width: 0px;'/>");
4085 this._dialogInput.keydown(this._doKeyDown);
4086 $("body").append(this._dialogInput);
4087 inst = this._dialogInst = this._newInst(this._dialogInput, false);
4088 inst.settings = {};
4089 $.data(this._dialogInput[0], "datepicker", inst);
4090 }
4091 datepicker_extendRemove(inst.settings, settings || {});
4092 date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
4093 this._dialogInput.val(date);
4094
4095 this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
4096 if (!this._pos) {
4097 browserWidth = document.documentElement.clientWidth;
4098 browserHeight = document.documentElement.clientHeight;
4099 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
4100 scrollY = document.documentElement.scrollTop || document.body.scrollTop;
4101 this._pos = // should use actual width/height below
4102 [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
4103 }
4104
4105 // move input on screen for focus, but hidden behind dialog
4106 this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
4107 inst.settings.onSelect = onSelect;
4108 this._inDialog = true;
4109 this.dpDiv.addClass(this._dialogClass);
4110 this._showDatepicker(this._dialogInput[0]);
4111 if ($.blockUI) {
4112 $.blockUI(this.dpDiv);
4113 }
4114 $.data(this._dialogInput[0], "datepicker", inst);
4115 return this;
4116 },
4117
4118 /* Detach a datepicker from its control.
4119 * @param target element - the target input field or division or span
4120 */
4121 _destroyDatepicker: function(target) {
4122 var nodeName,
4123 $target = $(target),
4124 inst = $.data(target, "datepicker");
4125
4126 if (!$target.hasClass(this.markerClassName)) {
4127 return;
4128 }
4129
4130 nodeName = target.nodeName.toLowerCase();
4131 $.removeData(target, "datepicker");
4132 if (nodeName === "input") {
4133 inst.append.remove();
4134 inst.trigger.remove();
4135 $target.removeClass(this.markerClassName).
4136 unbind("focus", this._showDatepicker).
4137 unbind("keydown", this._doKeyDown).
4138 unbind("keypress", this._doKeyPress).
4139 unbind("keyup", this._doKeyUp);
4140 } else if (nodeName === "div" || nodeName === "span") {
4141 $target.removeClass(this.markerClassName).empty();
4142 }
4143
4144 if ( datepicker_instActive === inst ) {
4145 datepicker_instActive = null;
4146 }
4147 },
4148
4149 /* Enable the date picker to a jQuery selection.
4150 * @param target element - the target input field or division or span
4151 */
4152 _enableDatepicker: function(target) {
4153 var nodeName, inline,
4154 $target = $(target),
4155 inst = $.data(target, "datepicker");
4156
4157 if (!$target.hasClass(this.markerClassName)) {
4158 return;
4159 }
4160
4161 nodeName = target.nodeName.toLowerCase();
4162 if (nodeName === "input") {
4163 target.disabled = false;
4164 inst.trigger.filter("button").
4165 each(function() { this.disabled = false; }).end().
4166 filter("img").css({opacity: "1.0", cursor: ""});
4167 } else if (nodeName === "div" || nodeName === "span") {
4168 inline = $target.children("." + this._inlineClass);
4169 inline.children().removeClass("ui-state-disabled");
4170 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
4171 prop("disabled", false);
4172 }
4173 this._disabledInputs = $.map(this._disabledInputs,
4174 function(value) { return (value === target ? null : value); }); // delete entry
4175 },
4176
4177 /* Disable the date picker to a jQuery selection.
4178 * @param target element - the target input field or division or span
4179 */
4180 _disableDatepicker: function(target) {
4181 var nodeName, inline,
4182 $target = $(target),
4183 inst = $.data(target, "datepicker");
4184
4185 if (!$target.hasClass(this.markerClassName)) {
4186 return;
4187 }
4188
4189 nodeName = target.nodeName.toLowerCase();
4190 if (nodeName === "input") {
4191 target.disabled = true;
4192 inst.trigger.filter("button").
4193 each(function() { this.disabled = true; }).end().
4194 filter("img").css({opacity: "0.5", cursor: "default"});
4195 } else if (nodeName === "div" || nodeName === "span") {
4196 inline = $target.children("." + this._inlineClass);
4197 inline.children().addClass("ui-state-disabled");
4198 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
4199 prop("disabled", true);
4200 }
4201 this._disabledInputs = $.map(this._disabledInputs,
4202 function(value) { return (value === target ? null : value); }); // delete entry
4203 this._disabledInputs[this._disabledInputs.length] = target;
4204 },
4205
4206 /* Is the first field in a jQuery collection disabled as a datepicker?
4207 * @param target element - the target input field or division or span
4208 * @return boolean - true if disabled, false if enabled
4209 */
4210 _isDisabledDatepicker: function(target) {
4211 if (!target) {
4212 return false;
4213 }
4214 for (var i = 0; i < this._disabledInputs.length; i++) {
4215 if (this._disabledInputs[i] === target) {
4216 return true;
4217 }
4218 }
4219 return false;
4220 },
4221
4222 /* Retrieve the instance data for the target control.
4223 * @param target element - the target input field or division or span
4224 * @return object - the associated instance data
4225 * @throws error if a jQuery problem getting data
4226 */
4227 _getInst: function(target) {
4228 try {
4229 return $.data(target, "datepicker");
4230 }
4231 catch (err) {
4232 throw "Missing instance data for this datepicker";
4233 }
4234 },
4235
4236 /* Update or retrieve the settings for a date picker attached to an input field or division.
4237 * @param target element - the target input field or division or span
4238 * @param name object - the new settings to update or
4239 * string - the name of the setting to change or retrieve,
4240 * when retrieving also "all" for all instance settings or
4241 * "defaults" for all global defaults
4242 * @param value any - the new value for the setting
4243 * (omit if above is an object or to retrieve a value)
4244 */
4245 _optionDatepicker: function(target, name, value) {
4246 var settings, date, minDate, maxDate,
4247 inst = this._getInst(target);
4248
4249 if (arguments.length === 2 && typeof name === "string") {
4250 return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
4251 (inst ? (name === "all" ? $.extend({}, inst.settings) :
4252 this._get(inst, name)) : null));
4253 }
4254
4255 settings = name || {};
4256 if (typeof name === "string") {
4257 settings = {};
4258 settings[name] = value;
4259 }
4260
4261 if (inst) {
4262 if (this._curInst === inst) {
4263 this._hideDatepicker();
4264 }
4265
4266 date = this._getDateDatepicker(target, true);
4267 minDate = this._getMinMaxDate(inst, "min");
4268 maxDate = this._getMinMaxDate(inst, "max");
4269 datepicker_extendRemove(inst.settings, settings);
4270 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
4271 if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
4272 inst.settings.minDate = this._formatDate(inst, minDate);
4273 }
4274 if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
4275 inst.settings.maxDate = this._formatDate(inst, maxDate);
4276 }
4277 if ( "disabled" in settings ) {
4278 if ( settings.disabled ) {
4279 this._disableDatepicker(target);
4280 } else {
4281 this._enableDatepicker(target);
4282 }
4283 }
4284 this._attachments($(target), inst);
4285 this._autoSize(inst);
4286 this._setDate(inst, date);
4287 this._updateAlternate(inst);
4288 this._updateDatepicker(inst);
4289 }
4290 },
4291
4292 // change method deprecated
4293 _changeDatepicker: function(target, name, value) {
4294 this._optionDatepicker(target, name, value);
4295 },
4296
4297 /* Redraw the date picker attached to an input field or division.
4298 * @param target element - the target input field or division or span
4299 */
4300 _refreshDatepicker: function(target) {
4301 var inst = this._getInst(target);
4302 if (inst) {
4303 this._updateDatepicker(inst);
4304 }
4305 },
4306
4307 /* Set the dates for a jQuery selection.
4308 * @param target element - the target input field or division or span
4309 * @param date Date - the new date
4310 */
4311 _setDateDatepicker: function(target, date) {
4312 var inst = this._getInst(target);
4313 if (inst) {
4314 this._setDate(inst, date);
4315 this._updateDatepicker(inst);
4316 this._updateAlternate(inst);
4317 }
4318 },
4319
4320 /* Get the date(s) for the first entry in a jQuery selection.
4321 * @param target element - the target input field or division or span
4322 * @param noDefault boolean - true if no default date is to be used
4323 * @return Date - the current date
4324 */
4325 _getDateDatepicker: function(target, noDefault) {
4326 var inst = this._getInst(target);
4327 if (inst && !inst.inline) {
4328 this._setDateFromField(inst, noDefault);
4329 }
4330 return (inst ? this._getDate(inst) : null);
4331 },
4332
4333 /* Handle keystrokes. */
4334 _doKeyDown: function(event) {
4335 var onSelect, dateStr, sel,
4336 inst = $.datepicker._getInst(event.target),
4337 handled = true,
4338 isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
4339
4340 inst._keyEvent = true;
4341 if ($.datepicker._datepickerShowing) {
4342 switch (event.keyCode) {
4343 case 9: $.datepicker._hideDatepicker();
4344 handled = false;
4345 break; // hide on tab out
4346 case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
4347 $.datepicker._currentClass + ")", inst.dpDiv);
4348 if (sel[0]) {
4349 $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
4350 }
4351
4352 onSelect = $.datepicker._get(inst, "onSelect");
4353 if (onSelect) {
4354 dateStr = $.datepicker._formatDate(inst);
4355
4356 // trigger custom callback
4357 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
4358 } else {
4359 $.datepicker._hideDatepicker();
4360 }
4361
4362 return false; // don't submit the form
4363 case 27: $.datepicker._hideDatepicker();
4364 break; // hide on escape
4365 case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
4366 -$.datepicker._get(inst, "stepBigMonths") :
4367 -$.datepicker._get(inst, "stepMonths")), "M");
4368 break; // previous month/year on page up/+ ctrl
4369 case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
4370 +$.datepicker._get(inst, "stepBigMonths") :
4371 +$.datepicker._get(inst, "stepMonths")), "M");
4372 break; // next month/year on page down/+ ctrl
4373 case 35: if (event.ctrlKey || event.metaKey) {
4374 $.datepicker._clearDate(event.target);
4375 }
4376 handled = event.ctrlKey || event.metaKey;
4377 break; // clear on ctrl or command +end
4378 case 36: if (event.ctrlKey || event.metaKey) {
4379 $.datepicker._gotoToday(event.target);
4380 }
4381 handled = event.ctrlKey || event.metaKey;
4382 break; // current on ctrl or command +home
4383 case 37: if (event.ctrlKey || event.metaKey) {
4384 $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
4385 }
4386 handled = event.ctrlKey || event.metaKey;
4387 // -1 day on ctrl or command +left
4388 if (event.originalEvent.altKey) {
4389 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
4390 -$.datepicker._get(inst, "stepBigMonths") :
4391 -$.datepicker._get(inst, "stepMonths")), "M");
4392 }
4393 // next month/year on alt +left on Mac
4394 break;
4395 case 38: if (event.ctrlKey || event.metaKey) {
4396 $.datepicker._adjustDate(event.target, -7, "D");
4397 }
4398 handled = event.ctrlKey || event.metaKey;
4399 break; // -1 week on ctrl or command +up
4400 case 39: if (event.ctrlKey || event.metaKey) {
4401 $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
4402 }
4403 handled = event.ctrlKey || event.metaKey;
4404 // +1 day on ctrl or command +right
4405 if (event.originalEvent.altKey) {
4406 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
4407 +$.datepicker._get(inst, "stepBigMonths") :
4408 +$.datepicker._get(inst, "stepMonths")), "M");
4409 }
4410 // next month/year on alt +right
4411 break;
4412 case 40: if (event.ctrlKey || event.metaKey) {
4413 $.datepicker._adjustDate(event.target, +7, "D");
4414 }
4415 handled = event.ctrlKey || event.metaKey;
4416 break; // +1 week on ctrl or command +down
4417 default: handled = false;
4418 }
4419 } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
4420 $.datepicker._showDatepicker(this);
4421 } else {
4422 handled = false;
4423 }
4424
4425 if (handled) {
4426 event.preventDefault();
4427 event.stopPropagation();
4428 }
4429 },
4430
4431 /* Filter entered characters - based on date format. */
4432 _doKeyPress: function(event) {
4433 var chars, chr,
4434 inst = $.datepicker._getInst(event.target);
4435
4436 if ($.datepicker._get(inst, "constrainInput")) {
4437 chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
4438 chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
4439 return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
4440 }
4441 },
4442
4443 /* Synchronise manual entry and field/alternate field. */
4444 _doKeyUp: function(event) {
4445 var date,
4446 inst = $.datepicker._getInst(event.target);
4447
4448 if (inst.input.val() !== inst.lastVal) {
4449 try {
4450 date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
4451 (inst.input ? inst.input.val() : null),
4452 $.datepicker._getFormatConfig(inst));
4453
4454 if (date) { // only if valid
4455 $.datepicker._setDateFromField(inst);
4456 $.datepicker._updateAlternate(inst);
4457 $.datepicker._updateDatepicker(inst);
4458 }
4459 }
4460 catch (err) {
4461 }
4462 }
4463 return true;
4464 },
4465
4466 /* Pop-up the date picker for a given input field.
4467 * If false returned from beforeShow event handler do not show.
4468 * @param input element - the input field attached to the date picker or
4469 * event - if triggered by focus
4470 */
4471 _showDatepicker: function(input) {
4472 input = input.target || input;
4473 if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
4474 input = $("input", input.parentNode)[0];
4475 }
4476
4477 if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
4478 return;
4479 }
4480
4481 var inst, beforeShow, beforeShowSettings, isFixed,
4482 offset, showAnim, duration;
4483
4484 inst = $.datepicker._getInst(input);
4485 if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
4486 $.datepicker._curInst.dpDiv.stop(true, true);
4487 if ( inst && $.datepicker._datepickerShowing ) {
4488 $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
4489 }
4490 }
4491
4492 beforeShow = $.datepicker._get(inst, "beforeShow");
4493 beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
4494 if(beforeShowSettings === false){
4495 return;
4496 }
4497 datepicker_extendRemove(inst.settings, beforeShowSettings);
4498
4499 inst.lastVal = null;
4500 $.datepicker._lastInput = input;
4501 $.datepicker._setDateFromField(inst);
4502
4503 if ($.datepicker._inDialog) { // hide cursor
4504 input.value = "";
4505 }
4506 if (!$.datepicker._pos) { // position below input
4507 $.datepicker._pos = $.datepicker._findPos(input);
4508 $.datepicker._pos[1] += input.offsetHeight; // add the height
4509 }
4510
4511 isFixed = false;
4512 $(input).parents().each(function() {
4513 isFixed |= $(this).css("position") === "fixed";
4514 return !isFixed;
4515 });
4516
4517 offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
4518 $.datepicker._pos = null;
4519 //to avoid flashes on Firefox
4520 inst.dpDiv.empty();
4521 // determine sizing offscreen
4522 inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
4523 $.datepicker._updateDatepicker(inst);
4524 // fix width for dynamic number of date pickers
4525 // and adjust position before showing
4526 offset = $.datepicker._checkOffset(inst, offset, isFixed);
4527 inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
4528 "static" : (isFixed ? "fixed" : "absolute")), display: "none",
4529 left: offset.left + "px", top: offset.top + "px"});
4530
4531 if (!inst.inline) {
4532 showAnim = $.datepicker._get(inst, "showAnim");
4533 duration = $.datepicker._get(inst, "duration");
4534 inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
4535 $.datepicker._datepickerShowing = true;
4536
4537 if ( $.effects && $.effects.effect[ showAnim ] ) {
4538 inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
4539 } else {
4540 inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
4541 }
4542
4543 if ( $.datepicker._shouldFocusInput( inst ) ) {
4544 inst.input.focus();
4545 }
4546
4547 $.datepicker._curInst = inst;
4548 }
4549 },
4550
4551 /* Generate the date picker content. */
4552 _updateDatepicker: function(inst) {
4553 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
4554 datepicker_instActive = inst; // for delegate hover events
4555 inst.dpDiv.empty().append(this._generateHTML(inst));
4556 this._attachHandlers(inst);
4557
4558 var origyearshtml,
4559 numMonths = this._getNumberOfMonths(inst),
4560 cols = numMonths[1],
4561 width = 17,
4562 activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
4563
4564 if ( activeCell.length > 0 ) {
4565 datepicker_handleMouseover.apply( activeCell.get( 0 ) );
4566 }
4567
4568 inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
4569 if (cols > 1) {
4570 inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
4571 }
4572 inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
4573 "Class"]("ui-datepicker-multi");
4574 inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
4575 "Class"]("ui-datepicker-rtl");
4576
4577 if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
4578 inst.input.focus();
4579 }
4580
4581 // deffered render of the years select (to avoid flashes on Firefox)
4582 if( inst.yearshtml ){
4583 origyearshtml = inst.yearshtml;
4584 setTimeout(function(){
4585 //assure that inst.yearshtml didn't change.
4586 if( origyearshtml === inst.yearshtml && inst.yearshtml ){
4587 inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
4588 }
4589 origyearshtml = inst.yearshtml = null;
4590 }, 0);
4591 }
4592 },
4593
4594 // #6694 - don't focus the input if it's already focused
4595 // this breaks the change event in IE
4596 // Support: IE and jQuery <1.9
4597 _shouldFocusInput: function( inst ) {
4598 return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
4599 },
4600
4601 /* Check positioning to remain on screen. */
4602 _checkOffset: function(inst, offset, isFixed) {
4603 var dpWidth = inst.dpDiv.outerWidth(),
4604 dpHeight = inst.dpDiv.outerHeight(),
4605 inputWidth = inst.input ? inst.input.outerWidth() : 0,
4606 inputHeight = inst.input ? inst.input.outerHeight() : 0,
4607 viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
4608 viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
4609
4610 offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
4611 offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
4612 offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
4613
4614 // now check if datepicker is showing outside window viewport - move to a better place if so.
4615 offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
4616 Math.abs(offset.left + dpWidth - viewWidth) : 0);
4617 offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
4618 Math.abs(dpHeight + inputHeight) : 0);
4619
4620 return offset;
4621 },
4622
4623 /* Find an object's position on the screen. */
4624 _findPos: function(obj) {
4625 var position,
4626 inst = this._getInst(obj),
4627 isRTL = this._get(inst, "isRTL");
4628
4629 while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
4630 obj = obj[isRTL ? "previousSibling" : "nextSibling"];
4631 }
4632
4633 position = $(obj).offset();
4634 return [position.left, position.top];
4635 },
4636
4637 /* Hide the date picker from view.
4638 * @param input element - the input field attached to the date picker
4639 */
4640 _hideDatepicker: function(input) {
4641 var showAnim, duration, postProcess, onClose,
4642 inst = this._curInst;
4643
4644 if (!inst || (input && inst !== $.data(input, "datepicker"))) {
4645 return;
4646 }
4647
4648 if (this._datepickerShowing) {
4649 showAnim = this._get(inst, "showAnim");
4650 duration = this._get(inst, "duration");
4651 postProcess = function() {
4652 $.datepicker._tidyDialog(inst);
4653 };
4654
4655 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
4656 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
4657 inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
4658 } else {
4659 inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
4660 (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
4661 }
4662
4663 if (!showAnim) {
4664 postProcess();
4665 }
4666 this._datepickerShowing = false;
4667
4668 onClose = this._get(inst, "onClose");
4669 if (onClose) {
4670 onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
4671 }
4672
4673 this._lastInput = null;
4674 if (this._inDialog) {
4675 this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
4676 if ($.blockUI) {
4677 $.unblockUI();
4678 $("body").append(this.dpDiv);
4679 }
4680 }
4681 this._inDialog = false;
4682 }
4683 },
4684
4685 /* Tidy up after a dialog display. */
4686 _tidyDialog: function(inst) {
4687 inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");
4688 },
4689
4690 /* Close date picker if clicked elsewhere. */
4691 _checkExternalClick: function(event) {
4692 if (!$.datepicker._curInst) {
4693 return;
4694 }
4695
4696 var $target = $(event.target),
4697 inst = $.datepicker._getInst($target[0]);
4698
4699 if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
4700 $target.parents("#" + $.datepicker._mainDivId).length === 0 &&
4701 !$target.hasClass($.datepicker.markerClassName) &&
4702 !$target.closest("." + $.datepicker._triggerClass).length &&
4703 $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
4704 ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
4705 $.datepicker._hideDatepicker();
4706 }
4707 },
4708
4709 /* Adjust one of the date sub-fields. */
4710 _adjustDate: function(id, offset, period) {
4711 var target = $(id),
4712 inst = this._getInst(target[0]);
4713
4714 if (this._isDisabledDatepicker(target[0])) {
4715 return;
4716 }
4717 this._adjustInstDate(inst, offset +
4718 (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
4719 period);
4720 this._updateDatepicker(inst);
4721 },
4722
4723 /* Action for current link. */
4724 _gotoToday: function(id) {
4725 var date,
4726 target = $(id),
4727 inst = this._getInst(target[0]);
4728
4729 if (this._get(inst, "gotoCurrent") && inst.currentDay) {
4730 inst.selectedDay = inst.currentDay;
4731 inst.drawMonth = inst.selectedMonth = inst.currentMonth;
4732 inst.drawYear = inst.selectedYear = inst.currentYear;
4733 } else {
4734 date = new Date();
4735 inst.selectedDay = date.getDate();
4736 inst.drawMonth = inst.selectedMonth = date.getMonth();
4737 inst.drawYear = inst.selectedYear = date.getFullYear();
4738 }
4739 this._notifyChange(inst);
4740 this._adjustDate(target);
4741 },
4742
4743 /* Action for selecting a new month/year. */
4744 _selectMonthYear: function(id, select, period) {
4745 var target = $(id),
4746 inst = this._getInst(target[0]);
4747
4748 inst["selected" + (period === "M" ? "Month" : "Year")] =
4749 inst["draw" + (period === "M" ? "Month" : "Year")] =
4750 parseInt(select.options[select.selectedIndex].value,10);
4751
4752 this._notifyChange(inst);
4753 this._adjustDate(target);
4754 },
4755
4756 /* Action for selecting a day. */
4757 _selectDay: function(id, month, year, td) {
4758 var inst,
4759 target = $(id);
4760
4761 if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
4762 return;
4763 }
4764
4765 inst = this._getInst(target[0]);
4766 inst.selectedDay = inst.currentDay = $("a", td).html();
4767 inst.selectedMonth = inst.currentMonth = month;
4768 inst.selectedYear = inst.currentYear = year;
4769 this._selectDate(id, this._formatDate(inst,
4770 inst.currentDay, inst.currentMonth, inst.currentYear));
4771 },
4772
4773 /* Erase the input field and hide the date picker. */
4774 _clearDate: function(id) {
4775 var target = $(id);
4776 this._selectDate(target, "");
4777 },
4778
4779 /* Update the input field with the selected date. */
4780 _selectDate: function(id, dateStr) {
4781 var onSelect,
4782 target = $(id),
4783 inst = this._getInst(target[0]);
4784
4785 dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
4786 if (inst.input) {
4787 inst.input.val(dateStr);
4788 }
4789 this._updateAlternate(inst);
4790
4791 onSelect = this._get(inst, "onSelect");
4792 if (onSelect) {
4793 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
4794 } else if (inst.input) {
4795 inst.input.trigger("change"); // fire the change event
4796 }
4797
4798 if (inst.inline){
4799 this._updateDatepicker(inst);
4800 } else {
4801 this._hideDatepicker();
4802 this._lastInput = inst.input[0];
4803 if (typeof(inst.input[0]) !== "object") {
4804 inst.input.focus(); // restore focus
4805 }
4806 this._lastInput = null;
4807 }
4808 },
4809
4810 /* Update any alternate field to synchronise with the main field. */
4811 _updateAlternate: function(inst) {
4812 var altFormat, date, dateStr,
4813 altField = this._get(inst, "altField");
4814
4815 if (altField) { // update alternate field too
4816 altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
4817 date = this._getDate(inst);
4818 dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
4819 $(altField).each(function() { $(this).val(dateStr); });
4820 }
4821 },
4822
4823 /* Set as beforeShowDay function to prevent selection of weekends.
4824 * @param date Date - the date to customise
4825 * @return [boolean, string] - is this date selectable?, what is its CSS class?
4826 */
4827 noWeekends: function(date) {
4828 var day = date.getDay();
4829 return [(day > 0 && day < 6), ""];
4830 },
4831
4832 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
4833 * @param date Date - the date to get the week for
4834 * @return number - the number of the week within the year that contains this date
4835 */
4836 iso8601Week: function(date) {
4837 var time,
4838 checkDate = new Date(date.getTime());
4839
4840 // Find Thursday of this week starting on Monday
4841 checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
4842
4843 time = checkDate.getTime();
4844 checkDate.setMonth(0); // Compare with Jan 1
4845 checkDate.setDate(1);
4846 return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
4847 },
4848
4849 /* Parse a string value into a date object.
4850 * See formatDate below for the possible formats.
4851 *
4852 * @param format string - the expected format of the date
4853 * @param value string - the date in the above format
4854 * @param settings Object - attributes include:
4855 * shortYearCutoff number - the cutoff year for determining the century (optional)
4856 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
4857 * dayNames string[7] - names of the days from Sunday (optional)
4858 * monthNamesShort string[12] - abbreviated names of the months (optional)
4859 * monthNames string[12] - names of the months (optional)
4860 * @return Date - the extracted date value or null if value is blank
4861 */
4862 parseDate: function (format, value, settings) {
4863 if (format == null || value == null) {
4864 throw "Invalid arguments";
4865 }
4866
4867 value = (typeof value === "object" ? value.toString() : value + "");
4868 if (value === "") {
4869 return null;
4870 }
4871
4872 var iFormat, dim, extra,
4873 iValue = 0,
4874 shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
4875 shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
4876 new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
4877 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
4878 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
4879 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
4880 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
4881 year = -1,
4882 month = -1,
4883 day = -1,
4884 doy = -1,
4885 literal = false,
4886 date,
4887 // Check whether a format character is doubled
4888 lookAhead = function(match) {
4889 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
4890 if (matches) {
4891 iFormat++;
4892 }
4893 return matches;
4894 },
4895 // Extract a number from the string value
4896 getNumber = function(match) {
4897 var isDoubled = lookAhead(match),
4898 size = (match === "@" ? 14 : (match === "!" ? 20 :
4899 (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
4900 minSize = (match === "y" ? size : 1),
4901 digits = new RegExp("^\\d{" + minSize + "," + size + "}"),
4902 num = value.substring(iValue).match(digits);
4903 if (!num) {
4904 throw "Missing number at position " + iValue;
4905 }
4906 iValue += num[0].length;
4907 return parseInt(num[0], 10);
4908 },
4909 // Extract a name from the string value and convert to an index
4910 getName = function(match, shortNames, longNames) {
4911 var index = -1,
4912 names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
4913 return [ [k, v] ];
4914 }).sort(function (a, b) {
4915 return -(a[1].length - b[1].length);
4916 });
4917
4918 $.each(names, function (i, pair) {
4919 var name = pair[1];
4920 if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
4921 index = pair[0];
4922 iValue += name.length;
4923 return false;
4924 }
4925 });
4926 if (index !== -1) {
4927 return index + 1;
4928 } else {
4929 throw "Unknown name at position " + iValue;
4930 }
4931 },
4932 // Confirm that a literal character matches the string value
4933 checkLiteral = function() {
4934 if (value.charAt(iValue) !== format.charAt(iFormat)) {
4935 throw "Unexpected literal at position " + iValue;
4936 }
4937 iValue++;
4938 };
4939
4940 for (iFormat = 0; iFormat < format.length; iFormat++) {
4941 if (literal) {
4942 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
4943 literal = false;
4944 } else {
4945 checkLiteral();
4946 }
4947 } else {
4948 switch (format.charAt(iFormat)) {
4949 case "d":
4950 day = getNumber("d");
4951 break;
4952 case "D":
4953 getName("D", dayNamesShort, dayNames);
4954 break;
4955 case "o":
4956 doy = getNumber("o");
4957 break;
4958 case "m":
4959 month = getNumber("m");
4960 break;
4961 case "M":
4962 month = getName("M", monthNamesShort, monthNames);
4963 break;
4964 case "y":
4965 year = getNumber("y");
4966 break;
4967 case "@":
4968 date = new Date(getNumber("@"));
4969 year = date.getFullYear();
4970 month = date.getMonth() + 1;
4971 day = date.getDate();
4972 break;
4973 case "!":
4974 date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
4975 year = date.getFullYear();
4976 month = date.getMonth() + 1;
4977 day = date.getDate();
4978 break;
4979 case "'":
4980 if (lookAhead("'")){
4981 checkLiteral();
4982 } else {
4983 literal = true;
4984 }
4985 break;
4986 default:
4987 checkLiteral();
4988 }
4989 }
4990 }
4991
4992 if (iValue < value.length){
4993 extra = value.substr(iValue);
4994 if (!/^\s+/.test(extra)) {
4995 throw "Extra/unparsed characters found in date: " + extra;
4996 }
4997 }
4998
4999 if (year === -1) {
5000 year = new Date().getFullYear();
5001 } else if (year < 100) {
5002 year += new Date().getFullYear() - new Date().getFullYear() % 100 +
5003 (year <= shortYearCutoff ? 0 : -100);
5004 }
5005
5006 if (doy > -1) {
5007 month = 1;
5008 day = doy;
5009 do {
5010 dim = this._getDaysInMonth(year, month - 1);
5011 if (day <= dim) {
5012 break;
5013 }
5014 month++;
5015 day -= dim;
5016 } while (true);
5017 }
5018
5019 date = this._daylightSavingAdjust(new Date(year, month - 1, day));
5020 if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
5021 throw "Invalid date"; // E.g. 31/02/00
5022 }
5023 return date;
5024 },
5025
5026 /* Standard date formats. */
5027 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
5028 COOKIE: "D, dd M yy",
5029 ISO_8601: "yy-mm-dd",
5030 RFC_822: "D, d M y",
5031 RFC_850: "DD, dd-M-y",
5032 RFC_1036: "D, d M y",
5033 RFC_1123: "D, d M yy",
5034 RFC_2822: "D, d M yy",
5035 RSS: "D, d M y", // RFC 822
5036 TICKS: "!",
5037 TIMESTAMP: "@",
5038 W3C: "yy-mm-dd", // ISO 8601
5039
5040 _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
5041 Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
5042
5043 /* Format a date object into a string value.
5044 * The format can be combinations of the following:
5045 * d - day of month (no leading zero)
5046 * dd - day of month (two digit)
5047 * o - day of year (no leading zeros)
5048 * oo - day of year (three digit)
5049 * D - day name short
5050 * DD - day name long
5051 * m - month of year (no leading zero)
5052 * mm - month of year (two digit)
5053 * M - month name short
5054 * MM - month name long
5055 * y - year (two digit)
5056 * yy - year (four digit)
5057 * @ - Unix timestamp (ms since 01/01/1970)
5058 * ! - Windows ticks (100ns since 01/01/0001)
5059 * "..." - literal text
5060 * '' - single quote
5061 *
5062 * @param format string - the desired format of the date
5063 * @param date Date - the date value to format
5064 * @param settings Object - attributes include:
5065 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
5066 * dayNames string[7] - names of the days from Sunday (optional)
5067 * monthNamesShort string[12] - abbreviated names of the months (optional)
5068 * monthNames string[12] - names of the months (optional)
5069 * @return string - the date in the above format
5070 */
5071 formatDate: function (format, date, settings) {
5072 if (!date) {
5073 return "";
5074 }
5075
5076 var iFormat,
5077 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
5078 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
5079 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
5080 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
5081 // Check whether a format character is doubled
5082 lookAhead = function(match) {
5083 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
5084 if (matches) {
5085 iFormat++;
5086 }
5087 return matches;
5088 },
5089 // Format a number, with leading zero if necessary
5090 formatNumber = function(match, value, len) {
5091 var num = "" + value;
5092 if (lookAhead(match)) {
5093 while (num.length < len) {
5094 num = "0" + num;
5095 }
5096 }
5097 return num;
5098 },
5099 // Format a name, short or long as requested
5100 formatName = function(match, value, shortNames, longNames) {
5101 return (lookAhead(match) ? longNames[value] : shortNames[value]);
5102 },
5103 output = "",
5104 literal = false;
5105
5106 if (date) {
5107 for (iFormat = 0; iFormat < format.length; iFormat++) {
5108 if (literal) {
5109 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
5110 literal = false;
5111 } else {
5112 output += format.charAt(iFormat);
5113 }
5114 } else {
5115 switch (format.charAt(iFormat)) {
5116 case "d":
5117 output += formatNumber("d", date.getDate(), 2);
5118 break;
5119 case "D":
5120 output += formatName("D", date.getDay(), dayNamesShort, dayNames);
5121 break;
5122 case "o":
5123 output += formatNumber("o",
5124 Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
5125 break;
5126 case "m":
5127 output += formatNumber("m", date.getMonth() + 1, 2);
5128 break;
5129 case "M":
5130 output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
5131 break;
5132 case "y":
5133 output += (lookAhead("y") ? date.getFullYear() :
5134 (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
5135 break;
5136 case "@":
5137 output += date.getTime();
5138 break;
5139 case "!":
5140 output += date.getTime() * 10000 + this._ticksTo1970;
5141 break;
5142 case "'":
5143 if (lookAhead("'")) {
5144 output += "'";
5145 } else {
5146 literal = true;
5147 }
5148 break;
5149 default:
5150 output += format.charAt(iFormat);
5151 }
5152 }
5153 }
5154 }
5155 return output;
5156 },
5157
5158 /* Extract all possible characters from the date format. */
5159 _possibleChars: function (format) {
5160 var iFormat,
5161 chars = "",
5162 literal = false,
5163 // Check whether a format character is doubled
5164 lookAhead = function(match) {
5165 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
5166 if (matches) {
5167 iFormat++;
5168 }
5169 return matches;
5170 };
5171
5172 for (iFormat = 0; iFormat < format.length; iFormat++) {
5173 if (literal) {
5174 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
5175 literal = false;
5176 } else {
5177 chars += format.charAt(iFormat);
5178 }
5179 } else {
5180 switch (format.charAt(iFormat)) {
5181 case "d": case "m": case "y": case "@":
5182 chars += "0123456789";
5183 break;
5184 case "D": case "M":
5185 return null; // Accept anything
5186 case "'":
5187 if (lookAhead("'")) {
5188 chars += "'";
5189 } else {
5190 literal = true;
5191 }
5192 break;
5193 default:
5194 chars += format.charAt(iFormat);
5195 }
5196 }
5197 }
5198 return chars;
5199 },
5200
5201 /* Get a setting value, defaulting if necessary. */
5202 _get: function(inst, name) {
5203 return inst.settings[name] !== undefined ?
5204 inst.settings[name] : this._defaults[name];
5205 },
5206
5207 /* Parse existing date and initialise date picker. */
5208 _setDateFromField: function(inst, noDefault) {
5209 if (inst.input.val() === inst.lastVal) {
5210 return;
5211 }
5212
5213 var dateFormat = this._get(inst, "dateFormat"),
5214 dates = inst.lastVal = inst.input ? inst.input.val() : null,
5215 defaultDate = this._getDefaultDate(inst),
5216 date = defaultDate,
5217 settings = this._getFormatConfig(inst);
5218
5219 try {
5220 date = this.parseDate(dateFormat, dates, settings) || defaultDate;
5221 } catch (event) {
5222 dates = (noDefault ? "" : dates);
5223 }
5224 inst.selectedDay = date.getDate();
5225 inst.drawMonth = inst.selectedMonth = date.getMonth();
5226 inst.drawYear = inst.selectedYear = date.getFullYear();
5227 inst.currentDay = (dates ? date.getDate() : 0);
5228 inst.currentMonth = (dates ? date.getMonth() : 0);
5229 inst.currentYear = (dates ? date.getFullYear() : 0);
5230 this._adjustInstDate(inst);
5231 },
5232
5233 /* Retrieve the default date shown on opening. */
5234 _getDefaultDate: function(inst) {
5235 return this._restrictMinMax(inst,
5236 this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
5237 },
5238
5239 /* A date may be specified as an exact value or a relative one. */
5240 _determineDate: function(inst, date, defaultDate) {
5241 var offsetNumeric = function(offset) {
5242 var date = new Date();
5243 date.setDate(date.getDate() + offset);
5244 return date;
5245 },
5246 offsetString = function(offset) {
5247 try {
5248 return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
5249 offset, $.datepicker._getFormatConfig(inst));
5250 }
5251 catch (e) {
5252 // Ignore
5253 }
5254
5255 var date = (offset.toLowerCase().match(/^c/) ?
5256 $.datepicker._getDate(inst) : null) || new Date(),
5257 year = date.getFullYear(),
5258 month = date.getMonth(),
5259 day = date.getDate(),
5260 pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
5261 matches = pattern.exec(offset);
5262
5263 while (matches) {
5264 switch (matches[2] || "d") {
5265 case "d" : case "D" :
5266 day += parseInt(matches[1],10); break;
5267 case "w" : case "W" :
5268 day += parseInt(matches[1],10) * 7; break;
5269 case "m" : case "M" :
5270 month += parseInt(matches[1],10);
5271 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
5272 break;
5273 case "y": case "Y" :
5274 year += parseInt(matches[1],10);
5275 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
5276 break;
5277 }
5278 matches = pattern.exec(offset);
5279 }
5280 return new Date(year, month, day);
5281 },
5282 newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
5283 (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
5284
5285 newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
5286 if (newDate) {
5287 newDate.setHours(0);
5288 newDate.setMinutes(0);
5289 newDate.setSeconds(0);
5290 newDate.setMilliseconds(0);
5291 }
5292 return this._daylightSavingAdjust(newDate);
5293 },
5294
5295 /* Handle switch to/from daylight saving.
5296 * Hours may be non-zero on daylight saving cut-over:
5297 * > 12 when midnight changeover, but then cannot generate
5298 * midnight datetime, so jump to 1AM, otherwise reset.
5299 * @param date (Date) the date to check
5300 * @return (Date) the corrected date
5301 */
5302 _daylightSavingAdjust: function(date) {
5303 if (!date) {
5304 return null;
5305 }
5306 date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
5307 return date;
5308 },
5309
5310 /* Set the date(s) directly. */
5311 _setDate: function(inst, date, noChange) {
5312 var clear = !date,
5313 origMonth = inst.selectedMonth,
5314 origYear = inst.selectedYear,
5315 newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
5316
5317 inst.selectedDay = inst.currentDay = newDate.getDate();
5318 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
5319 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
5320 if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
5321 this._notifyChange(inst);
5322 }
5323 this._adjustInstDate(inst);
5324 if (inst.input) {
5325 inst.input.val(clear ? "" : this._formatDate(inst));
5326 }
5327 },
5328
5329 /* Retrieve the date(s) directly. */
5330 _getDate: function(inst) {
5331 var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
5332 this._daylightSavingAdjust(new Date(
5333 inst.currentYear, inst.currentMonth, inst.currentDay)));
5334 return startDate;
5335 },
5336
5337 /* Attach the onxxx handlers. These are declared statically so
5338 * they work with static code transformers like Caja.
5339 */
5340 _attachHandlers: function(inst) {
5341 var stepMonths = this._get(inst, "stepMonths"),
5342 id = "#" + inst.id.replace( /\\\\/g, "\\" );
5343 inst.dpDiv.find("[data-handler]").map(function () {
5344 var handler = {
5345 prev: function () {
5346 $.datepicker._adjustDate(id, -stepMonths, "M");
5347 },
5348 next: function () {
5349 $.datepicker._adjustDate(id, +stepMonths, "M");
5350 },
5351 hide: function () {
5352 $.datepicker._hideDatepicker();
5353 },
5354 today: function () {
5355 $.datepicker._gotoToday(id);
5356 },
5357 selectDay: function () {
5358 $.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
5359 return false;
5360 },
5361 selectMonth: function () {
5362 $.datepicker._selectMonthYear(id, this, "M");
5363 return false;
5364 },
5365 selectYear: function () {
5366 $.datepicker._selectMonthYear(id, this, "Y");
5367 return false;
5368 }
5369 };
5370 $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
5371 });
5372 },
5373
5374 /* Generate the HTML for the current state of the date picker. */
5375 _generateHTML: function(inst) {
5376 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
5377 controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
5378 monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
5379 selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
5380 cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
5381 printDate, dRow, tbody, daySettings, otherMonth, unselectable,
5382 tempDate = new Date(),
5383 today = this._daylightSavingAdjust(
5384 new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
5385 isRTL = this._get(inst, "isRTL"),
5386 showButtonPanel = this._get(inst, "showButtonPanel"),
5387 hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
5388 navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
5389 numMonths = this._getNumberOfMonths(inst),
5390 showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
5391 stepMonths = this._get(inst, "stepMonths"),
5392 isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
5393 currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
5394 new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
5395 minDate = this._getMinMaxDate(inst, "min"),
5396 maxDate = this._getMinMaxDate(inst, "max"),
5397 drawMonth = inst.drawMonth - showCurrentAtPos,
5398 drawYear = inst.drawYear;
5399
5400 if (drawMonth < 0) {
5401 drawMonth += 12;
5402 drawYear--;
5403 }
5404 if (maxDate) {
5405 maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
5406 maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
5407 maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
5408 while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
5409 drawMonth--;
5410 if (drawMonth < 0) {
5411 drawMonth = 11;
5412 drawYear--;
5413 }
5414 }
5415 }
5416 inst.drawMonth = drawMonth;
5417 inst.drawYear = drawYear;
5418
5419 prevText = this._get(inst, "prevText");
5420 prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
5421 this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
5422 this._getFormatConfig(inst)));
5423
5424 prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
5425 "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
5426 " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
5427 (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>"));
5428
5429 nextText = this._get(inst, "nextText");
5430 nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
5431 this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
5432 this._getFormatConfig(inst)));
5433
5434 next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
5435 "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
5436 " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
5437 (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>"));
5438
5439 currentText = this._get(inst, "currentText");
5440 gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
5441 currentText = (!navigationAsDateFormat ? currentText :
5442 this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
5443
5444 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'>" +
5445 this._get(inst, "closeText") + "</button>" : "");
5446
5447 buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
5448 (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'" +
5449 ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";
5450
5451 firstDay = parseInt(this._get(inst, "firstDay"),10);
5452 firstDay = (isNaN(firstDay) ? 0 : firstDay);
5453
5454 showWeek = this._get(inst, "showWeek");
5455 dayNames = this._get(inst, "dayNames");
5456 dayNamesMin = this._get(inst, "dayNamesMin");
5457 monthNames = this._get(inst, "monthNames");
5458 monthNamesShort = this._get(inst, "monthNamesShort");
5459 beforeShowDay = this._get(inst, "beforeShowDay");
5460 showOtherMonths = this._get(inst, "showOtherMonths");
5461 selectOtherMonths = this._get(inst, "selectOtherMonths");
5462 defaultDate = this._getDefaultDate(inst);
5463 html = "";
5464 dow;
5465 for (row = 0; row < numMonths[0]; row++) {
5466 group = "";
5467 this.maxRows = 4;
5468 for (col = 0; col < numMonths[1]; col++) {
5469 selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
5470 cornerClass = " ui-corner-all";
5471 calender = "";
5472 if (isMultiMonth) {
5473 calender += "<div class='ui-datepicker-group";
5474 if (numMonths[1] > 1) {
5475 switch (col) {
5476 case 0: calender += " ui-datepicker-group-first";
5477 cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
5478 case numMonths[1]-1: calender += " ui-datepicker-group-last";
5479 cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
5480 default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
5481 }
5482 }
5483 calender += "'>";
5484 }
5485 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
5486 (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
5487 (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
5488 this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
5489 row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
5490 "</div><table class='ui-datepicker-calendar'><thead>" +
5491 "<tr>";
5492 thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
5493 for (dow = 0; dow < 7; dow++) { // days of the week
5494 day = (dow + firstDay) % 7;
5495 thead += "<th scope='col'" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
5496 "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
5497 }
5498 calender += thead + "</tr></thead><tbody>";
5499 daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
5500 if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
5501 inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
5502 }
5503 leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
5504 curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
5505 numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
5506 this.maxRows = numRows;
5507 printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
5508 for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
5509 calender += "<tr>";
5510 tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
5511 this._get(inst, "calculateWeek")(printDate) + "</td>");
5512 for (dow = 0; dow < 7; dow++) { // create date picker days
5513 daySettings = (beforeShowDay ?
5514 beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
5515 otherMonth = (printDate.getMonth() !== drawMonth);
5516 unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
5517 (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
5518 tbody += "<td class='" +
5519 ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
5520 (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
5521 ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
5522 (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
5523 // or defaultDate is current printedDate and defaultDate is selectedDate
5524 " " + this._dayOverClass : "") + // highlight selected day
5525 (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days
5526 (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
5527 (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
5528 (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
5529 ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "&#39;") + "'" : "") + // cell title
5530 (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
5531 (otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
5532 (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
5533 (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
5534 (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
5535 (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
5536 "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
5537 printDate.setDate(printDate.getDate() + 1);
5538 printDate = this._daylightSavingAdjust(printDate);
5539 }
5540 calender += tbody + "</tr>";
5541 }
5542 drawMonth++;
5543 if (drawMonth > 11) {
5544 drawMonth = 0;
5545 drawYear++;
5546 }
5547 calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
5548 ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
5549 group += calender;
5550 }
5551 html += group;
5552 }
5553 html += buttonPanel;
5554 inst._keyEvent = false;
5555 return html;
5556 },
5557
5558 /* Generate the month and year header. */
5559 _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
5560 secondary, monthNames, monthNamesShort) {
5561
5562 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
5563 changeMonth = this._get(inst, "changeMonth"),
5564 changeYear = this._get(inst, "changeYear"),
5565 showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
5566 html = "<div class='ui-datepicker-title'>",
5567 monthHtml = "";
5568
5569 // month selection
5570 if (secondary || !changeMonth) {
5571 monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
5572 } else {
5573 inMinYear = (minDate && minDate.getFullYear() === drawYear);
5574 inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
5575 monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
5576 for ( month = 0; month < 12; month++) {
5577 if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
5578 monthHtml += "<option value='" + month + "'" +
5579 (month === drawMonth ? " selected='selected'" : "") +
5580 ">" + monthNamesShort[month] + "</option>";
5581 }
5582 }
5583 monthHtml += "</select>";
5584 }
5585
5586 if (!showMonthAfterYear) {
5587 html += monthHtml + (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "");
5588 }
5589
5590 // year selection
5591 if ( !inst.yearshtml ) {
5592 inst.yearshtml = "";
5593 if (secondary || !changeYear) {
5594 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
5595 } else {
5596 // determine range of years to display
5597 years = this._get(inst, "yearRange").split(":");
5598 thisYear = new Date().getFullYear();
5599 determineYear = function(value) {
5600 var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
5601 (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
5602 parseInt(value, 10)));
5603 return (isNaN(year) ? thisYear : year);
5604 };
5605 year = determineYear(years[0]);
5606 endYear = Math.max(year, determineYear(years[1] || ""));
5607 year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
5608 endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
5609 inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
5610 for (; year <= endYear; year++) {
5611 inst.yearshtml += "<option value='" + year + "'" +
5612 (year === drawYear ? " selected='selected'" : "") +
5613 ">" + year + "</option>";
5614 }
5615 inst.yearshtml += "</select>";
5616
5617 html += inst.yearshtml;
5618 inst.yearshtml = null;
5619 }
5620 }
5621
5622 html += this._get(inst, "yearSuffix");
5623 if (showMonthAfterYear) {
5624 html += (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "") + monthHtml;
5625 }
5626 html += "</div>"; // Close datepicker_header
5627 return html;
5628 },
5629
5630 /* Adjust one of the date sub-fields. */
5631 _adjustInstDate: function(inst, offset, period) {
5632 var year = inst.drawYear + (period === "Y" ? offset : 0),
5633 month = inst.drawMonth + (period === "M" ? offset : 0),
5634 day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
5635 date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));
5636
5637 inst.selectedDay = date.getDate();
5638 inst.drawMonth = inst.selectedMonth = date.getMonth();
5639 inst.drawYear = inst.selectedYear = date.getFullYear();
5640 if (period === "M" || period === "Y") {
5641 this._notifyChange(inst);
5642 }
5643 },
5644
5645 /* Ensure a date is within any min/max bounds. */
5646 _restrictMinMax: function(inst, date) {
5647 var minDate = this._getMinMaxDate(inst, "min"),
5648 maxDate = this._getMinMaxDate(inst, "max"),
5649 newDate = (minDate && date < minDate ? minDate : date);
5650 return (maxDate && newDate > maxDate ? maxDate : newDate);
5651 },
5652
5653 /* Notify change of month/year. */
5654 _notifyChange: function(inst) {
5655 var onChange = this._get(inst, "onChangeMonthYear");
5656 if (onChange) {
5657 onChange.apply((inst.input ? inst.input[0] : null),
5658 [inst.selectedYear, inst.selectedMonth + 1, inst]);
5659 }
5660 },
5661
5662 /* Determine the number of months to show. */
5663 _getNumberOfMonths: function(inst) {
5664 var numMonths = this._get(inst, "numberOfMonths");
5665 return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
5666 },
5667
5668 /* Determine the current maximum date - ensure no time components are set. */
5669 _getMinMaxDate: function(inst, minMax) {
5670 return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
5671 },
5672
5673 /* Find the number of days in a given month. */
5674 _getDaysInMonth: function(year, month) {
5675 return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
5676 },
5677
5678 /* Find the day of the week of the first of a month. */
5679 _getFirstDayOfMonth: function(year, month) {
5680 return new Date(year, month, 1).getDay();
5681 },
5682
5683 /* Determines if we should allow a "next/prev" month display change. */
5684 _canAdjustMonth: function(inst, offset, curYear, curMonth) {
5685 var numMonths = this._getNumberOfMonths(inst),
5686 date = this._daylightSavingAdjust(new Date(curYear,
5687 curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
5688
5689 if (offset < 0) {
5690 date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
5691 }
5692 return this._isInRange(inst, date);
5693 },
5694
5695 /* Is the given date in the accepted range? */
5696 _isInRange: function(inst, date) {
5697 var yearSplit, currentYear,
5698 minDate = this._getMinMaxDate(inst, "min"),
5699 maxDate = this._getMinMaxDate(inst, "max"),
5700 minYear = null,
5701 maxYear = null,
5702 years = this._get(inst, "yearRange");
5703 if (years){
5704 yearSplit = years.split(":");
5705 currentYear = new Date().getFullYear();
5706 minYear = parseInt(yearSplit[0], 10);
5707 maxYear = parseInt(yearSplit[1], 10);
5708 if ( yearSplit[0].match(/[+\-].*/) ) {
5709 minYear += currentYear;
5710 }
5711 if ( yearSplit[1].match(/[+\-].*/) ) {
5712 maxYear += currentYear;
5713 }
5714 }
5715
5716 return ((!minDate || date.getTime() >= minDate.getTime()) &&
5717 (!maxDate || date.getTime() <= maxDate.getTime()) &&
5718 (!minYear || date.getFullYear() >= minYear) &&
5719 (!maxYear || date.getFullYear() <= maxYear));
5720 },
5721
5722 /* Provide the configuration settings for formatting/parsing. */
5723 _getFormatConfig: function(inst) {
5724 var shortYearCutoff = this._get(inst, "shortYearCutoff");
5725 shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
5726 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
5727 return {shortYearCutoff: shortYearCutoff,
5728 dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
5729 monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
5730 },
5731
5732 /* Format the given date for display. */
5733 _formatDate: function(inst, day, month, year) {
5734 if (!day) {
5735 inst.currentDay = inst.selectedDay;
5736 inst.currentMonth = inst.selectedMonth;
5737 inst.currentYear = inst.selectedYear;
5738 }
5739 var date = (day ? (typeof day === "object" ? day :
5740 this._daylightSavingAdjust(new Date(year, month, day))) :
5741 this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
5742 return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
5743 }
5744 });
5745
5746 /*
5747 * Bind hover events for datepicker elements.
5748 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
5749 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
5750 */
5751 function datepicker_bindHover(dpDiv) {
5752 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
5753 return dpDiv.delegate(selector, "mouseout", function() {
5754 $(this).removeClass("ui-state-hover");
5755 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
5756 $(this).removeClass("ui-datepicker-prev-hover");
5757 }
5758 if (this.className.indexOf("ui-datepicker-next") !== -1) {
5759 $(this).removeClass("ui-datepicker-next-hover");
5760 }
5761 })
5762 .delegate( selector, "mouseover", datepicker_handleMouseover );
5763 }
5764
5765 function datepicker_handleMouseover() {
5766 if (!$.datepicker._isDisabledDatepicker( datepicker_instActive.inline? datepicker_instActive.dpDiv.parent()[0] : datepicker_instActive.input[0])) {
5767 $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
5768 $(this).addClass("ui-state-hover");
5769 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
5770 $(this).addClass("ui-datepicker-prev-hover");
5771 }
5772 if (this.className.indexOf("ui-datepicker-next") !== -1) {
5773 $(this).addClass("ui-datepicker-next-hover");
5774 }
5775 }
5776 }
5777
5778 /* jQuery extend now ignores nulls! */
5779 function datepicker_extendRemove(target, props) {
5780 $.extend(target, props);
5781 for (var name in props) {
5782 if (props[name] == null) {
5783 target[name] = props[name];
5784 }
5785 }
5786 return target;
5787 }
5788
5789 /* Invoke the datepicker functionality.
5790 @param options string - a command, optionally followed by additional parameters or
5791 Object - settings for attaching new datepicker functionality
5792 @return jQuery object */
5793 $.fn.datepicker = function(options){
5794
5795 /* Verify an empty collection wasn't passed - Fixes #6976 */
5796 if ( !this.length ) {
5797 return this;
5798 }
5799
5800 /* Initialise the date picker. */
5801 if (!$.datepicker.initialized) {
5802 $(document).mousedown($.datepicker._checkExternalClick);
5803 $.datepicker.initialized = true;
5804 }
5805
5806 /* Append datepicker main container to body if not exist. */
5807 if ($("#"+$.datepicker._mainDivId).length === 0) {
5808 $("body").append($.datepicker.dpDiv);
5809 }
5810
5811 var otherArgs = Array.prototype.slice.call(arguments, 1);
5812 if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
5813 return $.datepicker["_" + options + "Datepicker"].
5814 apply($.datepicker, [this[0]].concat(otherArgs));
5815 }
5816 if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
5817 return $.datepicker["_" + options + "Datepicker"].
5818 apply($.datepicker, [this[0]].concat(otherArgs));
5819 }
5820 return this.each(function() {
5821 typeof options === "string" ?
5822 $.datepicker["_" + options + "Datepicker"].
5823 apply($.datepicker, [this].concat(otherArgs)) :
5824 $.datepicker._attachDatepicker(this, options);
5825 });
5826 };
5827
5828 $.datepicker = new Datepicker(); // singleton instance
5829 $.datepicker.initialized = false;
5830 $.datepicker.uuid = new Date().getTime();
5831 $.datepicker.version = "1.11.3";
5832
5833 var datepicker = $.datepicker;
5834
5835
5836 /*!
5837 * jQuery UI Draggable 1.11.3
5838 * http://jqueryui.com
5839 *
5840 * Copyright jQuery Foundation and other contributors
5841 * Released under the MIT license.
5842 * http://jquery.org/license
5843 *
5844 * http://api.jqueryui.com/draggable/
5845 */
5846
5847
5848 $.widget("ui.draggable", $.ui.mouse, {
5849 version: "1.11.3",
5850 widgetEventPrefix: "drag",
5851 options: {
5852 addClasses: true,
5853 appendTo: "parent",
5854 axis: false,
5855 connectToSortable: false,
5856 containment: false,
5857 cursor: "auto",
5858 cursorAt: false,
5859 grid: false,
5860 handle: false,
5861 helper: "original",
5862 iframeFix: false,
5863 opacity: false,
5864 refreshPositions: false,
5865 revert: false,
5866 revertDuration: 500,
5867 scope: "default",
5868 scroll: true,
5869 scrollSensitivity: 20,
5870 scrollSpeed: 20,
5871 snap: false,
5872 snapMode: "both",
5873 snapTolerance: 20,
5874 stack: false,
5875 zIndex: false,
5876
5877 // callbacks
5878 drag: null,
5879 start: null,
5880 stop: null
5881 },
5882 _create: function() {
5883
5884 if ( this.options.helper === "original" ) {
5885 this._setPositionRelative();
5886 }
5887 if (this.options.addClasses){
5888 this.element.addClass("ui-draggable");
5889 }
5890 if (this.options.disabled){
5891 this.element.addClass("ui-draggable-disabled");
5892 }
5893 this._setHandleClassName();
5894
5895 this._mouseInit();
5896 },
5897
5898 _setOption: function( key, value ) {
5899 this._super( key, value );
5900 if ( key === "handle" ) {
5901 this._removeHandleClassName();
5902 this._setHandleClassName();
5903 }
5904 },
5905
5906 _destroy: function() {
5907 if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
5908 this.destroyOnClear = true;
5909 return;
5910 }
5911 this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
5912 this._removeHandleClassName();
5913 this._mouseDestroy();
5914 },
5915
5916 _mouseCapture: function(event) {
5917 var o = this.options;
5918
5919 this._blurActiveElement( event );
5920
5921 // among others, prevent a drag on a resizable-handle
5922 if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) {
5923 return false;
5924 }
5925
5926 //Quit if we're not on a valid handle
5927 this.handle = this._getHandle(event);
5928 if (!this.handle) {
5929 return false;
5930 }
5931
5932 this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix );
5933
5934 return true;
5935
5936 },
5937
5938 _blockFrames: function( selector ) {
5939 this.iframeBlocks = this.document.find( selector ).map(function() {
5940 var iframe = $( this );
5941
5942 return $( "<div>" )
5943 .css( "position", "absolute" )
5944 .appendTo( iframe.parent() )
5945 .outerWidth( iframe.outerWidth() )
5946 .outerHeight( iframe.outerHeight() )
5947 .offset( iframe.offset() )[ 0 ];
5948 });
5949 },
5950
5951 _unblockFrames: function() {
5952 if ( this.iframeBlocks ) {
5953 this.iframeBlocks.remove();
5954 delete this.iframeBlocks;
5955 }
5956 },
5957
5958 _blurActiveElement: function( event ) {
5959 var document = this.document[ 0 ];
5960
5961 // Only need to blur if the event occurred on the draggable itself, see #10527
5962 if ( !this.handleElement.is( event.target ) ) {
5963 return;
5964 }
5965
5966 // support: IE9
5967 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
5968 try {
5969
5970 // Support: IE9, IE10
5971 // If the <body> is blurred, IE will switch windows, see #9520
5972 if ( document.activeElement && document.activeElement.nodeName.toLowerCase() !== "body" ) {
5973
5974 // Blur any element that currently has focus, see #4261
5975 $( document.activeElement ).blur();
5976 }
5977 } catch ( error ) {}
5978 },
5979
5980 _mouseStart: function(event) {
5981
5982 var o = this.options;
5983
5984 //Create and append the visible helper
5985 this.helper = this._createHelper(event);
5986
5987 this.helper.addClass("ui-draggable-dragging");
5988
5989 //Cache the helper size
5990 this._cacheHelperProportions();
5991
5992 //If ddmanager is used for droppables, set the global draggable
5993 if ($.ui.ddmanager) {
5994 $.ui.ddmanager.current = this;
5995 }
5996
5997 /*
5998 * - Position generation -
5999 * This block generates everything position related - it's the core of draggables.
6000 */
6001
6002 //Cache the margins of the original element
6003 this._cacheMargins();
6004
6005 //Store the helper's css position
6006 this.cssPosition = this.helper.css( "position" );
6007 this.scrollParent = this.helper.scrollParent( true );
6008 this.offsetParent = this.helper.offsetParent();
6009 this.hasFixedAncestor = this.helper.parents().filter(function() {
6010 return $( this ).css( "position" ) === "fixed";
6011 }).length > 0;
6012
6013 //The element's absolute position on the page minus margins
6014 this.positionAbs = this.element.offset();
6015 this._refreshOffsets( event );
6016
6017 //Generate the original position
6018 this.originalPosition = this.position = this._generatePosition( event, false );
6019 this.originalPageX = event.pageX;
6020 this.originalPageY = event.pageY;
6021
6022 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
6023 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
6024
6025 //Set a containment if given in the options
6026 this._setContainment();
6027
6028 //Trigger event + callbacks
6029 if (this._trigger("start", event) === false) {
6030 this._clear();
6031 return false;
6032 }
6033
6034 //Recache the helper size
6035 this._cacheHelperProportions();
6036
6037 //Prepare the droppable offsets
6038 if ($.ui.ddmanager && !o.dropBehaviour) {
6039 $.ui.ddmanager.prepareOffsets(this, event);
6040 }
6041
6042 // Reset helper's right/bottom css if they're set and set explicit width/height instead
6043 // as this prevents resizing of elements with right/bottom set (see #7772)
6044 this._normalizeRightBottom();
6045
6046 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
6047
6048 //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
6049 if ( $.ui.ddmanager ) {
6050 $.ui.ddmanager.dragStart(this, event);
6051 }
6052
6053 return true;
6054 },
6055
6056 _refreshOffsets: function( event ) {
6057 this.offset = {
6058 top: this.positionAbs.top - this.margins.top,
6059 left: this.positionAbs.left - this.margins.left,
6060 scroll: false,
6061 parent: this._getParentOffset(),
6062 relative: this._getRelativeOffset()
6063 };
6064
6065 this.offset.click = {
6066 left: event.pageX - this.offset.left,
6067 top: event.pageY - this.offset.top
6068 };
6069 },
6070
6071 _mouseDrag: function(event, noPropagation) {
6072 // reset any necessary cached properties (see #5009)
6073 if ( this.hasFixedAncestor ) {
6074 this.offset.parent = this._getParentOffset();
6075 }
6076
6077 //Compute the helpers position
6078 this.position = this._generatePosition( event, true );
6079 this.positionAbs = this._convertPositionTo("absolute");
6080
6081 //Call plugins and callbacks and use the resulting position if something is returned
6082 if (!noPropagation) {
6083 var ui = this._uiHash();
6084 if (this._trigger("drag", event, ui) === false) {
6085 this._mouseUp({});
6086 return false;
6087 }
6088 this.position = ui.position;
6089 }
6090
6091 this.helper[ 0 ].style.left = this.position.left + "px";
6092 this.helper[ 0 ].style.top = this.position.top + "px";
6093
6094 if ($.ui.ddmanager) {
6095 $.ui.ddmanager.drag(this, event);
6096 }
6097
6098 return false;
6099 },
6100
6101 _mouseStop: function(event) {
6102
6103 //If we are using droppables, inform the manager about the drop
6104 var that = this,
6105 dropped = false;
6106 if ($.ui.ddmanager && !this.options.dropBehaviour) {
6107 dropped = $.ui.ddmanager.drop(this, event);
6108 }
6109
6110 //if a drop comes from outside (a sortable)
6111 if (this.dropped) {
6112 dropped = this.dropped;
6113 this.dropped = false;
6114 }
6115
6116 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))) {
6117 $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
6118 if (that._trigger("stop", event) !== false) {
6119 that._clear();
6120 }
6121 });
6122 } else {
6123 if (this._trigger("stop", event) !== false) {
6124 this._clear();
6125 }
6126 }
6127
6128 return false;
6129 },
6130
6131 _mouseUp: function( event ) {
6132 this._unblockFrames();
6133
6134 //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
6135 if ( $.ui.ddmanager ) {
6136 $.ui.ddmanager.dragStop(this, event);
6137 }
6138
6139 // Only need to focus if the event occurred on the draggable itself, see #10527
6140 if ( this.handleElement.is( event.target ) ) {
6141 // The interaction is over; whether or not the click resulted in a drag, focus the element
6142 this.element.focus();
6143 }
6144
6145 return $.ui.mouse.prototype._mouseUp.call(this, event);
6146 },
6147
6148 cancel: function() {
6149
6150 if (this.helper.is(".ui-draggable-dragging")) {
6151 this._mouseUp({});
6152 } else {
6153 this._clear();
6154 }
6155
6156 return this;
6157
6158 },
6159
6160 _getHandle: function(event) {
6161 return this.options.handle ?
6162 !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
6163 true;
6164 },
6165
6166 _setHandleClassName: function() {
6167 this.handleElement = this.options.handle ?
6168 this.element.find( this.options.handle ) : this.element;
6169 this.handleElement.addClass( "ui-draggable-handle" );
6170 },
6171
6172 _removeHandleClassName: function() {
6173 this.handleElement.removeClass( "ui-draggable-handle" );
6174 },
6175
6176 _createHelper: function(event) {
6177
6178 var o = this.options,
6179 helperIsFunction = $.isFunction( o.helper ),
6180 helper = helperIsFunction ?
6181 $( o.helper.apply( this.element[ 0 ], [ event ] ) ) :
6182 ( o.helper === "clone" ?
6183 this.element.clone().removeAttr( "id" ) :
6184 this.element );
6185
6186 if (!helper.parents("body").length) {
6187 helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo));
6188 }
6189
6190 // http://bugs.jqueryui.com/ticket/9446
6191 // a helper function can return the original element
6192 // which wouldn't have been set to relative in _create
6193 if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) {
6194 this._setPositionRelative();
6195 }
6196
6197 if (helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) {
6198 helper.css("position", "absolute");
6199 }
6200
6201 return helper;
6202
6203 },
6204
6205 _setPositionRelative: function() {
6206 if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) {
6207 this.element[ 0 ].style.position = "relative";
6208 }
6209 },
6210
6211 _adjustOffsetFromHelper: function(obj) {
6212 if (typeof obj === "string") {
6213 obj = obj.split(" ");
6214 }
6215 if ($.isArray(obj)) {
6216 obj = { left: +obj[0], top: +obj[1] || 0 };
6217 }
6218 if ("left" in obj) {
6219 this.offset.click.left = obj.left + this.margins.left;
6220 }
6221 if ("right" in obj) {
6222 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
6223 }
6224 if ("top" in obj) {
6225 this.offset.click.top = obj.top + this.margins.top;
6226 }
6227 if ("bottom" in obj) {
6228 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
6229 }
6230 },
6231
6232 _isRootNode: function( element ) {
6233 return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
6234 },
6235
6236 _getParentOffset: function() {
6237
6238 //Get the offsetParent and cache its position
6239 var po = this.offsetParent.offset(),
6240 document = this.document[ 0 ];
6241
6242 // This is a special case where we need to modify a offset calculated on start, since the following happened:
6243 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
6244 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
6245 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
6246 if (this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
6247 po.left += this.scrollParent.scrollLeft();
6248 po.top += this.scrollParent.scrollTop();
6249 }
6250
6251 if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
6252 po = { top: 0, left: 0 };
6253 }
6254
6255 return {
6256 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"), 10) || 0),
6257 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"), 10) || 0)
6258 };
6259
6260 },
6261
6262 _getRelativeOffset: function() {
6263 if ( this.cssPosition !== "relative" ) {
6264 return { top: 0, left: 0 };
6265 }
6266
6267 var p = this.element.position(),
6268 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
6269
6270 return {
6271 top: p.top - ( parseInt(this.helper.css( "top" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
6272 left: p.left - ( parseInt(this.helper.css( "left" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
6273 };
6274
6275 },
6276
6277 _cacheMargins: function() {
6278 this.margins = {
6279 left: (parseInt(this.element.css("marginLeft"), 10) || 0),
6280 top: (parseInt(this.element.css("marginTop"), 10) || 0),
6281 right: (parseInt(this.element.css("marginRight"), 10) || 0),
6282 bottom: (parseInt(this.element.css("marginBottom"), 10) || 0)
6283 };
6284 },
6285
6286 _cacheHelperProportions: function() {
6287 this.helperProportions = {
6288 width: this.helper.outerWidth(),
6289 height: this.helper.outerHeight()
6290 };
6291 },
6292
6293 _setContainment: function() {
6294
6295 var isUserScrollable, c, ce,
6296 o = this.options,
6297 document = this.document[ 0 ];
6298
6299 this.relativeContainer = null;
6300
6301 if ( !o.containment ) {
6302 this.containment = null;
6303 return;
6304 }
6305
6306 if ( o.containment === "window" ) {
6307 this.containment = [
6308 $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
6309 $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
6310 $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left,
6311 $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
6312 ];
6313 return;
6314 }
6315
6316 if ( o.containment === "document") {
6317 this.containment = [
6318 0,
6319 0,
6320 $( document ).width() - this.helperProportions.width - this.margins.left,
6321 ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
6322 ];
6323 return;
6324 }
6325
6326 if ( o.containment.constructor === Array ) {
6327 this.containment = o.containment;
6328 return;
6329 }
6330
6331 if ( o.containment === "parent" ) {
6332 o.containment = this.helper[ 0 ].parentNode;
6333 }
6334
6335 c = $( o.containment );
6336 ce = c[ 0 ];
6337
6338 if ( !ce ) {
6339 return;
6340 }
6341
6342 isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) );
6343
6344 this.containment = [
6345 ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
6346 ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ),
6347 ( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
6348 ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) -
6349 ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) -
6350 this.helperProportions.width -
6351 this.margins.left -
6352 this.margins.right,
6353 ( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
6354 ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) -
6355 ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) -
6356 this.helperProportions.height -
6357 this.margins.top -
6358 this.margins.bottom
6359 ];
6360 this.relativeContainer = c;
6361 },
6362
6363 _convertPositionTo: function(d, pos) {
6364
6365 if (!pos) {
6366 pos = this.position;
6367 }
6368
6369 var mod = d === "absolute" ? 1 : -1,
6370 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
6371
6372 return {
6373 top: (
6374 pos.top + // The absolute mouse position
6375 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
6376 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
6377 ( ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod)
6378 ),
6379 left: (
6380 pos.left + // The absolute mouse position
6381 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
6382 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
6383 ( ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod)
6384 )
6385 };
6386
6387 },
6388
6389 _generatePosition: function( event, constrainPosition ) {
6390
6391 var containment, co, top, left,
6392 o = this.options,
6393 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
6394 pageX = event.pageX,
6395 pageY = event.pageY;
6396
6397 // Cache the scroll
6398 if ( !scrollIsRootNode || !this.offset.scroll ) {
6399 this.offset.scroll = {
6400 top: this.scrollParent.scrollTop(),
6401 left: this.scrollParent.scrollLeft()
6402 };
6403 }
6404
6405 /*
6406 * - Position constraining -
6407 * Constrain the position to a mix of grid, containment.
6408 */
6409
6410 // If we are not dragging yet, we won't check for options
6411 if ( constrainPosition ) {
6412 if ( this.containment ) {
6413 if ( this.relativeContainer ){
6414 co = this.relativeContainer.offset();
6415 containment = [
6416 this.containment[ 0 ] + co.left,
6417 this.containment[ 1 ] + co.top,
6418 this.containment[ 2 ] + co.left,
6419 this.containment[ 3 ] + co.top
6420 ];
6421 } else {
6422 containment = this.containment;
6423 }
6424
6425 if (event.pageX - this.offset.click.left < containment[0]) {
6426 pageX = containment[0] + this.offset.click.left;
6427 }
6428 if (event.pageY - this.offset.click.top < containment[1]) {
6429 pageY = containment[1] + this.offset.click.top;
6430 }
6431 if (event.pageX - this.offset.click.left > containment[2]) {
6432 pageX = containment[2] + this.offset.click.left;
6433 }
6434 if (event.pageY - this.offset.click.top > containment[3]) {
6435 pageY = containment[3] + this.offset.click.top;
6436 }
6437 }
6438
6439 if (o.grid) {
6440 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
6441 top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
6442 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;
6443
6444 left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
6445 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;
6446 }
6447
6448 if ( o.axis === "y" ) {
6449 pageX = this.originalPageX;
6450 }
6451
6452 if ( o.axis === "x" ) {
6453 pageY = this.originalPageY;
6454 }
6455 }
6456
6457 return {
6458 top: (
6459 pageY - // The absolute mouse position
6460 this.offset.click.top - // Click offset (relative to the element)
6461 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
6462 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
6463 ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
6464 ),
6465 left: (
6466 pageX - // The absolute mouse position
6467 this.offset.click.left - // Click offset (relative to the element)
6468 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
6469 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
6470 ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
6471 )
6472 };
6473
6474 },
6475
6476 _clear: function() {
6477 this.helper.removeClass("ui-draggable-dragging");
6478 if (this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) {
6479 this.helper.remove();
6480 }
6481 this.helper = null;
6482 this.cancelHelperRemoval = false;
6483 if ( this.destroyOnClear ) {
6484 this.destroy();
6485 }
6486 },
6487
6488 _normalizeRightBottom: function() {
6489 if ( this.options.axis !== "y" && this.helper.css( "right" ) !== "auto" ) {
6490 this.helper.width( this.helper.width() );
6491 this.helper.css( "right", "auto" );
6492 }
6493 if ( this.options.axis !== "x" && this.helper.css( "bottom" ) !== "auto" ) {
6494 this.helper.height( this.helper.height() );
6495 this.helper.css( "bottom", "auto" );
6496 }
6497 },
6498
6499 // From now on bulk stuff - mainly helpers
6500
6501 _trigger: function( type, event, ui ) {
6502 ui = ui || this._uiHash();
6503 $.ui.plugin.call( this, type, [ event, ui, this ], true );
6504
6505 // Absolute position and offset (see #6884 ) have to be recalculated after plugins
6506 if ( /^(drag|start|stop)/.test( type ) ) {
6507 this.positionAbs = this._convertPositionTo( "absolute" );
6508 ui.offset = this.positionAbs;
6509 }
6510 return $.Widget.prototype._trigger.call( this, type, event, ui );
6511 },
6512
6513 plugins: {},
6514
6515 _uiHash: function() {
6516 return {
6517 helper: this.helper,
6518 position: this.position,
6519 originalPosition: this.originalPosition,
6520 offset: this.positionAbs
6521 };
6522 }
6523
6524 });
6525
6526 $.ui.plugin.add( "draggable", "connectToSortable", {
6527 start: function( event, ui, draggable ) {
6528 var uiSortable = $.extend( {}, ui, {
6529 item: draggable.element
6530 });
6531
6532 draggable.sortables = [];
6533 $( draggable.options.connectToSortable ).each(function() {
6534 var sortable = $( this ).sortable( "instance" );
6535
6536 if ( sortable && !sortable.options.disabled ) {
6537 draggable.sortables.push( sortable );
6538
6539 // refreshPositions is called at drag start to refresh the containerCache
6540 // which is used in drag. This ensures it's initialized and synchronized
6541 // with any changes that might have happened on the page since initialization.
6542 sortable.refreshPositions();
6543 sortable._trigger("activate", event, uiSortable);
6544 }
6545 });
6546 },
6547 stop: function( event, ui, draggable ) {
6548 var uiSortable = $.extend( {}, ui, {
6549 item: draggable.element
6550 });
6551
6552 draggable.cancelHelperRemoval = false;
6553
6554 $.each( draggable.sortables, function() {
6555 var sortable = this;
6556
6557 if ( sortable.isOver ) {
6558 sortable.isOver = 0;
6559
6560 // Allow this sortable to handle removing the helper
6561 draggable.cancelHelperRemoval = true;
6562 sortable.cancelHelperRemoval = false;
6563
6564 // Use _storedCSS To restore properties in the sortable,
6565 // as this also handles revert (#9675) since the draggable
6566 // may have modified them in unexpected ways (#8809)
6567 sortable._storedCSS = {
6568 position: sortable.placeholder.css( "position" ),
6569 top: sortable.placeholder.css( "top" ),
6570 left: sortable.placeholder.css( "left" )
6571 };
6572
6573 sortable._mouseStop(event);
6574
6575 // Once drag has ended, the sortable should return to using
6576 // its original helper, not the shared helper from draggable
6577 sortable.options.helper = sortable.options._helper;
6578 } else {
6579 // Prevent this Sortable from removing the helper.
6580 // However, don't set the draggable to remove the helper
6581 // either as another connected Sortable may yet handle the removal.
6582 sortable.cancelHelperRemoval = true;
6583
6584 sortable._trigger( "deactivate", event, uiSortable );
6585 }
6586 });
6587 },
6588 drag: function( event, ui, draggable ) {
6589 $.each( draggable.sortables, function() {
6590 var innermostIntersecting = false,
6591 sortable = this;
6592
6593 // Copy over variables that sortable's _intersectsWith uses
6594 sortable.positionAbs = draggable.positionAbs;
6595 sortable.helperProportions = draggable.helperProportions;
6596 sortable.offset.click = draggable.offset.click;
6597
6598 if ( sortable._intersectsWith( sortable.containerCache ) ) {
6599 innermostIntersecting = true;
6600
6601 $.each( draggable.sortables, function() {
6602 // Copy over variables that sortable's _intersectsWith uses
6603 this.positionAbs = draggable.positionAbs;
6604 this.helperProportions = draggable.helperProportions;
6605 this.offset.click = draggable.offset.click;
6606
6607 if ( this !== sortable &&
6608 this._intersectsWith( this.containerCache ) &&
6609 $.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) {
6610 innermostIntersecting = false;
6611 }
6612
6613 return innermostIntersecting;
6614 });
6615 }
6616
6617 if ( innermostIntersecting ) {
6618 // If it intersects, we use a little isOver variable and set it once,
6619 // so that the move-in stuff gets fired only once.
6620 if ( !sortable.isOver ) {
6621 sortable.isOver = 1;
6622
6623 sortable.currentItem = ui.helper
6624 .appendTo( sortable.element )
6625 .data( "ui-sortable-item", true );
6626
6627 // Store helper option to later restore it
6628 sortable.options._helper = sortable.options.helper;
6629
6630 sortable.options.helper = function() {
6631 return ui.helper[ 0 ];
6632 };
6633
6634 // Fire the start events of the sortable with our passed browser event,
6635 // and our own helper (so it doesn't create a new one)
6636 event.target = sortable.currentItem[ 0 ];
6637 sortable._mouseCapture( event, true );
6638 sortable._mouseStart( event, true, true );
6639
6640 // Because the browser event is way off the new appended portlet,
6641 // modify necessary variables to reflect the changes
6642 sortable.offset.click.top = draggable.offset.click.top;
6643 sortable.offset.click.left = draggable.offset.click.left;
6644 sortable.offset.parent.left -= draggable.offset.parent.left -
6645 sortable.offset.parent.left;
6646 sortable.offset.parent.top -= draggable.offset.parent.top -
6647 sortable.offset.parent.top;
6648
6649 draggable._trigger( "toSortable", event );
6650
6651 // Inform draggable that the helper is in a valid drop zone,
6652 // used solely in the revert option to handle "valid/invalid".
6653 draggable.dropped = sortable.element;
6654
6655 // Need to refreshPositions of all sortables in the case that
6656 // adding to one sortable changes the location of the other sortables (#9675)
6657 $.each( draggable.sortables, function() {
6658 this.refreshPositions();
6659 });
6660
6661 // hack so receive/update callbacks work (mostly)
6662 draggable.currentItem = draggable.element;
6663 sortable.fromOutside = draggable;
6664 }
6665
6666 if ( sortable.currentItem ) {
6667 sortable._mouseDrag( event );
6668 // Copy the sortable's position because the draggable's can potentially reflect
6669 // a relative position, while sortable is always absolute, which the dragged
6670 // element has now become. (#8809)
6671 ui.position = sortable.position;
6672 }
6673 } else {
6674 // If it doesn't intersect with the sortable, and it intersected before,
6675 // we fake the drag stop of the sortable, but make sure it doesn't remove
6676 // the helper by using cancelHelperRemoval.
6677 if ( sortable.isOver ) {
6678
6679 sortable.isOver = 0;
6680 sortable.cancelHelperRemoval = true;
6681
6682 // Calling sortable's mouseStop would trigger a revert,
6683 // so revert must be temporarily false until after mouseStop is called.
6684 sortable.options._revert = sortable.options.revert;
6685 sortable.options.revert = false;
6686
6687 sortable._trigger( "out", event, sortable._uiHash( sortable ) );
6688 sortable._mouseStop( event, true );
6689
6690 // restore sortable behaviors that were modfied
6691 // when the draggable entered the sortable area (#9481)
6692 sortable.options.revert = sortable.options._revert;
6693 sortable.options.helper = sortable.options._helper;
6694
6695 if ( sortable.placeholder ) {
6696 sortable.placeholder.remove();
6697 }
6698
6699 // Recalculate the draggable's offset considering the sortable
6700 // may have modified them in unexpected ways (#8809)
6701 draggable._refreshOffsets( event );
6702 ui.position = draggable._generatePosition( event, true );
6703
6704 draggable._trigger( "fromSortable", event );
6705
6706 // Inform draggable that the helper is no longer in a valid drop zone
6707 draggable.dropped = false;
6708
6709 // Need to refreshPositions of all sortables just in case removing
6710 // from one sortable changes the location of other sortables (#9675)
6711 $.each( draggable.sortables, function() {
6712 this.refreshPositions();
6713 });
6714 }
6715 }
6716 });
6717 }
6718 });
6719
6720 $.ui.plugin.add("draggable", "cursor", {
6721 start: function( event, ui, instance ) {
6722 var t = $( "body" ),
6723 o = instance.options;
6724
6725 if (t.css("cursor")) {
6726 o._cursor = t.css("cursor");
6727 }
6728 t.css("cursor", o.cursor);
6729 },
6730 stop: function( event, ui, instance ) {
6731 var o = instance.options;
6732 if (o._cursor) {
6733 $("body").css("cursor", o._cursor);
6734 }
6735 }
6736 });
6737
6738 $.ui.plugin.add("draggable", "opacity", {
6739 start: function( event, ui, instance ) {
6740 var t = $( ui.helper ),
6741 o = instance.options;
6742 if (t.css("opacity")) {
6743 o._opacity = t.css("opacity");
6744 }
6745 t.css("opacity", o.opacity);
6746 },
6747 stop: function( event, ui, instance ) {
6748 var o = instance.options;
6749 if (o._opacity) {
6750 $(ui.helper).css("opacity", o._opacity);
6751 }
6752 }
6753 });
6754
6755 $.ui.plugin.add("draggable", "scroll", {
6756 start: function( event, ui, i ) {
6757 if ( !i.scrollParentNotHidden ) {
6758 i.scrollParentNotHidden = i.helper.scrollParent( false );
6759 }
6760
6761 if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] && i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) {
6762 i.overflowOffset = i.scrollParentNotHidden.offset();
6763 }
6764 },
6765 drag: function( event, ui, i ) {
6766
6767 var o = i.options,
6768 scrolled = false,
6769 scrollParent = i.scrollParentNotHidden[ 0 ],
6770 document = i.document[ 0 ];
6771
6772 if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) {
6773 if ( !o.axis || o.axis !== "x" ) {
6774 if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY < o.scrollSensitivity ) {
6775 scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed;
6776 } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) {
6777 scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed;
6778 }
6779 }
6780
6781 if ( !o.axis || o.axis !== "y" ) {
6782 if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX < o.scrollSensitivity ) {
6783 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed;
6784 } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) {
6785 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed;
6786 }
6787 }
6788
6789 } else {
6790
6791 if (!o.axis || o.axis !== "x") {
6792 if (event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
6793 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
6794 } else if ($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
6795 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
6796 }
6797 }
6798
6799 if (!o.axis || o.axis !== "y") {
6800 if (event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
6801 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
6802 } else if ($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
6803 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
6804 }
6805 }
6806
6807 }
6808
6809 if (scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
6810 $.ui.ddmanager.prepareOffsets(i, event);
6811 }
6812
6813 }
6814 });
6815
6816 $.ui.plugin.add("draggable", "snap", {
6817 start: function( event, ui, i ) {
6818
6819 var o = i.options;
6820
6821 i.snapElements = [];
6822
6823 $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() {
6824 var $t = $(this),
6825 $o = $t.offset();
6826 if (this !== i.element[0]) {
6827 i.snapElements.push({
6828 item: this,
6829 width: $t.outerWidth(), height: $t.outerHeight(),
6830 top: $o.top, left: $o.left
6831 });
6832 }
6833 });
6834
6835 },
6836 drag: function( event, ui, inst ) {
6837
6838 var ts, bs, ls, rs, l, r, t, b, i, first,
6839 o = inst.options,
6840 d = o.snapTolerance,
6841 x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
6842 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
6843
6844 for (i = inst.snapElements.length - 1; i >= 0; i--){
6845
6846 l = inst.snapElements[i].left - inst.margins.left;
6847 r = l + inst.snapElements[i].width;
6848 t = inst.snapElements[i].top - inst.margins.top;
6849 b = t + inst.snapElements[i].height;
6850
6851 if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) {
6852 if (inst.snapElements[i].snapping) {
6853 (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
6854 }
6855 inst.snapElements[i].snapping = false;
6856 continue;
6857 }
6858
6859 if (o.snapMode !== "inner") {
6860 ts = Math.abs(t - y2) <= d;
6861 bs = Math.abs(b - y1) <= d;
6862 ls = Math.abs(l - x2) <= d;
6863 rs = Math.abs(r - x1) <= d;
6864 if (ts) {
6865 ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top;
6866 }
6867 if (bs) {
6868 ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top;
6869 }
6870 if (ls) {
6871 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left;
6872 }
6873 if (rs) {
6874 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left;
6875 }
6876 }
6877
6878 first = (ts || bs || ls || rs);
6879
6880 if (o.snapMode !== "outer") {
6881 ts = Math.abs(t - y1) <= d;
6882 bs = Math.abs(b - y2) <= d;
6883 ls = Math.abs(l - x1) <= d;
6884 rs = Math.abs(r - x2) <= d;
6885 if (ts) {
6886 ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top;
6887 }
6888 if (bs) {
6889 ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top;
6890 }
6891 if (ls) {
6892 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left;
6893 }
6894 if (rs) {
6895 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left;
6896 }
6897 }
6898
6899 if (!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) {
6900 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
6901 }
6902 inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
6903
6904 }
6905
6906 }
6907 });
6908
6909 $.ui.plugin.add("draggable", "stack", {
6910 start: function( event, ui, instance ) {
6911 var min,
6912 o = instance.options,
6913 group = $.makeArray($(o.stack)).sort(function(a, b) {
6914 return (parseInt($(a).css("zIndex"), 10) || 0) - (parseInt($(b).css("zIndex"), 10) || 0);
6915 });
6916
6917 if (!group.length) { return; }
6918
6919 min = parseInt($(group[0]).css("zIndex"), 10) || 0;
6920 $(group).each(function(i) {
6921 $(this).css("zIndex", min + i);
6922 });
6923 this.css("zIndex", (min + group.length));
6924 }
6925 });
6926
6927 $.ui.plugin.add("draggable", "zIndex", {
6928 start: function( event, ui, instance ) {
6929 var t = $( ui.helper ),
6930 o = instance.options;
6931
6932 if (t.css("zIndex")) {
6933 o._zIndex = t.css("zIndex");
6934 }
6935 t.css("zIndex", o.zIndex);
6936 },
6937 stop: function( event, ui, instance ) {
6938 var o = instance.options;
6939
6940 if (o._zIndex) {
6941 $(ui.helper).css("zIndex", o._zIndex);
6942 }
6943 }
6944 });
6945
6946 var draggable = $.ui.draggable;
6947
6948
6949 /*!
6950 * jQuery UI Resizable 1.11.3
6951 * http://jqueryui.com
6952 *
6953 * Copyright jQuery Foundation and other contributors
6954 * Released under the MIT license.
6955 * http://jquery.org/license
6956 *
6957 * http://api.jqueryui.com/resizable/
6958 */
6959
6960
6961 $.widget("ui.resizable", $.ui.mouse, {
6962 version: "1.11.3",
6963 widgetEventPrefix: "resize",
6964 options: {
6965 alsoResize: false,
6966 animate: false,
6967 animateDuration: "slow",
6968 animateEasing: "swing",
6969 aspectRatio: false,
6970 autoHide: false,
6971 containment: false,
6972 ghost: false,
6973 grid: false,
6974 handles: "e,s,se",
6975 helper: false,
6976 maxHeight: null,
6977 maxWidth: null,
6978 minHeight: 10,
6979 minWidth: 10,
6980 // See #7960
6981 zIndex: 90,
6982
6983 // callbacks
6984 resize: null,
6985 start: null,
6986 stop: null
6987 },
6988
6989 _num: function( value ) {
6990 return parseInt( value, 10 ) || 0;
6991 },
6992
6993 _isNumber: function( value ) {
6994 return !isNaN( parseInt( value, 10 ) );
6995 },
6996
6997 _hasScroll: function( el, a ) {
6998
6999 if ( $( el ).css( "overflow" ) === "hidden") {
7000 return false;
7001 }
7002
7003 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
7004 has = false;
7005
7006 if ( el[ scroll ] > 0 ) {
7007 return true;
7008 }
7009
7010 // TODO: determine which cases actually cause this to happen
7011 // if the element doesn't have the scroll set, see if it's possible to
7012 // set the scroll
7013 el[ scroll ] = 1;
7014 has = ( el[ scroll ] > 0 );
7015 el[ scroll ] = 0;
7016 return has;
7017 },
7018
7019 _create: function() {
7020
7021 var n, i, handle, axis, hname,
7022 that = this,
7023 o = this.options;
7024 this.element.addClass("ui-resizable");
7025
7026 $.extend(this, {
7027 _aspectRatio: !!(o.aspectRatio),
7028 aspectRatio: o.aspectRatio,
7029 originalElement: this.element,
7030 _proportionallyResizeElements: [],
7031 _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
7032 });
7033
7034 // Wrap the element if it cannot hold child nodes
7035 if (this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)) {
7036
7037 this.element.wrap(
7038 $("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({
7039 position: this.element.css("position"),
7040 width: this.element.outerWidth(),
7041 height: this.element.outerHeight(),
7042 top: this.element.css("top"),
7043 left: this.element.css("left")
7044 })
7045 );
7046
7047 this.element = this.element.parent().data(
7048 "ui-resizable", this.element.resizable( "instance" )
7049 );
7050
7051 this.elementIsWrapper = true;
7052
7053 this.element.css({
7054 marginLeft: this.originalElement.css("marginLeft"),
7055 marginTop: this.originalElement.css("marginTop"),
7056 marginRight: this.originalElement.css("marginRight"),
7057 marginBottom: this.originalElement.css("marginBottom")
7058 });
7059 this.originalElement.css({
7060 marginLeft: 0,
7061 marginTop: 0,
7062 marginRight: 0,
7063 marginBottom: 0
7064 });
7065 // support: Safari
7066 // Prevent Safari textarea resize
7067 this.originalResizeStyle = this.originalElement.css("resize");
7068 this.originalElement.css("resize", "none");
7069
7070 this._proportionallyResizeElements.push( this.originalElement.css({
7071 position: "static",
7072 zoom: 1,
7073 display: "block"
7074 }) );
7075
7076 // support: IE9
7077 // avoid IE jump (hard set the margin)
7078 this.originalElement.css({ margin: this.originalElement.css("margin") });
7079
7080 this._proportionallyResize();
7081 }
7082
7083 this.handles = o.handles ||
7084 ( !$(".ui-resizable-handle", this.element).length ?
7085 "e,s,se" : {
7086 n: ".ui-resizable-n",
7087 e: ".ui-resizable-e",
7088 s: ".ui-resizable-s",
7089 w: ".ui-resizable-w",
7090 se: ".ui-resizable-se",
7091 sw: ".ui-resizable-sw",
7092 ne: ".ui-resizable-ne",
7093 nw: ".ui-resizable-nw"
7094 } );
7095
7096 if (this.handles.constructor === String) {
7097
7098 if ( this.handles === "all") {
7099 this.handles = "n,e,s,w,se,sw,ne,nw";
7100 }
7101
7102 n = this.handles.split(",");
7103 this.handles = {};
7104
7105 for (i = 0; i < n.length; i++) {
7106
7107 handle = $.trim(n[i]);
7108 hname = "ui-resizable-" + handle;
7109 axis = $("<div class='ui-resizable-handle " + hname + "'></div>");
7110
7111 axis.css({ zIndex: o.zIndex });
7112
7113 // TODO : What's going on here?
7114 if ("se" === handle) {
7115 axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se");
7116 }
7117
7118 this.handles[handle] = ".ui-resizable-" + handle;
7119 this.element.append(axis);
7120 }
7121
7122 }
7123
7124 this._renderAxis = function(target) {
7125
7126 var i, axis, padPos, padWrapper;
7127
7128 target = target || this.element;
7129
7130 for (i in this.handles) {
7131
7132 if (this.handles[i].constructor === String) {
7133 this.handles[i] = this.element.children( this.handles[ i ] ).first().show();
7134 }
7135
7136 if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)) {
7137
7138 axis = $(this.handles[i], this.element);
7139
7140 padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
7141
7142 padPos = [ "padding",
7143 /ne|nw|n/.test(i) ? "Top" :
7144 /se|sw|s/.test(i) ? "Bottom" :
7145 /^e$/.test(i) ? "Right" : "Left" ].join("");
7146
7147 target.css(padPos, padWrapper);
7148
7149 this._proportionallyResize();
7150
7151 }
7152
7153 // TODO: What's that good for? There's not anything to be executed left
7154 if (!$(this.handles[i]).length) {
7155 continue;
7156 }
7157 }
7158 };
7159
7160 // TODO: make renderAxis a prototype function
7161 this._renderAxis(this.element);
7162
7163 this._handles = $(".ui-resizable-handle", this.element)
7164 .disableSelection();
7165
7166 this._handles.mouseover(function() {
7167 if (!that.resizing) {
7168 if (this.className) {
7169 axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
7170 }
7171 that.axis = axis && axis[1] ? axis[1] : "se";
7172 }
7173 });
7174
7175 if (o.autoHide) {
7176 this._handles.hide();
7177 $(this.element)
7178 .addClass("ui-resizable-autohide")
7179 .mouseenter(function() {
7180 if (o.disabled) {
7181 return;
7182 }
7183 $(this).removeClass("ui-resizable-autohide");
7184 that._handles.show();
7185 })
7186 .mouseleave(function() {
7187 if (o.disabled) {
7188 return;
7189 }
7190 if (!that.resizing) {
7191 $(this).addClass("ui-resizable-autohide");
7192 that._handles.hide();
7193 }
7194 });
7195 }
7196
7197 this._mouseInit();
7198
7199 },
7200
7201 _destroy: function() {
7202
7203 this._mouseDestroy();
7204
7205 var wrapper,
7206 _destroy = function(exp) {
7207 $(exp)
7208 .removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
7209 .removeData("resizable")
7210 .removeData("ui-resizable")
7211 .unbind(".resizable")
7212 .find(".ui-resizable-handle")
7213 .remove();
7214 };
7215
7216 // TODO: Unwrap at same DOM position
7217 if (this.elementIsWrapper) {
7218 _destroy(this.element);
7219 wrapper = this.element;
7220 this.originalElement.css({
7221 position: wrapper.css("position"),
7222 width: wrapper.outerWidth(),
7223 height: wrapper.outerHeight(),
7224 top: wrapper.css("top"),
7225 left: wrapper.css("left")
7226 }).insertAfter( wrapper );
7227 wrapper.remove();
7228 }
7229
7230 this.originalElement.css("resize", this.originalResizeStyle);
7231 _destroy(this.originalElement);
7232
7233 return this;
7234 },
7235
7236 _mouseCapture: function(event) {
7237 var i, handle,
7238 capture = false;
7239
7240 for (i in this.handles) {
7241 handle = $(this.handles[i])[0];
7242 if (handle === event.target || $.contains(handle, event.target)) {
7243 capture = true;
7244 }
7245 }
7246
7247 return !this.options.disabled && capture;
7248 },
7249
7250 _mouseStart: function(event) {
7251
7252 var curleft, curtop, cursor,
7253 o = this.options,
7254 el = this.element;
7255
7256 this.resizing = true;
7257
7258 this._renderProxy();
7259
7260 curleft = this._num(this.helper.css("left"));
7261 curtop = this._num(this.helper.css("top"));
7262
7263 if (o.containment) {
7264 curleft += $(o.containment).scrollLeft() || 0;
7265 curtop += $(o.containment).scrollTop() || 0;
7266 }
7267
7268 this.offset = this.helper.offset();
7269 this.position = { left: curleft, top: curtop };
7270
7271 this.size = this._helper ? {
7272 width: this.helper.width(),
7273 height: this.helper.height()
7274 } : {
7275 width: el.width(),
7276 height: el.height()
7277 };
7278
7279 this.originalSize = this._helper ? {
7280 width: el.outerWidth(),
7281 height: el.outerHeight()
7282 } : {
7283 width: el.width(),
7284 height: el.height()
7285 };
7286
7287 this.sizeDiff = {
7288 width: el.outerWidth() - el.width(),
7289 height: el.outerHeight() - el.height()
7290 };
7291
7292 this.originalPosition = { left: curleft, top: curtop };
7293 this.originalMousePosition = { left: event.pageX, top: event.pageY };
7294
7295 this.aspectRatio = (typeof o.aspectRatio === "number") ?
7296 o.aspectRatio :
7297 ((this.originalSize.width / this.originalSize.height) || 1);
7298
7299 cursor = $(".ui-resizable-" + this.axis).css("cursor");
7300 $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor);
7301
7302 el.addClass("ui-resizable-resizing");
7303 this._propagate("start", event);
7304 return true;
7305 },
7306
7307 _mouseDrag: function(event) {
7308
7309 var data, props,
7310 smp = this.originalMousePosition,
7311 a = this.axis,
7312 dx = (event.pageX - smp.left) || 0,
7313 dy = (event.pageY - smp.top) || 0,
7314 trigger = this._change[a];
7315
7316 this._updatePrevProperties();
7317
7318 if (!trigger) {
7319 return false;
7320 }
7321
7322 data = trigger.apply(this, [ event, dx, dy ]);
7323
7324 this._updateVirtualBoundaries(event.shiftKey);
7325 if (this._aspectRatio || event.shiftKey) {
7326 data = this._updateRatio(data, event);
7327 }
7328
7329 data = this._respectSize(data, event);
7330
7331 this._updateCache(data);
7332
7333 this._propagate("resize", event);
7334
7335 props = this._applyChanges();
7336
7337 if ( !this._helper && this._proportionallyResizeElements.length ) {
7338 this._proportionallyResize();
7339 }
7340
7341 if ( !$.isEmptyObject( props ) ) {
7342 this._updatePrevProperties();
7343 this._trigger( "resize", event, this.ui() );
7344 this._applyChanges();
7345 }
7346
7347 return false;
7348 },
7349
7350 _mouseStop: function(event) {
7351
7352 this.resizing = false;
7353 var pr, ista, soffseth, soffsetw, s, left, top,
7354 o = this.options, that = this;
7355
7356 if (this._helper) {
7357
7358 pr = this._proportionallyResizeElements;
7359 ista = pr.length && (/textarea/i).test(pr[0].nodeName);
7360 soffseth = ista && this._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height;
7361 soffsetw = ista ? 0 : that.sizeDiff.width;
7362
7363 s = {
7364 width: (that.helper.width() - soffsetw),
7365 height: (that.helper.height() - soffseth)
7366 };
7367 left = (parseInt(that.element.css("left"), 10) +
7368 (that.position.left - that.originalPosition.left)) || null;
7369 top = (parseInt(that.element.css("top"), 10) +
7370 (that.position.top - that.originalPosition.top)) || null;
7371
7372 if (!o.animate) {
7373 this.element.css($.extend(s, { top: top, left: left }));
7374 }
7375
7376 that.helper.height(that.size.height);
7377 that.helper.width(that.size.width);
7378
7379 if (this._helper && !o.animate) {
7380 this._proportionallyResize();
7381 }
7382 }
7383
7384 $("body").css("cursor", "auto");
7385
7386 this.element.removeClass("ui-resizable-resizing");
7387
7388 this._propagate("stop", event);
7389
7390 if (this._helper) {
7391 this.helper.remove();
7392 }
7393
7394 return false;
7395
7396 },
7397
7398 _updatePrevProperties: function() {
7399 this.prevPosition = {
7400 top: this.position.top,
7401 left: this.position.left
7402 };
7403 this.prevSize = {
7404 width: this.size.width,
7405 height: this.size.height
7406 };
7407 },
7408
7409 _applyChanges: function() {
7410 var props = {};
7411
7412 if ( this.position.top !== this.prevPosition.top ) {
7413 props.top = this.position.top + "px";
7414 }
7415 if ( this.position.left !== this.prevPosition.left ) {
7416 props.left = this.position.left + "px";
7417 }
7418 if ( this.size.width !== this.prevSize.width ) {
7419 props.width = this.size.width + "px";
7420 }
7421 if ( this.size.height !== this.prevSize.height ) {
7422 props.height = this.size.height + "px";
7423 }
7424
7425 this.helper.css( props );
7426
7427 return props;
7428 },
7429
7430 _updateVirtualBoundaries: function(forceAspectRatio) {
7431 var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
7432 o = this.options;
7433
7434 b = {
7435 minWidth: this._isNumber(o.minWidth) ? o.minWidth : 0,
7436 maxWidth: this._isNumber(o.maxWidth) ? o.maxWidth : Infinity,
7437 minHeight: this._isNumber(o.minHeight) ? o.minHeight : 0,
7438 maxHeight: this._isNumber(o.maxHeight) ? o.maxHeight : Infinity
7439 };
7440
7441 if (this._aspectRatio || forceAspectRatio) {
7442 pMinWidth = b.minHeight * this.aspectRatio;
7443 pMinHeight = b.minWidth / this.aspectRatio;
7444 pMaxWidth = b.maxHeight * this.aspectRatio;
7445 pMaxHeight = b.maxWidth / this.aspectRatio;
7446
7447 if (pMinWidth > b.minWidth) {
7448 b.minWidth = pMinWidth;
7449 }
7450 if (pMinHeight > b.minHeight) {
7451 b.minHeight = pMinHeight;
7452 }
7453 if (pMaxWidth < b.maxWidth) {
7454 b.maxWidth = pMaxWidth;
7455 }
7456 if (pMaxHeight < b.maxHeight) {
7457 b.maxHeight = pMaxHeight;
7458 }
7459 }
7460 this._vBoundaries = b;
7461 },
7462
7463 _updateCache: function(data) {
7464 this.offset = this.helper.offset();
7465 if (this._isNumber(data.left)) {
7466 this.position.left = data.left;
7467 }
7468 if (this._isNumber(data.top)) {
7469 this.position.top = data.top;
7470 }
7471 if (this._isNumber(data.height)) {
7472 this.size.height = data.height;
7473 }
7474 if (this._isNumber(data.width)) {
7475 this.size.width = data.width;
7476 }
7477 },
7478
7479 _updateRatio: function( data ) {
7480
7481 var cpos = this.position,
7482 csize = this.size,
7483 a = this.axis;
7484
7485 if (this._isNumber(data.height)) {
7486 data.width = (data.height * this.aspectRatio);
7487 } else if (this._isNumber(data.width)) {
7488 data.height = (data.width / this.aspectRatio);
7489 }
7490
7491 if (a === "sw") {
7492 data.left = cpos.left + (csize.width - data.width);
7493 data.top = null;
7494 }
7495 if (a === "nw") {
7496 data.top = cpos.top + (csize.height - data.height);
7497 data.left = cpos.left + (csize.width - data.width);
7498 }
7499
7500 return data;
7501 },
7502
7503 _respectSize: function( data ) {
7504
7505 var o = this._vBoundaries,
7506 a = this.axis,
7507 ismaxw = this._isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width),
7508 ismaxh = this._isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
7509 isminw = this._isNumber(data.width) && o.minWidth && (o.minWidth > data.width),
7510 isminh = this._isNumber(data.height) && o.minHeight && (o.minHeight > data.height),
7511 dw = this.originalPosition.left + this.originalSize.width,
7512 dh = this.position.top + this.size.height,
7513 cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
7514 if (isminw) {
7515 data.width = o.minWidth;
7516 }
7517 if (isminh) {
7518 data.height = o.minHeight;
7519 }
7520 if (ismaxw) {
7521 data.width = o.maxWidth;
7522 }
7523 if (ismaxh) {
7524 data.height = o.maxHeight;
7525 }
7526
7527 if (isminw && cw) {
7528 data.left = dw - o.minWidth;
7529 }
7530 if (ismaxw && cw) {
7531 data.left = dw - o.maxWidth;
7532 }
7533 if (isminh && ch) {
7534 data.top = dh - o.minHeight;
7535 }
7536 if (ismaxh && ch) {
7537 data.top = dh - o.maxHeight;
7538 }
7539
7540 // Fixing jump error on top/left - bug #2330
7541 if (!data.width && !data.height && !data.left && data.top) {
7542 data.top = null;
7543 } else if (!data.width && !data.height && !data.top && data.left) {
7544 data.left = null;
7545 }
7546
7547 return data;
7548 },
7549
7550 _getPaddingPlusBorderDimensions: function( element ) {
7551 var i = 0,
7552 widths = [],
7553 borders = [
7554 element.css( "borderTopWidth" ),
7555 element.css( "borderRightWidth" ),
7556 element.css( "borderBottomWidth" ),
7557 element.css( "borderLeftWidth" )
7558 ],
7559 paddings = [
7560 element.css( "paddingTop" ),
7561 element.css( "paddingRight" ),
7562 element.css( "paddingBottom" ),
7563 element.css( "paddingLeft" )
7564 ];
7565
7566 for ( ; i < 4; i++ ) {
7567 widths[ i ] = ( parseInt( borders[ i ], 10 ) || 0 );
7568 widths[ i ] += ( parseInt( paddings[ i ], 10 ) || 0 );
7569 }
7570
7571 return {
7572 height: widths[ 0 ] + widths[ 2 ],
7573 width: widths[ 1 ] + widths[ 3 ]
7574 };
7575 },
7576
7577 _proportionallyResize: function() {
7578
7579 if (!this._proportionallyResizeElements.length) {
7580 return;
7581 }
7582
7583 var prel,
7584 i = 0,
7585 element = this.helper || this.element;
7586
7587 for ( ; i < this._proportionallyResizeElements.length; i++) {
7588
7589 prel = this._proportionallyResizeElements[i];
7590
7591 // TODO: Seems like a bug to cache this.outerDimensions
7592 // considering that we are in a loop.
7593 if (!this.outerDimensions) {
7594 this.outerDimensions = this._getPaddingPlusBorderDimensions( prel );
7595 }
7596
7597 prel.css({
7598 height: (element.height() - this.outerDimensions.height) || 0,
7599 width: (element.width() - this.outerDimensions.width) || 0
7600 });
7601
7602 }
7603
7604 },
7605
7606 _renderProxy: function() {
7607
7608 var el = this.element, o = this.options;
7609 this.elementOffset = el.offset();
7610
7611 if (this._helper) {
7612
7613 this.helper = this.helper || $("<div style='overflow:hidden;'></div>");
7614
7615 this.helper.addClass(this._helper).css({
7616 width: this.element.outerWidth() - 1,
7617 height: this.element.outerHeight() - 1,
7618 position: "absolute",
7619 left: this.elementOffset.left + "px",
7620 top: this.elementOffset.top + "px",
7621 zIndex: ++o.zIndex //TODO: Don't modify option
7622 });
7623
7624 this.helper
7625 .appendTo("body")
7626 .disableSelection();
7627
7628 } else {
7629 this.helper = this.element;
7630 }
7631
7632 },
7633
7634 _change: {
7635 e: function(event, dx) {
7636 return { width: this.originalSize.width + dx };
7637 },
7638 w: function(event, dx) {
7639 var cs = this.originalSize, sp = this.originalPosition;
7640 return { left: sp.left + dx, width: cs.width - dx };
7641 },
7642 n: function(event, dx, dy) {
7643 var cs = this.originalSize, sp = this.originalPosition;
7644 return { top: sp.top + dy, height: cs.height - dy };
7645 },
7646 s: function(event, dx, dy) {
7647 return { height: this.originalSize.height + dy };
7648 },
7649 se: function(event, dx, dy) {
7650 return $.extend(this._change.s.apply(this, arguments),
7651 this._change.e.apply(this, [ event, dx, dy ]));
7652 },
7653 sw: function(event, dx, dy) {
7654 return $.extend(this._change.s.apply(this, arguments),
7655 this._change.w.apply(this, [ event, dx, dy ]));
7656 },
7657 ne: function(event, dx, dy) {
7658 return $.extend(this._change.n.apply(this, arguments),
7659 this._change.e.apply(this, [ event, dx, dy ]));
7660 },
7661 nw: function(event, dx, dy) {
7662 return $.extend(this._change.n.apply(this, arguments),
7663 this._change.w.apply(this, [ event, dx, dy ]));
7664 }
7665 },
7666
7667 _propagate: function(n, event) {
7668 $.ui.plugin.call(this, n, [ event, this.ui() ]);
7669 (n !== "resize" && this._trigger(n, event, this.ui()));
7670 },
7671
7672 plugins: {},
7673
7674 ui: function() {
7675 return {
7676 originalElement: this.originalElement,
7677 element: this.element,
7678 helper: this.helper,
7679 position: this.position,
7680 size: this.size,
7681 originalSize: this.originalSize,
7682 originalPosition: this.originalPosition
7683 };
7684 }
7685
7686 });
7687
7688 /*
7689 * Resizable Extensions
7690 */
7691
7692 $.ui.plugin.add("resizable", "animate", {
7693
7694 stop: function( event ) {
7695 var that = $(this).resizable( "instance" ),
7696 o = that.options,
7697 pr = that._proportionallyResizeElements,
7698 ista = pr.length && (/textarea/i).test(pr[0].nodeName),
7699 soffseth = ista && that._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height,
7700 soffsetw = ista ? 0 : that.sizeDiff.width,
7701 style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) },
7702 left = (parseInt(that.element.css("left"), 10) +
7703 (that.position.left - that.originalPosition.left)) || null,
7704 top = (parseInt(that.element.css("top"), 10) +
7705 (that.position.top - that.originalPosition.top)) || null;
7706
7707 that.element.animate(
7708 $.extend(style, top && left ? { top: top, left: left } : {}), {
7709 duration: o.animateDuration,
7710 easing: o.animateEasing,
7711 step: function() {
7712
7713 var data = {
7714 width: parseInt(that.element.css("width"), 10),
7715 height: parseInt(that.element.css("height"), 10),
7716 top: parseInt(that.element.css("top"), 10),
7717 left: parseInt(that.element.css("left"), 10)
7718 };
7719
7720 if (pr && pr.length) {
7721 $(pr[0]).css({ width: data.width, height: data.height });
7722 }
7723
7724 // propagating resize, and updating values for each animation step
7725 that._updateCache(data);
7726 that._propagate("resize", event);
7727
7728 }
7729 }
7730 );
7731 }
7732
7733 });
7734
7735 $.ui.plugin.add( "resizable", "containment", {
7736
7737 start: function() {
7738 var element, p, co, ch, cw, width, height,
7739 that = $( this ).resizable( "instance" ),
7740 o = that.options,
7741 el = that.element,
7742 oc = o.containment,
7743 ce = ( oc instanceof $ ) ? oc.get( 0 ) : ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc;
7744
7745 if ( !ce ) {
7746 return;
7747 }
7748
7749 that.containerElement = $( ce );
7750
7751 if ( /document/.test( oc ) || oc === document ) {
7752 that.containerOffset = {
7753 left: 0,
7754 top: 0
7755 };
7756 that.containerPosition = {
7757 left: 0,
7758 top: 0
7759 };
7760
7761 that.parentData = {
7762 element: $( document ),
7763 left: 0,
7764 top: 0,
7765 width: $( document ).width(),
7766 height: $( document ).height() || document.body.parentNode.scrollHeight
7767 };
7768 } else {
7769 element = $( ce );
7770 p = [];
7771 $([ "Top", "Right", "Left", "Bottom" ]).each(function( i, name ) {
7772 p[ i ] = that._num( element.css( "padding" + name ) );
7773 });
7774
7775 that.containerOffset = element.offset();
7776 that.containerPosition = element.position();
7777 that.containerSize = {
7778 height: ( element.innerHeight() - p[ 3 ] ),
7779 width: ( element.innerWidth() - p[ 1 ] )
7780 };
7781
7782 co = that.containerOffset;
7783 ch = that.containerSize.height;
7784 cw = that.containerSize.width;
7785 width = ( that._hasScroll ( ce, "left" ) ? ce.scrollWidth : cw );
7786 height = ( that._hasScroll ( ce ) ? ce.scrollHeight : ch ) ;
7787
7788 that.parentData = {
7789 element: ce,
7790 left: co.left,
7791 top: co.top,
7792 width: width,
7793 height: height
7794 };
7795 }
7796 },
7797
7798 resize: function( event ) {
7799 var woset, hoset, isParent, isOffsetRelative,
7800 that = $( this ).resizable( "instance" ),
7801 o = that.options,
7802 co = that.containerOffset,
7803 cp = that.position,
7804 pRatio = that._aspectRatio || event.shiftKey,
7805 cop = {
7806 top: 0,
7807 left: 0
7808 },
7809 ce = that.containerElement,
7810 continueResize = true;
7811
7812 if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) {
7813 cop = co;
7814 }
7815
7816 if ( cp.left < ( that._helper ? co.left : 0 ) ) {
7817 that.size.width = that.size.width +
7818 ( that._helper ?
7819 ( that.position.left - co.left ) :
7820 ( that.position.left - cop.left ) );
7821
7822 if ( pRatio ) {
7823 that.size.height = that.size.width / that.aspectRatio;
7824 continueResize = false;
7825 }
7826 that.position.left = o.helper ? co.left : 0;
7827 }
7828
7829 if ( cp.top < ( that._helper ? co.top : 0 ) ) {
7830 that.size.height = that.size.height +
7831 ( that._helper ?
7832 ( that.position.top - co.top ) :
7833 that.position.top );
7834
7835 if ( pRatio ) {
7836 that.size.width = that.size.height * that.aspectRatio;
7837 continueResize = false;
7838 }
7839 that.position.top = that._helper ? co.top : 0;
7840 }
7841
7842 isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 );
7843 isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) );
7844
7845 if ( isParent && isOffsetRelative ) {
7846 that.offset.left = that.parentData.left + that.position.left;
7847 that.offset.top = that.parentData.top + that.position.top;
7848 } else {
7849 that.offset.left = that.element.offset().left;
7850 that.offset.top = that.element.offset().top;
7851 }
7852
7853 woset = Math.abs( that.sizeDiff.width +
7854 (that._helper ?
7855 that.offset.left - cop.left :
7856 (that.offset.left - co.left)) );
7857
7858 hoset = Math.abs( that.sizeDiff.height +
7859 (that._helper ?
7860 that.offset.top - cop.top :
7861 (that.offset.top - co.top)) );
7862
7863 if ( woset + that.size.width >= that.parentData.width ) {
7864 that.size.width = that.parentData.width - woset;
7865 if ( pRatio ) {
7866 that.size.height = that.size.width / that.aspectRatio;
7867 continueResize = false;
7868 }
7869 }
7870
7871 if ( hoset + that.size.height >= that.parentData.height ) {
7872 that.size.height = that.parentData.height - hoset;
7873 if ( pRatio ) {
7874 that.size.width = that.size.height * that.aspectRatio;
7875 continueResize = false;
7876 }
7877 }
7878
7879 if ( !continueResize ) {
7880 that.position.left = that.prevPosition.left;
7881 that.position.top = that.prevPosition.top;
7882 that.size.width = that.prevSize.width;
7883 that.size.height = that.prevSize.height;
7884 }
7885 },
7886
7887 stop: function() {
7888 var that = $( this ).resizable( "instance" ),
7889 o = that.options,
7890 co = that.containerOffset,
7891 cop = that.containerPosition,
7892 ce = that.containerElement,
7893 helper = $( that.helper ),
7894 ho = helper.offset(),
7895 w = helper.outerWidth() - that.sizeDiff.width,
7896 h = helper.outerHeight() - that.sizeDiff.height;
7897
7898 if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) {
7899 $( this ).css({
7900 left: ho.left - cop.left - co.left,
7901 width: w,
7902 height: h
7903 });
7904 }
7905
7906 if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) {
7907 $( this ).css({
7908 left: ho.left - cop.left - co.left,
7909 width: w,
7910 height: h
7911 });
7912 }
7913 }
7914 });
7915
7916 $.ui.plugin.add("resizable", "alsoResize", {
7917
7918 start: function() {
7919 var that = $(this).resizable( "instance" ),
7920 o = that.options,
7921 _store = function(exp) {
7922 $(exp).each(function() {
7923 var el = $(this);
7924 el.data("ui-resizable-alsoresize", {
7925 width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
7926 left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10)
7927 });
7928 });
7929 };
7930
7931 if (typeof(o.alsoResize) === "object" && !o.alsoResize.parentNode) {
7932 if (o.alsoResize.length) {
7933 o.alsoResize = o.alsoResize[0];
7934 _store(o.alsoResize);
7935 } else {
7936 $.each(o.alsoResize, function(exp) {
7937 _store(exp);
7938 });
7939 }
7940 } else {
7941 _store(o.alsoResize);
7942 }
7943 },
7944
7945 resize: function(event, ui) {
7946 var that = $(this).resizable( "instance" ),
7947 o = that.options,
7948 os = that.originalSize,
7949 op = that.originalPosition,
7950 delta = {
7951 height: (that.size.height - os.height) || 0,
7952 width: (that.size.width - os.width) || 0,
7953 top: (that.position.top - op.top) || 0,
7954 left: (that.position.left - op.left) || 0
7955 },
7956
7957 _alsoResize = function(exp, c) {
7958 $(exp).each(function() {
7959 var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {},
7960 css = c && c.length ?
7961 c :
7962 el.parents(ui.originalElement[0]).length ?
7963 [ "width", "height" ] :
7964 [ "width", "height", "top", "left" ];
7965
7966 $.each(css, function(i, prop) {
7967 var sum = (start[prop] || 0) + (delta[prop] || 0);
7968 if (sum && sum >= 0) {
7969 style[prop] = sum || null;
7970 }
7971 });
7972
7973 el.css(style);
7974 });
7975 };
7976
7977 if (typeof(o.alsoResize) === "object" && !o.alsoResize.nodeType) {
7978 $.each(o.alsoResize, function(exp, c) {
7979 _alsoResize(exp, c);
7980 });
7981 } else {
7982 _alsoResize(o.alsoResize);
7983 }
7984 },
7985
7986 stop: function() {
7987 $(this).removeData("resizable-alsoresize");
7988 }
7989 });
7990
7991 $.ui.plugin.add("resizable", "ghost", {
7992
7993 start: function() {
7994
7995 var that = $(this).resizable( "instance" ), o = that.options, cs = that.size;
7996
7997 that.ghost = that.originalElement.clone();
7998 that.ghost
7999 .css({
8000 opacity: 0.25,
8001 display: "block",
8002 position: "relative",
8003 height: cs.height,
8004 width: cs.width,
8005 margin: 0,
8006 left: 0,
8007 top: 0
8008 })
8009 .addClass("ui-resizable-ghost")
8010 .addClass(typeof o.ghost === "string" ? o.ghost : "");
8011
8012 that.ghost.appendTo(that.helper);
8013
8014 },
8015
8016 resize: function() {
8017 var that = $(this).resizable( "instance" );
8018 if (that.ghost) {
8019 that.ghost.css({
8020 position: "relative",
8021 height: that.size.height,
8022 width: that.size.width
8023 });
8024 }
8025 },
8026
8027 stop: function() {
8028 var that = $(this).resizable( "instance" );
8029 if (that.ghost && that.helper) {
8030 that.helper.get(0).removeChild(that.ghost.get(0));
8031 }
8032 }
8033
8034 });
8035
8036 $.ui.plugin.add("resizable", "grid", {
8037
8038 resize: function() {
8039 var outerDimensions,
8040 that = $(this).resizable( "instance" ),
8041 o = that.options,
8042 cs = that.size,
8043 os = that.originalSize,
8044 op = that.originalPosition,
8045 a = that.axis,
8046 grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid,
8047 gridX = (grid[0] || 1),
8048 gridY = (grid[1] || 1),
8049 ox = Math.round((cs.width - os.width) / gridX) * gridX,
8050 oy = Math.round((cs.height - os.height) / gridY) * gridY,
8051 newWidth = os.width + ox,
8052 newHeight = os.height + oy,
8053 isMaxWidth = o.maxWidth && (o.maxWidth < newWidth),
8054 isMaxHeight = o.maxHeight && (o.maxHeight < newHeight),
8055 isMinWidth = o.minWidth && (o.minWidth > newWidth),
8056 isMinHeight = o.minHeight && (o.minHeight > newHeight);
8057
8058 o.grid = grid;
8059
8060 if (isMinWidth) {
8061 newWidth += gridX;
8062 }
8063 if (isMinHeight) {
8064 newHeight += gridY;
8065 }
8066 if (isMaxWidth) {
8067 newWidth -= gridX;
8068 }
8069 if (isMaxHeight) {
8070 newHeight -= gridY;
8071 }
8072
8073 if (/^(se|s|e)$/.test(a)) {
8074 that.size.width = newWidth;
8075 that.size.height = newHeight;
8076 } else if (/^(ne)$/.test(a)) {
8077 that.size.width = newWidth;
8078 that.size.height = newHeight;
8079 that.position.top = op.top - oy;
8080 } else if (/^(sw)$/.test(a)) {
8081 that.size.width = newWidth;
8082 that.size.height = newHeight;
8083 that.position.left = op.left - ox;
8084 } else {
8085 if ( newHeight - gridY <= 0 || newWidth - gridX <= 0) {
8086 outerDimensions = that._getPaddingPlusBorderDimensions( this );
8087 }
8088
8089 if ( newHeight - gridY > 0 ) {
8090 that.size.height = newHeight;
8091 that.position.top = op.top - oy;
8092 } else {
8093 newHeight = gridY - outerDimensions.height;
8094 that.size.height = newHeight;
8095 that.position.top = op.top + os.height - newHeight;
8096 }
8097 if ( newWidth - gridX > 0 ) {
8098 that.size.width = newWidth;
8099 that.position.left = op.left - ox;
8100 } else {
8101 newWidth = gridX - outerDimensions.width;
8102 that.size.width = newWidth;
8103 that.position.left = op.left + os.width - newWidth;
8104 }
8105 }
8106 }
8107
8108 });
8109
8110 var resizable = $.ui.resizable;
8111
8112
8113 /*!
8114 * jQuery UI Dialog 1.11.3
8115 * http://jqueryui.com
8116 *
8117 * Copyright jQuery Foundation and other contributors
8118 * Released under the MIT license.
8119 * http://jquery.org/license
8120 *
8121 * http://api.jqueryui.com/dialog/
8122 */
8123
8124
8125 var dialog = $.widget( "ui.dialog", {
8126 version: "1.11.3",
8127 options: {
8128 appendTo: "body",
8129 autoOpen: true,
8130 buttons: [],
8131 closeOnEscape: true,
8132 closeText: "Close",
8133 dialogClass: "",
8134 draggable: true,
8135 hide: null,
8136 height: "auto",
8137 maxHeight: null,
8138 maxWidth: null,
8139 minHeight: 150,
8140 minWidth: 150,
8141 modal: false,
8142 position: {
8143 my: "center",
8144 at: "center",
8145 of: window,
8146 collision: "fit",
8147 // Ensure the titlebar is always visible
8148 using: function( pos ) {
8149 var topOffset = $( this ).css( pos ).offset().top;
8150 if ( topOffset < 0 ) {
8151 $( this ).css( "top", pos.top - topOffset );
8152 }
8153 }
8154 },
8155 resizable: true,
8156 show: null,
8157 title: null,
8158 width: 300,
8159
8160 // callbacks
8161 beforeClose: null,
8162 close: null,
8163 drag: null,
8164 dragStart: null,
8165 dragStop: null,
8166 focus: null,
8167 open: null,
8168 resize: null,
8169 resizeStart: null,
8170 resizeStop: null
8171 },
8172
8173 sizeRelatedOptions: {
8174 buttons: true,
8175 height: true,
8176 maxHeight: true,
8177 maxWidth: true,
8178 minHeight: true,
8179 minWidth: true,
8180 width: true
8181 },
8182
8183 resizableRelatedOptions: {
8184 maxHeight: true,
8185 maxWidth: true,
8186 minHeight: true,
8187 minWidth: true
8188 },
8189
8190 _create: function() {
8191 this.originalCss = {
8192 display: this.element[ 0 ].style.display,
8193 width: this.element[ 0 ].style.width,
8194 minHeight: this.element[ 0 ].style.minHeight,
8195 maxHeight: this.element[ 0 ].style.maxHeight,
8196 height: this.element[ 0 ].style.height
8197 };
8198 this.originalPosition = {
8199 parent: this.element.parent(),
8200 index: this.element.parent().children().index( this.element )
8201 };
8202 this.originalTitle = this.element.attr( "title" );
8203 this.options.title = this.options.title || this.originalTitle;
8204
8205 this._createWrapper();
8206
8207 this.element
8208 .show()
8209 .removeAttr( "title" )
8210 .addClass( "ui-dialog-content ui-widget-content" )
8211 .appendTo( this.uiDialog );
8212
8213 this._createTitlebar();
8214 this._createButtonPane();
8215
8216 if ( this.options.draggable && $.fn.draggable ) {
8217 this._makeDraggable();
8218 }
8219 if ( this.options.resizable && $.fn.resizable ) {
8220 this._makeResizable();
8221 }
8222
8223 this._isOpen = false;
8224
8225 this._trackFocus();
8226 },
8227
8228 _init: function() {
8229 if ( this.options.autoOpen ) {
8230 this.open();
8231 }
8232 },
8233
8234 _appendTo: function() {
8235 var element = this.options.appendTo;
8236 if ( element && (element.jquery || element.nodeType) ) {
8237 return $( element );
8238 }
8239 return this.document.find( element || "body" ).eq( 0 );
8240 },
8241
8242 _destroy: function() {
8243 var next,
8244 originalPosition = this.originalPosition;
8245
8246 this._destroyOverlay();
8247
8248 this.element
8249 .removeUniqueId()
8250 .removeClass( "ui-dialog-content ui-widget-content" )
8251 .css( this.originalCss )
8252 // Without detaching first, the following becomes really slow
8253 .detach();
8254
8255 this.uiDialog.stop( true, true ).remove();
8256
8257 if ( this.originalTitle ) {
8258 this.element.attr( "title", this.originalTitle );
8259 }
8260
8261 next = originalPosition.parent.children().eq( originalPosition.index );
8262 // Don't try to place the dialog next to itself (#8613)
8263 if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
8264 next.before( this.element );
8265 } else {
8266 originalPosition.parent.append( this.element );
8267 }
8268 },
8269
8270 widget: function() {
8271 return this.uiDialog;
8272 },
8273
8274 disable: $.noop,
8275 enable: $.noop,
8276
8277 close: function( event ) {
8278 var activeElement,
8279 that = this;
8280
8281 if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
8282 return;
8283 }
8284
8285 this._isOpen = false;
8286 this._focusedElement = null;
8287 this._destroyOverlay();
8288 this._untrackInstance();
8289
8290 if ( !this.opener.filter( ":focusable" ).focus().length ) {
8291
8292 // support: IE9
8293 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
8294 try {
8295 activeElement = this.document[ 0 ].activeElement;
8296
8297 // Support: IE9, IE10
8298 // If the <body> is blurred, IE will switch windows, see #4520
8299 if ( activeElement && activeElement.nodeName.toLowerCase() !== "body" ) {
8300
8301 // Hiding a focused element doesn't trigger blur in WebKit
8302 // so in case we have nothing to focus on, explicitly blur the active element
8303 // https://bugs.webkit.org/show_bug.cgi?id=47182
8304 $( activeElement ).blur();
8305 }
8306 } catch ( error ) {}
8307 }
8308
8309 this._hide( this.uiDialog, this.options.hide, function() {
8310 that._trigger( "close", event );
8311 });
8312 },
8313
8314 isOpen: function() {
8315 return this._isOpen;
8316 },
8317
8318 moveToTop: function() {
8319 this._moveToTop();
8320 },
8321
8322 _moveToTop: function( event, silent ) {
8323 var moved = false,
8324 zIndicies = this.uiDialog.siblings( ".ui-front:visible" ).map(function() {
8325 return +$( this ).css( "z-index" );
8326 }).get(),
8327 zIndexMax = Math.max.apply( null, zIndicies );
8328
8329 if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) {
8330 this.uiDialog.css( "z-index", zIndexMax + 1 );
8331 moved = true;
8332 }
8333
8334 if ( moved && !silent ) {
8335 this._trigger( "focus", event );
8336 }
8337 return moved;
8338 },
8339
8340 open: function() {
8341 var that = this;
8342 if ( this._isOpen ) {
8343 if ( this._moveToTop() ) {
8344 this._focusTabbable();
8345 }
8346 return;
8347 }
8348
8349 this._isOpen = true;
8350 this.opener = $( this.document[ 0 ].activeElement );
8351
8352 this._size();
8353 this._position();
8354 this._createOverlay();
8355 this._moveToTop( null, true );
8356
8357 // Ensure the overlay is moved to the top with the dialog, but only when
8358 // opening. The overlay shouldn't move after the dialog is open so that
8359 // modeless dialogs opened after the modal dialog stack properly.
8360 if ( this.overlay ) {
8361 this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 );
8362 }
8363
8364 this._show( this.uiDialog, this.options.show, function() {
8365 that._focusTabbable();
8366 that._trigger( "focus" );
8367 });
8368
8369 // Track the dialog immediately upon openening in case a focus event
8370 // somehow occurs outside of the dialog before an element inside the
8371 // dialog is focused (#10152)
8372 this._makeFocusTarget();
8373
8374 this._trigger( "open" );
8375 },
8376
8377 _focusTabbable: function() {
8378 // Set focus to the first match:
8379 // 1. An element that was focused previously
8380 // 2. First element inside the dialog matching [autofocus]
8381 // 3. Tabbable element inside the content element
8382 // 4. Tabbable element inside the buttonpane
8383 // 5. The close button
8384 // 6. The dialog itself
8385 var hasFocus = this._focusedElement;
8386 if ( !hasFocus ) {
8387 hasFocus = this.element.find( "[autofocus]" );
8388 }
8389 if ( !hasFocus.length ) {
8390 hasFocus = this.element.find( ":tabbable" );
8391 }
8392 if ( !hasFocus.length ) {
8393 hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
8394 }
8395 if ( !hasFocus.length ) {
8396 hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" );
8397 }
8398 if ( !hasFocus.length ) {
8399 hasFocus = this.uiDialog;
8400 }
8401 hasFocus.eq( 0 ).focus();
8402 },
8403
8404 _keepFocus: function( event ) {
8405 function checkFocus() {
8406 var activeElement = this.document[0].activeElement,
8407 isActive = this.uiDialog[0] === activeElement ||
8408 $.contains( this.uiDialog[0], activeElement );
8409 if ( !isActive ) {
8410 this._focusTabbable();
8411 }
8412 }
8413 event.preventDefault();
8414 checkFocus.call( this );
8415 // support: IE
8416 // IE <= 8 doesn't prevent moving focus even with event.preventDefault()
8417 // so we check again later
8418 this._delay( checkFocus );
8419 },
8420
8421 _createWrapper: function() {
8422 this.uiDialog = $("<div>")
8423 .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " +
8424 this.options.dialogClass )
8425 .hide()
8426 .attr({
8427 // Setting tabIndex makes the div focusable
8428 tabIndex: -1,
8429 role: "dialog"
8430 })
8431 .appendTo( this._appendTo() );
8432
8433 this._on( this.uiDialog, {
8434 keydown: function( event ) {
8435 if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
8436 event.keyCode === $.ui.keyCode.ESCAPE ) {
8437 event.preventDefault();
8438 this.close( event );
8439 return;
8440 }
8441
8442 // prevent tabbing out of dialogs
8443 if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) {
8444 return;
8445 }
8446 var tabbables = this.uiDialog.find( ":tabbable" ),
8447 first = tabbables.filter( ":first" ),
8448 last = tabbables.filter( ":last" );
8449
8450 if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) {
8451 this._delay(function() {
8452 first.focus();
8453 });
8454 event.preventDefault();
8455 } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) {
8456 this._delay(function() {
8457 last.focus();
8458 });
8459 event.preventDefault();
8460 }
8461 },
8462 mousedown: function( event ) {
8463 if ( this._moveToTop( event ) ) {
8464 this._focusTabbable();
8465 }
8466 }
8467 });
8468
8469 // We assume that any existing aria-describedby attribute means
8470 // that the dialog content is marked up properly
8471 // otherwise we brute force the content as the description
8472 if ( !this.element.find( "[aria-describedby]" ).length ) {
8473 this.uiDialog.attr({
8474 "aria-describedby": this.element.uniqueId().attr( "id" )
8475 });
8476 }
8477 },
8478
8479 _createTitlebar: function() {
8480 var uiDialogTitle;
8481
8482 this.uiDialogTitlebar = $( "<div>" )
8483 .addClass( "ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix" )
8484 .prependTo( this.uiDialog );
8485 this._on( this.uiDialogTitlebar, {
8486 mousedown: function( event ) {
8487 // Don't prevent click on close button (#8838)
8488 // Focusing a dialog that is partially scrolled out of view
8489 // causes the browser to scroll it into view, preventing the click event
8490 if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) {
8491 // Dialog isn't getting focus when dragging (#8063)
8492 this.uiDialog.focus();
8493 }
8494 }
8495 });
8496
8497 // support: IE
8498 // Use type="button" to prevent enter keypresses in textboxes from closing the
8499 // dialog in IE (#9312)
8500 this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
8501 .button({
8502 label: this.options.closeText,
8503 icons: {
8504 primary: "ui-icon-closethick"
8505 },
8506 text: false
8507 })
8508 .addClass( "ui-dialog-titlebar-close" )
8509 .appendTo( this.uiDialogTitlebar );
8510 this._on( this.uiDialogTitlebarClose, {
8511 click: function( event ) {
8512 event.preventDefault();
8513 this.close( event );
8514 }
8515 });
8516
8517 uiDialogTitle = $( "<span>" )
8518 .uniqueId()
8519 .addClass( "ui-dialog-title" )
8520 .prependTo( this.uiDialogTitlebar );
8521 this._title( uiDialogTitle );
8522
8523 this.uiDialog.attr({
8524 "aria-labelledby": uiDialogTitle.attr( "id" )
8525 });
8526 },
8527
8528 _title: function( title ) {
8529 if ( !this.options.title ) {
8530 title.html( "&#160;" );
8531 }
8532 title.text( this.options.title );
8533 },
8534
8535 _createButtonPane: function() {
8536 this.uiDialogButtonPane = $( "<div>" )
8537 .addClass( "ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" );
8538
8539 this.uiButtonSet = $( "<div>" )
8540 .addClass( "ui-dialog-buttonset" )
8541 .appendTo( this.uiDialogButtonPane );
8542
8543 this._createButtons();
8544 },
8545
8546 _createButtons: function() {
8547 var that = this,
8548 buttons = this.options.buttons;
8549
8550 // if we already have a button pane, remove it
8551 this.uiDialogButtonPane.remove();
8552 this.uiButtonSet.empty();
8553
8554 if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) {
8555 this.uiDialog.removeClass( "ui-dialog-buttons" );
8556 return;
8557 }
8558
8559 $.each( buttons, function( name, props ) {
8560 var click, buttonOptions;
8561 props = $.isFunction( props ) ?
8562 { click: props, text: name } :
8563 props;
8564 // Default to a non-submitting button
8565 props = $.extend( { type: "button" }, props );
8566 // Change the context for the click callback to be the main element
8567 click = props.click;
8568 props.click = function() {
8569 click.apply( that.element[ 0 ], arguments );
8570 };
8571 buttonOptions = {
8572 icons: props.icons,
8573 text: props.showText
8574 };
8575 delete props.icons;
8576 delete props.showText;
8577 $( "<button></button>", props )
8578 .button( buttonOptions )
8579 .appendTo( that.uiButtonSet );
8580 });
8581 this.uiDialog.addClass( "ui-dialog-buttons" );
8582 this.uiDialogButtonPane.appendTo( this.uiDialog );
8583 },
8584
8585 _makeDraggable: function() {
8586 var that = this,
8587 options = this.options;
8588
8589 function filteredUi( ui ) {
8590 return {
8591 position: ui.position,
8592 offset: ui.offset
8593 };
8594 }
8595
8596 this.uiDialog.draggable({
8597 cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
8598 handle: ".ui-dialog-titlebar",
8599 containment: "document",
8600 start: function( event, ui ) {
8601 $( this ).addClass( "ui-dialog-dragging" );
8602 that._blockFrames();
8603 that._trigger( "dragStart", event, filteredUi( ui ) );
8604 },
8605 drag: function( event, ui ) {
8606 that._trigger( "drag", event, filteredUi( ui ) );
8607 },
8608 stop: function( event, ui ) {
8609 var left = ui.offset.left - that.document.scrollLeft(),
8610 top = ui.offset.top - that.document.scrollTop();
8611
8612 options.position = {
8613 my: "left top",
8614 at: "left" + (left >= 0 ? "+" : "") + left + " " +
8615 "top" + (top >= 0 ? "+" : "") + top,
8616 of: that.window
8617 };
8618 $( this ).removeClass( "ui-dialog-dragging" );
8619 that._unblockFrames();
8620 that._trigger( "dragStop", event, filteredUi( ui ) );
8621 }
8622 });
8623 },
8624
8625 _makeResizable: function() {
8626 var that = this,
8627 options = this.options,
8628 handles = options.resizable,
8629 // .ui-resizable has position: relative defined in the stylesheet
8630 // but dialogs have to use absolute or fixed positioning
8631 position = this.uiDialog.css("position"),
8632 resizeHandles = typeof handles === "string" ?
8633 handles :
8634 "n,e,s,w,se,sw,ne,nw";
8635
8636 function filteredUi( ui ) {
8637 return {
8638 originalPosition: ui.originalPosition,
8639 originalSize: ui.originalSize,
8640 position: ui.position,
8641 size: ui.size
8642 };
8643 }
8644
8645 this.uiDialog.resizable({
8646 cancel: ".ui-dialog-content",
8647 containment: "document",
8648 alsoResize: this.element,
8649 maxWidth: options.maxWidth,
8650 maxHeight: options.maxHeight,
8651 minWidth: options.minWidth,
8652 minHeight: this._minHeight(),
8653 handles: resizeHandles,
8654 start: function( event, ui ) {
8655 $( this ).addClass( "ui-dialog-resizing" );
8656 that._blockFrames();
8657 that._trigger( "resizeStart", event, filteredUi( ui ) );
8658 },
8659 resize: function( event, ui ) {
8660 that._trigger( "resize", event, filteredUi( ui ) );
8661 },
8662 stop: function( event, ui ) {
8663 var offset = that.uiDialog.offset(),
8664 left = offset.left - that.document.scrollLeft(),
8665 top = offset.top - that.document.scrollTop();
8666
8667 options.height = that.uiDialog.height();
8668 options.width = that.uiDialog.width();
8669 options.position = {
8670 my: "left top",
8671 at: "left" + (left >= 0 ? "+" : "") + left + " " +
8672 "top" + (top >= 0 ? "+" : "") + top,
8673 of: that.window
8674 };
8675 $( this ).removeClass( "ui-dialog-resizing" );
8676 that._unblockFrames();
8677 that._trigger( "resizeStop", event, filteredUi( ui ) );
8678 }
8679 })
8680 .css( "position", position );
8681 },
8682
8683 _trackFocus: function() {
8684 this._on( this.widget(), {
8685 focusin: function( event ) {
8686 this._makeFocusTarget();
8687 this._focusedElement = $( event.target );
8688 }
8689 });
8690 },
8691
8692 _makeFocusTarget: function() {
8693 this._untrackInstance();
8694 this._trackingInstances().unshift( this );
8695 },
8696
8697 _untrackInstance: function() {
8698 var instances = this._trackingInstances(),
8699 exists = $.inArray( this, instances );
8700 if ( exists !== -1 ) {
8701 instances.splice( exists, 1 );
8702 }
8703 },
8704
8705 _trackingInstances: function() {
8706 var instances = this.document.data( "ui-dialog-instances" );
8707 if ( !instances ) {
8708 instances = [];
8709 this.document.data( "ui-dialog-instances", instances );
8710 }
8711 return instances;
8712 },
8713
8714 _minHeight: function() {
8715 var options = this.options;
8716
8717 return options.height === "auto" ?
8718 options.minHeight :
8719 Math.min( options.minHeight, options.height );
8720 },
8721
8722 _position: function() {
8723 // Need to show the dialog to get the actual offset in the position plugin
8724 var isVisible = this.uiDialog.is( ":visible" );
8725 if ( !isVisible ) {
8726 this.uiDialog.show();
8727 }
8728 this.uiDialog.position( this.options.position );
8729 if ( !isVisible ) {
8730 this.uiDialog.hide();
8731 }
8732 },
8733
8734 _setOptions: function( options ) {
8735 var that = this,
8736 resize = false,
8737 resizableOptions = {};
8738
8739 $.each( options, function( key, value ) {
8740 that._setOption( key, value );
8741
8742 if ( key in that.sizeRelatedOptions ) {
8743 resize = true;
8744 }
8745 if ( key in that.resizableRelatedOptions ) {
8746 resizableOptions[ key ] = value;
8747 }
8748 });
8749
8750 if ( resize ) {
8751 this._size();
8752 this._position();
8753 }
8754 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
8755 this.uiDialog.resizable( "option", resizableOptions );
8756 }
8757 },
8758
8759 _setOption: function( key, value ) {
8760 var isDraggable, isResizable,
8761 uiDialog = this.uiDialog;
8762
8763 if ( key === "dialogClass" ) {
8764 uiDialog
8765 .removeClass( this.options.dialogClass )
8766 .addClass( value );
8767 }
8768
8769 if ( key === "disabled" ) {
8770 return;
8771 }
8772
8773 this._super( key, value );
8774
8775 if ( key === "appendTo" ) {
8776 this.uiDialog.appendTo( this._appendTo() );
8777 }
8778
8779 if ( key === "buttons" ) {
8780 this._createButtons();
8781 }
8782
8783 if ( key === "closeText" ) {
8784 this.uiDialogTitlebarClose.button({
8785 // Ensure that we always pass a string
8786 label: "" + value
8787 });
8788 }
8789
8790 if ( key === "draggable" ) {
8791 isDraggable = uiDialog.is( ":data(ui-draggable)" );
8792 if ( isDraggable && !value ) {
8793 uiDialog.draggable( "destroy" );
8794 }
8795
8796 if ( !isDraggable && value ) {
8797 this._makeDraggable();
8798 }
8799 }
8800
8801 if ( key === "position" ) {
8802 this._position();
8803 }
8804
8805 if ( key === "resizable" ) {
8806 // currently resizable, becoming non-resizable
8807 isResizable = uiDialog.is( ":data(ui-resizable)" );
8808 if ( isResizable && !value ) {
8809 uiDialog.resizable( "destroy" );
8810 }
8811
8812 // currently resizable, changing handles
8813 if ( isResizable && typeof value === "string" ) {
8814 uiDialog.resizable( "option", "handles", value );
8815 }
8816
8817 // currently non-resizable, becoming resizable
8818 if ( !isResizable && value !== false ) {
8819 this._makeResizable();
8820 }
8821 }
8822
8823 if ( key === "title" ) {
8824 this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) );
8825 }
8826 },
8827
8828 _size: function() {
8829 // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
8830 // divs will both have width and height set, so we need to reset them
8831 var nonContentHeight, minContentHeight, maxContentHeight,
8832 options = this.options;
8833
8834 // Reset content sizing
8835 this.element.show().css({
8836 width: "auto",
8837 minHeight: 0,
8838 maxHeight: "none",
8839 height: 0
8840 });
8841
8842 if ( options.minWidth > options.width ) {
8843 options.width = options.minWidth;
8844 }
8845
8846 // reset wrapper sizing
8847 // determine the height of all the non-content elements
8848 nonContentHeight = this.uiDialog.css({
8849 height: "auto",
8850 width: options.width
8851 })
8852 .outerHeight();
8853 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
8854 maxContentHeight = typeof options.maxHeight === "number" ?
8855 Math.max( 0, options.maxHeight - nonContentHeight ) :
8856 "none";
8857
8858 if ( options.height === "auto" ) {
8859 this.element.css({
8860 minHeight: minContentHeight,
8861 maxHeight: maxContentHeight,
8862 height: "auto"
8863 });
8864 } else {
8865 this.element.height( Math.max( 0, options.height - nonContentHeight ) );
8866 }
8867
8868 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
8869 this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
8870 }
8871 },
8872
8873 _blockFrames: function() {
8874 this.iframeBlocks = this.document.find( "iframe" ).map(function() {
8875 var iframe = $( this );
8876
8877 return $( "<div>" )
8878 .css({
8879 position: "absolute",
8880 width: iframe.outerWidth(),
8881 height: iframe.outerHeight()
8882 })
8883 .appendTo( iframe.parent() )
8884 .offset( iframe.offset() )[0];
8885 });
8886 },
8887
8888 _unblockFrames: function() {
8889 if ( this.iframeBlocks ) {
8890 this.iframeBlocks.remove();
8891 delete this.iframeBlocks;
8892 }
8893 },
8894
8895 _allowInteraction: function( event ) {
8896 if ( $( event.target ).closest( ".ui-dialog" ).length ) {
8897 return true;
8898 }
8899
8900 // TODO: Remove hack when datepicker implements
8901 // the .ui-front logic (#8989)
8902 return !!$( event.target ).closest( ".ui-datepicker" ).length;
8903 },
8904
8905 _createOverlay: function() {
8906 if ( !this.options.modal ) {
8907 return;
8908 }
8909
8910 // We use a delay in case the overlay is created from an
8911 // event that we're going to be cancelling (#2804)
8912 var isOpening = true;
8913 this._delay(function() {
8914 isOpening = false;
8915 });
8916
8917 if ( !this.document.data( "ui-dialog-overlays" ) ) {
8918
8919 // Prevent use of anchors and inputs
8920 // Using _on() for an event handler shared across many instances is
8921 // safe because the dialogs stack and must be closed in reverse order
8922 this._on( this.document, {
8923 focusin: function( event ) {
8924 if ( isOpening ) {
8925 return;
8926 }
8927
8928 if ( !this._allowInteraction( event ) ) {
8929 event.preventDefault();
8930 this._trackingInstances()[ 0 ]._focusTabbable();
8931 }
8932 }
8933 });
8934 }
8935
8936 this.overlay = $( "<div>" )
8937 .addClass( "ui-widget-overlay ui-front" )
8938 .appendTo( this._appendTo() );
8939 this._on( this.overlay, {
8940 mousedown: "_keepFocus"
8941 });
8942 this.document.data( "ui-dialog-overlays",
8943 (this.document.data( "ui-dialog-overlays" ) || 0) + 1 );
8944 },
8945
8946 _destroyOverlay: function() {
8947 if ( !this.options.modal ) {
8948 return;
8949 }
8950
8951 if ( this.overlay ) {
8952 var overlays = this.document.data( "ui-dialog-overlays" ) - 1;
8953
8954 if ( !overlays ) {
8955 this.document
8956 .unbind( "focusin" )
8957 .removeData( "ui-dialog-overlays" );
8958 } else {
8959 this.document.data( "ui-dialog-overlays", overlays );
8960 }
8961
8962 this.overlay.remove();
8963 this.overlay = null;
8964 }
8965 }
8966 });
8967
8968
8969 /*!
8970 * jQuery UI Droppable 1.11.3
8971 * http://jqueryui.com
8972 *
8973 * Copyright jQuery Foundation and other contributors
8974 * Released under the MIT license.
8975 * http://jquery.org/license
8976 *
8977 * http://api.jqueryui.com/droppable/
8978 */
8979
8980
8981 $.widget( "ui.droppable", {
8982 version: "1.11.3",
8983 widgetEventPrefix: "drop",
8984 options: {
8985 accept: "*",
8986 activeClass: false,
8987 addClasses: true,
8988 greedy: false,
8989 hoverClass: false,
8990 scope: "default",
8991 tolerance: "intersect",
8992
8993 // callbacks
8994 activate: null,
8995 deactivate: null,
8996 drop: null,
8997 out: null,
8998 over: null
8999 },
9000 _create: function() {
9001
9002 var proportions,
9003 o = this.options,
9004 accept = o.accept;
9005
9006 this.isover = false;
9007 this.isout = true;
9008
9009 this.accept = $.isFunction( accept ) ? accept : function( d ) {
9010 return d.is( accept );
9011 };
9012
9013 this.proportions = function( /* valueToWrite */ ) {
9014 if ( arguments.length ) {
9015 // Store the droppable's proportions
9016 proportions = arguments[ 0 ];
9017 } else {
9018 // Retrieve or derive the droppable's proportions
9019 return proportions ?
9020 proportions :
9021 proportions = {
9022 width: this.element[ 0 ].offsetWidth,
9023 height: this.element[ 0 ].offsetHeight
9024 };
9025 }
9026 };
9027
9028 this._addToManager( o.scope );
9029
9030 o.addClasses && this.element.addClass( "ui-droppable" );
9031
9032 },
9033
9034 _addToManager: function( scope ) {
9035 // Add the reference and positions to the manager
9036 $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || [];
9037 $.ui.ddmanager.droppables[ scope ].push( this );
9038 },
9039
9040 _splice: function( drop ) {
9041 var i = 0;
9042 for ( ; i < drop.length; i++ ) {
9043 if ( drop[ i ] === this ) {
9044 drop.splice( i, 1 );
9045 }
9046 }
9047 },
9048
9049 _destroy: function() {
9050 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
9051
9052 this._splice( drop );
9053
9054 this.element.removeClass( "ui-droppable ui-droppable-disabled" );
9055 },
9056
9057 _setOption: function( key, value ) {
9058
9059 if ( key === "accept" ) {
9060 this.accept = $.isFunction( value ) ? value : function( d ) {
9061 return d.is( value );
9062 };
9063 } else if ( key === "scope" ) {
9064 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
9065
9066 this._splice( drop );
9067 this._addToManager( value );
9068 }
9069
9070 this._super( key, value );
9071 },
9072
9073 _activate: function( event ) {
9074 var draggable = $.ui.ddmanager.current;
9075 if ( this.options.activeClass ) {
9076 this.element.addClass( this.options.activeClass );
9077 }
9078 if ( draggable ){
9079 this._trigger( "activate", event, this.ui( draggable ) );
9080 }
9081 },
9082
9083 _deactivate: function( event ) {
9084 var draggable = $.ui.ddmanager.current;
9085 if ( this.options.activeClass ) {
9086 this.element.removeClass( this.options.activeClass );
9087 }
9088 if ( draggable ){
9089 this._trigger( "deactivate", event, this.ui( draggable ) );
9090 }
9091 },
9092
9093 _over: function( event ) {
9094
9095 var draggable = $.ui.ddmanager.current;
9096
9097 // Bail if draggable and droppable are same element
9098 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
9099 return;
9100 }
9101
9102 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
9103 if ( this.options.hoverClass ) {
9104 this.element.addClass( this.options.hoverClass );
9105 }
9106 this._trigger( "over", event, this.ui( draggable ) );
9107 }
9108
9109 },
9110
9111 _out: function( event ) {
9112
9113 var draggable = $.ui.ddmanager.current;
9114
9115 // Bail if draggable and droppable are same element
9116 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
9117 return;
9118 }
9119
9120 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
9121 if ( this.options.hoverClass ) {
9122 this.element.removeClass( this.options.hoverClass );
9123 }
9124 this._trigger( "out", event, this.ui( draggable ) );
9125 }
9126
9127 },
9128
9129 _drop: function( event, custom ) {
9130
9131 var draggable = custom || $.ui.ddmanager.current,
9132 childrenIntersection = false;
9133
9134 // Bail if draggable and droppable are same element
9135 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
9136 return false;
9137 }
9138
9139 this.element.find( ":data(ui-droppable)" ).not( ".ui-draggable-dragging" ).each(function() {
9140 var inst = $( this ).droppable( "instance" );
9141 if (
9142 inst.options.greedy &&
9143 !inst.options.disabled &&
9144 inst.options.scope === draggable.options.scope &&
9145 inst.accept.call( inst.element[ 0 ], ( draggable.currentItem || draggable.element ) ) &&
9146 $.ui.intersect( draggable, $.extend( inst, { offset: inst.element.offset() } ), inst.options.tolerance, event )
9147 ) { childrenIntersection = true; return false; }
9148 });
9149 if ( childrenIntersection ) {
9150 return false;
9151 }
9152
9153 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
9154 if ( this.options.activeClass ) {
9155 this.element.removeClass( this.options.activeClass );
9156 }
9157 if ( this.options.hoverClass ) {
9158 this.element.removeClass( this.options.hoverClass );
9159 }
9160 this._trigger( "drop", event, this.ui( draggable ) );
9161 return this.element;
9162 }
9163
9164 return false;
9165
9166 },
9167
9168 ui: function( c ) {
9169 return {
9170 draggable: ( c.currentItem || c.element ),
9171 helper: c.helper,
9172 position: c.position,
9173 offset: c.positionAbs
9174 };
9175 }
9176
9177 });
9178
9179 $.ui.intersect = (function() {
9180 function isOverAxis( x, reference, size ) {
9181 return ( x >= reference ) && ( x < ( reference + size ) );
9182 }
9183
9184 return function( draggable, droppable, toleranceMode, event ) {
9185
9186 if ( !droppable.offset ) {
9187 return false;
9188 }
9189
9190 var x1 = ( draggable.positionAbs || draggable.position.absolute ).left + draggable.margins.left,
9191 y1 = ( draggable.positionAbs || draggable.position.absolute ).top + draggable.margins.top,
9192 x2 = x1 + draggable.helperProportions.width,
9193 y2 = y1 + draggable.helperProportions.height,
9194 l = droppable.offset.left,
9195 t = droppable.offset.top,
9196 r = l + droppable.proportions().width,
9197 b = t + droppable.proportions().height;
9198
9199 switch ( toleranceMode ) {
9200 case "fit":
9201 return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
9202 case "intersect":
9203 return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
9204 x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
9205 t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
9206 y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
9207 case "pointer":
9208 return isOverAxis( event.pageY, t, droppable.proportions().height ) && isOverAxis( event.pageX, l, droppable.proportions().width );
9209 case "touch":
9210 return (
9211 ( y1 >= t && y1 <= b ) || // Top edge touching
9212 ( y2 >= t && y2 <= b ) || // Bottom edge touching
9213 ( y1 < t && y2 > b ) // Surrounded vertically
9214 ) && (
9215 ( x1 >= l && x1 <= r ) || // Left edge touching
9216 ( x2 >= l && x2 <= r ) || // Right edge touching
9217 ( x1 < l && x2 > r ) // Surrounded horizontally
9218 );
9219 default:
9220 return false;
9221 }
9222 };
9223 })();
9224
9225 /*
9226 This manager tracks offsets of draggables and droppables
9227 */
9228 $.ui.ddmanager = {
9229 current: null,
9230 droppables: { "default": [] },
9231 prepareOffsets: function( t, event ) {
9232
9233 var i, j,
9234 m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
9235 type = event ? event.type : null, // workaround for #2317
9236 list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack();
9237
9238 droppablesLoop: for ( i = 0; i < m.length; i++ ) {
9239
9240 // No disabled and non-accepted
9241 if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ], ( t.currentItem || t.element ) ) ) ) {
9242 continue;
9243 }
9244
9245 // Filter out elements in the current dragged item
9246 for ( j = 0; j < list.length; j++ ) {
9247 if ( list[ j ] === m[ i ].element[ 0 ] ) {
9248 m[ i ].proportions().height = 0;
9249 continue droppablesLoop;
9250 }
9251 }
9252
9253 m[ i ].visible = m[ i ].element.css( "display" ) !== "none";
9254 if ( !m[ i ].visible ) {
9255 continue;
9256 }
9257
9258 // Activate the droppable if used directly from draggables
9259 if ( type === "mousedown" ) {
9260 m[ i ]._activate.call( m[ i ], event );
9261 }
9262
9263 m[ i ].offset = m[ i ].element.offset();
9264 m[ i ].proportions({ width: m[ i ].element[ 0 ].offsetWidth, height: m[ i ].element[ 0 ].offsetHeight });
9265
9266 }
9267
9268 },
9269 drop: function( draggable, event ) {
9270
9271 var dropped = false;
9272 // Create a copy of the droppables in case the list changes during the drop (#9116)
9273 $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {
9274
9275 if ( !this.options ) {
9276 return;
9277 }
9278 if ( !this.options.disabled && this.visible && $.ui.intersect( draggable, this, this.options.tolerance, event ) ) {
9279 dropped = this._drop.call( this, event ) || dropped;
9280 }
9281
9282 if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
9283 this.isout = true;
9284 this.isover = false;
9285 this._deactivate.call( this, event );
9286 }
9287
9288 });
9289 return dropped;
9290
9291 },
9292 dragStart: function( draggable, event ) {
9293 // Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
9294 draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
9295 if ( !draggable.options.refreshPositions ) {
9296 $.ui.ddmanager.prepareOffsets( draggable, event );
9297 }
9298 });
9299 },
9300 drag: function( draggable, event ) {
9301
9302 // If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
9303 if ( draggable.options.refreshPositions ) {
9304 $.ui.ddmanager.prepareOffsets( draggable, event );
9305 }
9306
9307 // Run through all droppables and check their positions based on specific tolerance options
9308 $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {
9309
9310 if ( this.options.disabled || this.greedyChild || !this.visible ) {
9311 return;
9312 }
9313
9314 var parentInstance, scope, parent,
9315 intersects = $.ui.intersect( draggable, this, this.options.tolerance, event ),
9316 c = !intersects && this.isover ? "isout" : ( intersects && !this.isover ? "isover" : null );
9317 if ( !c ) {
9318 return;
9319 }
9320
9321 if ( this.options.greedy ) {
9322 // find droppable parents with same scope
9323 scope = this.options.scope;
9324 parent = this.element.parents( ":data(ui-droppable)" ).filter(function() {
9325 return $( this ).droppable( "instance" ).options.scope === scope;
9326 });
9327
9328 if ( parent.length ) {
9329 parentInstance = $( parent[ 0 ] ).droppable( "instance" );
9330 parentInstance.greedyChild = ( c === "isover" );
9331 }
9332 }
9333
9334 // we just moved into a greedy child
9335 if ( parentInstance && c === "isover" ) {
9336 parentInstance.isover = false;
9337 parentInstance.isout = true;
9338 parentInstance._out.call( parentInstance, event );
9339 }
9340
9341 this[ c ] = true;
9342 this[c === "isout" ? "isover" : "isout"] = false;
9343 this[c === "isover" ? "_over" : "_out"].call( this, event );
9344
9345 // we just moved out of a greedy child
9346 if ( parentInstance && c === "isout" ) {
9347 parentInstance.isout = false;
9348 parentInstance.isover = true;
9349 parentInstance._over.call( parentInstance, event );
9350 }
9351 });
9352
9353 },
9354 dragStop: function( draggable, event ) {
9355 draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
9356 // Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
9357 if ( !draggable.options.refreshPositions ) {
9358 $.ui.ddmanager.prepareOffsets( draggable, event );
9359 }
9360 }
9361 };
9362
9363 var droppable = $.ui.droppable;
9364
9365
9366 /*!
9367 * jQuery UI Effects 1.11.3
9368 * http://jqueryui.com
9369 *
9370 * Copyright jQuery Foundation and other contributors
9371 * Released under the MIT license.
9372 * http://jquery.org/license
9373 *
9374 * http://api.jqueryui.com/category/effects-core/
9375 */
9376
9377
9378 var dataSpace = "ui-effects-",
9379
9380 // Create a local jQuery because jQuery Color relies on it and the
9381 // global may not exist with AMD and a custom build (#10199)
9382 jQuery = $;
9383
9384 $.effects = {
9385 effect: {}
9386 };
9387
9388 /*!
9389 * jQuery Color Animations v2.1.2
9390 * https://github.com/jquery/jquery-color
9391 *
9392 * Copyright 2014 jQuery Foundation and other contributors
9393 * Released under the MIT license.
9394 * http://jquery.org/license
9395 *
9396 * Date: Wed Jan 16 08:47:09 2013 -0600
9397 */
9398 (function( jQuery, undefined ) {
9399
9400 var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
9401
9402 // plusequals test for += 100 -= 100
9403 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
9404 // a set of RE's that can match strings and generate color tuples.
9405 stringParsers = [ {
9406 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
9407 parse: function( execResult ) {
9408 return [
9409 execResult[ 1 ],
9410 execResult[ 2 ],
9411 execResult[ 3 ],
9412 execResult[ 4 ]
9413 ];
9414 }
9415 }, {
9416 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
9417 parse: function( execResult ) {
9418 return [
9419 execResult[ 1 ] * 2.55,
9420 execResult[ 2 ] * 2.55,
9421 execResult[ 3 ] * 2.55,
9422 execResult[ 4 ]
9423 ];
9424 }
9425 }, {
9426 // this regex ignores A-F because it's compared against an already lowercased string
9427 re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
9428 parse: function( execResult ) {
9429 return [
9430 parseInt( execResult[ 1 ], 16 ),
9431 parseInt( execResult[ 2 ], 16 ),
9432 parseInt( execResult[ 3 ], 16 )
9433 ];
9434 }
9435 }, {
9436 // this regex ignores A-F because it's compared against an already lowercased string
9437 re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
9438 parse: function( execResult ) {
9439 return [
9440 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
9441 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
9442 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
9443 ];
9444 }
9445 }, {
9446 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
9447 space: "hsla",
9448 parse: function( execResult ) {
9449 return [
9450 execResult[ 1 ],
9451 execResult[ 2 ] / 100,
9452 execResult[ 3 ] / 100,
9453 execResult[ 4 ]
9454 ];
9455 }
9456 } ],
9457
9458 // jQuery.Color( )
9459 color = jQuery.Color = function( color, green, blue, alpha ) {
9460 return new jQuery.Color.fn.parse( color, green, blue, alpha );
9461 },
9462 spaces = {
9463 rgba: {
9464 props: {
9465 red: {
9466 idx: 0,
9467 type: "byte"
9468 },
9469 green: {
9470 idx: 1,
9471 type: "byte"
9472 },
9473 blue: {
9474 idx: 2,
9475 type: "byte"
9476 }
9477 }
9478 },
9479
9480 hsla: {
9481 props: {
9482 hue: {
9483 idx: 0,
9484 type: "degrees"
9485 },
9486 saturation: {
9487 idx: 1,
9488 type: "percent"
9489 },
9490 lightness: {
9491 idx: 2,
9492 type: "percent"
9493 }
9494 }
9495 }
9496 },
9497 propTypes = {
9498 "byte": {
9499 floor: true,
9500 max: 255
9501 },
9502 "percent": {
9503 max: 1
9504 },
9505 "degrees": {
9506 mod: 360,
9507 floor: true
9508 }
9509 },
9510 support = color.support = {},
9511
9512 // element for support tests
9513 supportElem = jQuery( "<p>" )[ 0 ],
9514
9515 // colors = jQuery.Color.names
9516 colors,
9517
9518 // local aliases of functions called often
9519 each = jQuery.each;
9520
9521 // determine rgba support immediately
9522 supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
9523 support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
9524
9525 // define cache name and alpha properties
9526 // for rgba and hsla spaces
9527 each( spaces, function( spaceName, space ) {
9528 space.cache = "_" + spaceName;
9529 space.props.alpha = {
9530 idx: 3,
9531 type: "percent",
9532 def: 1
9533 };
9534 });
9535
9536 function clamp( value, prop, allowEmpty ) {
9537 var type = propTypes[ prop.type ] || {};
9538
9539 if ( value == null ) {
9540 return (allowEmpty || !prop.def) ? null : prop.def;
9541 }
9542
9543 // ~~ is an short way of doing floor for positive numbers
9544 value = type.floor ? ~~value : parseFloat( value );
9545
9546 // IE will pass in empty strings as value for alpha,
9547 // which will hit this case
9548 if ( isNaN( value ) ) {
9549 return prop.def;
9550 }
9551
9552 if ( type.mod ) {
9553 // we add mod before modding to make sure that negatives values
9554 // get converted properly: -10 -> 350
9555 return (value + type.mod) % type.mod;
9556 }
9557
9558 // for now all property types without mod have min and max
9559 return 0 > value ? 0 : type.max < value ? type.max : value;
9560 }
9561
9562 function stringParse( string ) {
9563 var inst = color(),
9564 rgba = inst._rgba = [];
9565
9566 string = string.toLowerCase();
9567
9568 each( stringParsers, function( i, parser ) {
9569 var parsed,
9570 match = parser.re.exec( string ),
9571 values = match && parser.parse( match ),
9572 spaceName = parser.space || "rgba";
9573
9574 if ( values ) {
9575 parsed = inst[ spaceName ]( values );
9576
9577 // if this was an rgba parse the assignment might happen twice
9578 // oh well....
9579 inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
9580 rgba = inst._rgba = parsed._rgba;
9581
9582 // exit each( stringParsers ) here because we matched
9583 return false;
9584 }
9585 });
9586
9587 // Found a stringParser that handled it
9588 if ( rgba.length ) {
9589
9590 // if this came from a parsed string, force "transparent" when alpha is 0
9591 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
9592 if ( rgba.join() === "0,0,0,0" ) {
9593 jQuery.extend( rgba, colors.transparent );
9594 }
9595 return inst;
9596 }
9597
9598 // named colors
9599 return colors[ string ];
9600 }
9601
9602 color.fn = jQuery.extend( color.prototype, {
9603 parse: function( red, green, blue, alpha ) {
9604 if ( red === undefined ) {
9605 this._rgba = [ null, null, null, null ];
9606 return this;
9607 }
9608 if ( red.jquery || red.nodeType ) {
9609 red = jQuery( red ).css( green );
9610 green = undefined;
9611 }
9612
9613 var inst = this,
9614 type = jQuery.type( red ),
9615 rgba = this._rgba = [];
9616
9617 // more than 1 argument specified - assume ( red, green, blue, alpha )
9618 if ( green !== undefined ) {
9619 red = [ red, green, blue, alpha ];
9620 type = "array";
9621 }
9622
9623 if ( type === "string" ) {
9624 return this.parse( stringParse( red ) || colors._default );
9625 }
9626
9627 if ( type === "array" ) {
9628 each( spaces.rgba.props, function( key, prop ) {
9629 rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
9630 });
9631 return this;
9632 }
9633
9634 if ( type === "object" ) {
9635 if ( red instanceof color ) {
9636 each( spaces, function( spaceName, space ) {
9637 if ( red[ space.cache ] ) {
9638 inst[ space.cache ] = red[ space.cache ].slice();
9639 }
9640 });
9641 } else {
9642 each( spaces, function( spaceName, space ) {
9643 var cache = space.cache;
9644 each( space.props, function( key, prop ) {
9645
9646 // if the cache doesn't exist, and we know how to convert
9647 if ( !inst[ cache ] && space.to ) {
9648
9649 // if the value was null, we don't need to copy it
9650 // if the key was alpha, we don't need to copy it either
9651 if ( key === "alpha" || red[ key ] == null ) {
9652 return;
9653 }
9654 inst[ cache ] = space.to( inst._rgba );
9655 }
9656
9657 // this is the only case where we allow nulls for ALL properties.
9658 // call clamp with alwaysAllowEmpty
9659 inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
9660 });
9661
9662 // everything defined but alpha?
9663 if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
9664 // use the default of 1
9665 inst[ cache ][ 3 ] = 1;
9666 if ( space.from ) {
9667 inst._rgba = space.from( inst[ cache ] );
9668 }
9669 }
9670 });
9671 }
9672 return this;
9673 }
9674 },
9675 is: function( compare ) {
9676 var is = color( compare ),
9677 same = true,
9678 inst = this;
9679
9680 each( spaces, function( _, space ) {
9681 var localCache,
9682 isCache = is[ space.cache ];
9683 if (isCache) {
9684 localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
9685 each( space.props, function( _, prop ) {
9686 if ( isCache[ prop.idx ] != null ) {
9687 same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
9688 return same;
9689 }
9690 });
9691 }
9692 return same;
9693 });
9694 return same;
9695 },
9696 _space: function() {
9697 var used = [],
9698 inst = this;
9699 each( spaces, function( spaceName, space ) {
9700 if ( inst[ space.cache ] ) {
9701 used.push( spaceName );
9702 }
9703 });
9704 return used.pop();
9705 },
9706 transition: function( other, distance ) {
9707 var end = color( other ),
9708 spaceName = end._space(),
9709 space = spaces[ spaceName ],
9710 startColor = this.alpha() === 0 ? color( "transparent" ) : this,
9711 start = startColor[ space.cache ] || space.to( startColor._rgba ),
9712 result = start.slice();
9713
9714 end = end[ space.cache ];
9715 each( space.props, function( key, prop ) {
9716 var index = prop.idx,
9717 startValue = start[ index ],
9718 endValue = end[ index ],
9719 type = propTypes[ prop.type ] || {};
9720
9721 // if null, don't override start value
9722 if ( endValue === null ) {
9723 return;
9724 }
9725 // if null - use end
9726 if ( startValue === null ) {
9727 result[ index ] = endValue;
9728 } else {
9729 if ( type.mod ) {
9730 if ( endValue - startValue > type.mod / 2 ) {
9731 startValue += type.mod;
9732 } else if ( startValue - endValue > type.mod / 2 ) {
9733 startValue -= type.mod;
9734 }
9735 }
9736 result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
9737 }
9738 });
9739 return this[ spaceName ]( result );
9740 },
9741 blend: function( opaque ) {
9742 // if we are already opaque - return ourself
9743 if ( this._rgba[ 3 ] === 1 ) {
9744 return this;
9745 }
9746
9747 var rgb = this._rgba.slice(),
9748 a = rgb.pop(),
9749 blend = color( opaque )._rgba;
9750
9751 return color( jQuery.map( rgb, function( v, i ) {
9752 return ( 1 - a ) * blend[ i ] + a * v;
9753 }));
9754 },
9755 toRgbaString: function() {
9756 var prefix = "rgba(",
9757 rgba = jQuery.map( this._rgba, function( v, i ) {
9758 return v == null ? ( i > 2 ? 1 : 0 ) : v;
9759 });
9760
9761 if ( rgba[ 3 ] === 1 ) {
9762 rgba.pop();
9763 prefix = "rgb(";
9764 }
9765
9766 return prefix + rgba.join() + ")";
9767 },
9768 toHslaString: function() {
9769 var prefix = "hsla(",
9770 hsla = jQuery.map( this.hsla(), function( v, i ) {
9771 if ( v == null ) {
9772 v = i > 2 ? 1 : 0;
9773 }
9774
9775 // catch 1 and 2
9776 if ( i && i < 3 ) {
9777 v = Math.round( v * 100 ) + "%";
9778 }
9779 return v;
9780 });
9781
9782 if ( hsla[ 3 ] === 1 ) {
9783 hsla.pop();
9784 prefix = "hsl(";
9785 }
9786 return prefix + hsla.join() + ")";
9787 },
9788 toHexString: function( includeAlpha ) {
9789 var rgba = this._rgba.slice(),
9790 alpha = rgba.pop();
9791
9792 if ( includeAlpha ) {
9793 rgba.push( ~~( alpha * 255 ) );
9794 }
9795
9796 return "#" + jQuery.map( rgba, function( v ) {
9797
9798 // default to 0 when nulls exist
9799 v = ( v || 0 ).toString( 16 );
9800 return v.length === 1 ? "0" + v : v;
9801 }).join("");
9802 },
9803 toString: function() {
9804 return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
9805 }
9806 });
9807 color.fn.parse.prototype = color.fn;
9808
9809 // hsla conversions adapted from:
9810 // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
9811
9812 function hue2rgb( p, q, h ) {
9813 h = ( h + 1 ) % 1;
9814 if ( h * 6 < 1 ) {
9815 return p + ( q - p ) * h * 6;
9816 }
9817 if ( h * 2 < 1) {
9818 return q;
9819 }
9820 if ( h * 3 < 2 ) {
9821 return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6;
9822 }
9823 return p;
9824 }
9825
9826 spaces.hsla.to = function( rgba ) {
9827 if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
9828 return [ null, null, null, rgba[ 3 ] ];
9829 }
9830 var r = rgba[ 0 ] / 255,
9831 g = rgba[ 1 ] / 255,
9832 b = rgba[ 2 ] / 255,
9833 a = rgba[ 3 ],
9834 max = Math.max( r, g, b ),
9835 min = Math.min( r, g, b ),
9836 diff = max - min,
9837 add = max + min,
9838 l = add * 0.5,
9839 h, s;
9840
9841 if ( min === max ) {
9842 h = 0;
9843 } else if ( r === max ) {
9844 h = ( 60 * ( g - b ) / diff ) + 360;
9845 } else if ( g === max ) {
9846 h = ( 60 * ( b - r ) / diff ) + 120;
9847 } else {
9848 h = ( 60 * ( r - g ) / diff ) + 240;
9849 }
9850
9851 // chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
9852 // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
9853 if ( diff === 0 ) {
9854 s = 0;
9855 } else if ( l <= 0.5 ) {
9856 s = diff / add;
9857 } else {
9858 s = diff / ( 2 - add );
9859 }
9860 return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
9861 };
9862
9863 spaces.hsla.from = function( hsla ) {
9864 if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
9865 return [ null, null, null, hsla[ 3 ] ];
9866 }
9867 var h = hsla[ 0 ] / 360,
9868 s = hsla[ 1 ],
9869 l = hsla[ 2 ],
9870 a = hsla[ 3 ],
9871 q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
9872 p = 2 * l - q;
9873
9874 return [
9875 Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
9876 Math.round( hue2rgb( p, q, h ) * 255 ),
9877 Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
9878 a
9879 ];
9880 };
9881
9882 each( spaces, function( spaceName, space ) {
9883 var props = space.props,
9884 cache = space.cache,
9885 to = space.to,
9886 from = space.from;
9887
9888 // makes rgba() and hsla()
9889 color.fn[ spaceName ] = function( value ) {
9890
9891 // generate a cache for this space if it doesn't exist
9892 if ( to && !this[ cache ] ) {
9893 this[ cache ] = to( this._rgba );
9894 }
9895 if ( value === undefined ) {
9896 return this[ cache ].slice();
9897 }
9898
9899 var ret,
9900 type = jQuery.type( value ),
9901 arr = ( type === "array" || type === "object" ) ? value : arguments,
9902 local = this[ cache ].slice();
9903
9904 each( props, function( key, prop ) {
9905 var val = arr[ type === "object" ? key : prop.idx ];
9906 if ( val == null ) {
9907 val = local[ prop.idx ];
9908 }
9909 local[ prop.idx ] = clamp( val, prop );
9910 });
9911
9912 if ( from ) {
9913 ret = color( from( local ) );
9914 ret[ cache ] = local;
9915 return ret;
9916 } else {
9917 return color( local );
9918 }
9919 };
9920
9921 // makes red() green() blue() alpha() hue() saturation() lightness()
9922 each( props, function( key, prop ) {
9923 // alpha is included in more than one space
9924 if ( color.fn[ key ] ) {
9925 return;
9926 }
9927 color.fn[ key ] = function( value ) {
9928 var vtype = jQuery.type( value ),
9929 fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
9930 local = this[ fn ](),
9931 cur = local[ prop.idx ],
9932 match;
9933
9934 if ( vtype === "undefined" ) {
9935 return cur;
9936 }
9937
9938 if ( vtype === "function" ) {
9939 value = value.call( this, cur );
9940 vtype = jQuery.type( value );
9941 }
9942 if ( value == null && prop.empty ) {
9943 return this;
9944 }
9945 if ( vtype === "string" ) {
9946 match = rplusequals.exec( value );
9947 if ( match ) {
9948 value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
9949 }
9950 }
9951 local[ prop.idx ] = value;
9952 return this[ fn ]( local );
9953 };
9954 });
9955 });
9956
9957 // add cssHook and .fx.step function for each named hook.
9958 // accept a space separated string of properties
9959 color.hook = function( hook ) {
9960 var hooks = hook.split( " " );
9961 each( hooks, function( i, hook ) {
9962 jQuery.cssHooks[ hook ] = {
9963 set: function( elem, value ) {
9964 var parsed, curElem,
9965 backgroundColor = "";
9966
9967 if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
9968 value = color( parsed || value );
9969 if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
9970 curElem = hook === "backgroundColor" ? elem.parentNode : elem;
9971 while (
9972 (backgroundColor === "" || backgroundColor === "transparent") &&
9973 curElem && curElem.style
9974 ) {
9975 try {
9976 backgroundColor = jQuery.css( curElem, "backgroundColor" );
9977 curElem = curElem.parentNode;
9978 } catch ( e ) {
9979 }
9980 }
9981
9982 value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
9983 backgroundColor :
9984 "_default" );
9985 }
9986
9987 value = value.toRgbaString();
9988 }
9989 try {
9990 elem.style[ hook ] = value;
9991 } catch ( e ) {
9992 // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
9993 }
9994 }
9995 };
9996 jQuery.fx.step[ hook ] = function( fx ) {
9997 if ( !fx.colorInit ) {
9998 fx.start = color( fx.elem, hook );
9999 fx.end = color( fx.end );
10000 fx.colorInit = true;
10001 }
10002 jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
10003 };
10004 });
10005
10006 };
10007
10008 color.hook( stepHooks );
10009
10010 jQuery.cssHooks.borderColor = {
10011 expand: function( value ) {
10012 var expanded = {};
10013
10014 each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
10015 expanded[ "border" + part + "Color" ] = value;
10016 });
10017 return expanded;
10018 }
10019 };
10020
10021 // Basic color names only.
10022 // Usage of any of the other color names requires adding yourself or including
10023 // jquery.color.svg-names.js.
10024 colors = jQuery.Color.names = {
10025 // 4.1. Basic color keywords
10026 aqua: "#00ffff",
10027 black: "#000000",
10028 blue: "#0000ff",
10029 fuchsia: "#ff00ff",
10030 gray: "#808080",
10031 green: "#008000",
10032 lime: "#00ff00",
10033 maroon: "#800000",
10034 navy: "#000080",
10035 olive: "#808000",
10036 purple: "#800080",
10037 red: "#ff0000",
10038 silver: "#c0c0c0",
10039 teal: "#008080",
10040 white: "#ffffff",
10041 yellow: "#ffff00",
10042
10043 // 4.2.3. "transparent" color keyword
10044 transparent: [ null, null, null, 0 ],
10045
10046 _default: "#ffffff"
10047 };
10048
10049 })( jQuery );
10050
10051 /******************************************************************************/
10052 /****************************** CLASS ANIMATIONS ******************************/
10053 /******************************************************************************/
10054 (function() {
10055
10056 var classAnimationActions = [ "add", "remove", "toggle" ],
10057 shorthandStyles = {
10058 border: 1,
10059 borderBottom: 1,
10060 borderColor: 1,
10061 borderLeft: 1,
10062 borderRight: 1,
10063 borderTop: 1,
10064 borderWidth: 1,
10065 margin: 1,
10066 padding: 1
10067 };
10068
10069 $.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) {
10070 $.fx.step[ prop ] = function( fx ) {
10071 if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
10072 jQuery.style( fx.elem, prop, fx.end );
10073 fx.setAttr = true;
10074 }
10075 };
10076 });
10077
10078 function getElementStyles( elem ) {
10079 var key, len,
10080 style = elem.ownerDocument.defaultView ?
10081 elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
10082 elem.currentStyle,
10083 styles = {};
10084
10085 if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
10086 len = style.length;
10087 while ( len-- ) {
10088 key = style[ len ];
10089 if ( typeof style[ key ] === "string" ) {
10090 styles[ $.camelCase( key ) ] = style[ key ];
10091 }
10092 }
10093 // support: Opera, IE <9
10094 } else {
10095 for ( key in style ) {
10096 if ( typeof style[ key ] === "string" ) {
10097 styles[ key ] = style[ key ];
10098 }
10099 }
10100 }
10101
10102 return styles;
10103 }
10104
10105 function styleDifference( oldStyle, newStyle ) {
10106 var diff = {},
10107 name, value;
10108
10109 for ( name in newStyle ) {
10110 value = newStyle[ name ];
10111 if ( oldStyle[ name ] !== value ) {
10112 if ( !shorthandStyles[ name ] ) {
10113 if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
10114 diff[ name ] = value;
10115 }
10116 }
10117 }
10118 }
10119
10120 return diff;
10121 }
10122
10123 // support: jQuery <1.8
10124 if ( !$.fn.addBack ) {
10125 $.fn.addBack = function( selector ) {
10126 return this.add( selector == null ?
10127 this.prevObject : this.prevObject.filter( selector )
10128 );
10129 };
10130 }
10131
10132 $.effects.animateClass = function( value, duration, easing, callback ) {
10133 var o = $.speed( duration, easing, callback );
10134
10135 return this.queue( function() {
10136 var animated = $( this ),
10137 baseClass = animated.attr( "class" ) || "",
10138 applyClassChange,
10139 allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
10140
10141 // map the animated objects to store the original styles.
10142 allAnimations = allAnimations.map(function() {
10143 var el = $( this );
10144 return {
10145 el: el,
10146 start: getElementStyles( this )
10147 };
10148 });
10149
10150 // apply class change
10151 applyClassChange = function() {
10152 $.each( classAnimationActions, function(i, action) {
10153 if ( value[ action ] ) {
10154 animated[ action + "Class" ]( value[ action ] );
10155 }
10156 });
10157 };
10158 applyClassChange();
10159
10160 // map all animated objects again - calculate new styles and diff
10161 allAnimations = allAnimations.map(function() {
10162 this.end = getElementStyles( this.el[ 0 ] );
10163 this.diff = styleDifference( this.start, this.end );
10164 return this;
10165 });
10166
10167 // apply original class
10168 animated.attr( "class", baseClass );
10169
10170 // map all animated objects again - this time collecting a promise
10171 allAnimations = allAnimations.map(function() {
10172 var styleInfo = this,
10173 dfd = $.Deferred(),
10174 opts = $.extend({}, o, {
10175 queue: false,
10176 complete: function() {
10177 dfd.resolve( styleInfo );
10178 }
10179 });
10180
10181 this.el.animate( this.diff, opts );
10182 return dfd.promise();
10183 });
10184
10185 // once all animations have completed:
10186 $.when.apply( $, allAnimations.get() ).done(function() {
10187
10188 // set the final class
10189 applyClassChange();
10190
10191 // for each animated element,
10192 // clear all css properties that were animated
10193 $.each( arguments, function() {
10194 var el = this.el;
10195 $.each( this.diff, function(key) {
10196 el.css( key, "" );
10197 });
10198 });
10199
10200 // this is guarnteed to be there if you use jQuery.speed()
10201 // it also handles dequeuing the next anim...
10202 o.complete.call( animated[ 0 ] );
10203 });
10204 });
10205 };
10206
10207 $.fn.extend({
10208 addClass: (function( orig ) {
10209 return function( classNames, speed, easing, callback ) {
10210 return speed ?
10211 $.effects.animateClass.call( this,
10212 { add: classNames }, speed, easing, callback ) :
10213 orig.apply( this, arguments );
10214 };
10215 })( $.fn.addClass ),
10216
10217 removeClass: (function( orig ) {
10218 return function( classNames, speed, easing, callback ) {
10219 return arguments.length > 1 ?
10220 $.effects.animateClass.call( this,
10221 { remove: classNames }, speed, easing, callback ) :
10222 orig.apply( this, arguments );
10223 };
10224 })( $.fn.removeClass ),
10225
10226 toggleClass: (function( orig ) {
10227 return function( classNames, force, speed, easing, callback ) {
10228 if ( typeof force === "boolean" || force === undefined ) {
10229 if ( !speed ) {
10230 // without speed parameter
10231 return orig.apply( this, arguments );
10232 } else {
10233 return $.effects.animateClass.call( this,
10234 (force ? { add: classNames } : { remove: classNames }),
10235 speed, easing, callback );
10236 }
10237 } else {
10238 // without force parameter
10239 return $.effects.animateClass.call( this,
10240 { toggle: classNames }, force, speed, easing );
10241 }
10242 };
10243 })( $.fn.toggleClass ),
10244
10245 switchClass: function( remove, add, speed, easing, callback) {
10246 return $.effects.animateClass.call( this, {
10247 add: add,
10248 remove: remove
10249 }, speed, easing, callback );
10250 }
10251 });
10252
10253 })();
10254
10255 /******************************************************************************/
10256 /*********************************** EFFECTS **********************************/
10257 /******************************************************************************/
10258
10259 (function() {
10260
10261 $.extend( $.effects, {
10262 version: "1.11.3",
10263
10264 // Saves a set of properties in a data storage
10265 save: function( element, set ) {
10266 for ( var i = 0; i < set.length; i++ ) {
10267 if ( set[ i ] !== null ) {
10268 element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
10269 }
10270 }
10271 },
10272
10273 // Restores a set of previously saved properties from a data storage
10274 restore: function( element, set ) {
10275 var val, i;
10276 for ( i = 0; i < set.length; i++ ) {
10277 if ( set[ i ] !== null ) {
10278 val = element.data( dataSpace + set[ i ] );
10279 // support: jQuery 1.6.2
10280 // http://bugs.jquery.com/ticket/9917
10281 // jQuery 1.6.2 incorrectly returns undefined for any falsy value.
10282 // We can't differentiate between "" and 0 here, so we just assume
10283 // empty string since it's likely to be a more common value...
10284 if ( val === undefined ) {
10285 val = "";
10286 }
10287 element.css( set[ i ], val );
10288 }
10289 }
10290 },
10291
10292 setMode: function( el, mode ) {
10293 if (mode === "toggle") {
10294 mode = el.is( ":hidden" ) ? "show" : "hide";
10295 }
10296 return mode;
10297 },
10298
10299 // Translates a [top,left] array into a baseline value
10300 // this should be a little more flexible in the future to handle a string & hash
10301 getBaseline: function( origin, original ) {
10302 var y, x;
10303 switch ( origin[ 0 ] ) {
10304 case "top": y = 0; break;
10305 case "middle": y = 0.5; break;
10306 case "bottom": y = 1; break;
10307 default: y = origin[ 0 ] / original.height;
10308 }
10309 switch ( origin[ 1 ] ) {
10310 case "left": x = 0; break;
10311 case "center": x = 0.5; break;
10312 case "right": x = 1; break;
10313 default: x = origin[ 1 ] / original.width;
10314 }
10315 return {
10316 x: x,
10317 y: y
10318 };
10319 },
10320
10321 // Wraps the element around a wrapper that copies position properties
10322 createWrapper: function( element ) {
10323
10324 // if the element is already wrapped, return it
10325 if ( element.parent().is( ".ui-effects-wrapper" )) {
10326 return element.parent();
10327 }
10328
10329 // wrap the element
10330 var props = {
10331 width: element.outerWidth(true),
10332 height: element.outerHeight(true),
10333 "float": element.css( "float" )
10334 },
10335 wrapper = $( "<div></div>" )
10336 .addClass( "ui-effects-wrapper" )
10337 .css({
10338 fontSize: "100%",
10339 background: "transparent",
10340 border: "none",
10341 margin: 0,
10342 padding: 0
10343 }),
10344 // Store the size in case width/height are defined in % - Fixes #5245
10345 size = {
10346 width: element.width(),
10347 height: element.height()
10348 },
10349 active = document.activeElement;
10350
10351 // support: Firefox
10352 // Firefox incorrectly exposes anonymous content
10353 // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
10354 try {
10355 active.id;
10356 } catch ( e ) {
10357 active = document.body;
10358 }
10359
10360 element.wrap( wrapper );
10361
10362 // Fixes #7595 - Elements lose focus when wrapped.
10363 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
10364 $( active ).focus();
10365 }
10366
10367 wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element
10368
10369 // transfer positioning properties to the wrapper
10370 if ( element.css( "position" ) === "static" ) {
10371 wrapper.css({ position: "relative" });
10372 element.css({ position: "relative" });
10373 } else {
10374 $.extend( props, {
10375 position: element.css( "position" ),
10376 zIndex: element.css( "z-index" )
10377 });
10378 $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
10379 props[ pos ] = element.css( pos );
10380 if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
10381 props[ pos ] = "auto";
10382 }
10383 });
10384 element.css({
10385 position: "relative",
10386 top: 0,
10387 left: 0,
10388 right: "auto",
10389 bottom: "auto"
10390 });
10391 }
10392 element.css(size);
10393
10394 return wrapper.css( props ).show();
10395 },
10396
10397 removeWrapper: function( element ) {
10398 var active = document.activeElement;
10399
10400 if ( element.parent().is( ".ui-effects-wrapper" ) ) {
10401 element.parent().replaceWith( element );
10402
10403 // Fixes #7595 - Elements lose focus when wrapped.
10404 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
10405 $( active ).focus();
10406 }
10407 }
10408
10409 return element;
10410 },
10411
10412 setTransition: function( element, list, factor, value ) {
10413 value = value || {};
10414 $.each( list, function( i, x ) {
10415 var unit = element.cssUnit( x );
10416 if ( unit[ 0 ] > 0 ) {
10417 value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
10418 }
10419 });
10420 return value;
10421 }
10422 });
10423
10424 // return an effect options object for the given parameters:
10425 function _normalizeArguments( effect, options, speed, callback ) {
10426
10427 // allow passing all options as the first parameter
10428 if ( $.isPlainObject( effect ) ) {
10429 options = effect;
10430 effect = effect.effect;
10431 }
10432
10433 // convert to an object
10434 effect = { effect: effect };
10435
10436 // catch (effect, null, ...)
10437 if ( options == null ) {
10438 options = {};
10439 }
10440
10441 // catch (effect, callback)
10442 if ( $.isFunction( options ) ) {
10443 callback = options;
10444 speed = null;
10445 options = {};
10446 }
10447
10448 // catch (effect, speed, ?)
10449 if ( typeof options === "number" || $.fx.speeds[ options ] ) {
10450 callback = speed;
10451 speed = options;
10452 options = {};
10453 }
10454
10455 // catch (effect, options, callback)
10456 if ( $.isFunction( speed ) ) {
10457 callback = speed;
10458 speed = null;
10459 }
10460
10461 // add options to effect
10462 if ( options ) {
10463 $.extend( effect, options );
10464 }
10465
10466 speed = speed || options.duration;
10467 effect.duration = $.fx.off ? 0 :
10468 typeof speed === "number" ? speed :
10469 speed in $.fx.speeds ? $.fx.speeds[ speed ] :
10470 $.fx.speeds._default;
10471
10472 effect.complete = callback || options.complete;
10473
10474 return effect;
10475 }
10476
10477 function standardAnimationOption( option ) {
10478 // Valid standard speeds (nothing, number, named speed)
10479 if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
10480 return true;
10481 }
10482
10483 // Invalid strings - treat as "normal" speed
10484 if ( typeof option === "string" && !$.effects.effect[ option ] ) {
10485 return true;
10486 }
10487
10488 // Complete callback
10489 if ( $.isFunction( option ) ) {
10490 return true;
10491 }
10492
10493 // Options hash (but not naming an effect)
10494 if ( typeof option === "object" && !option.effect ) {
10495 return true;
10496 }
10497
10498 // Didn't match any standard API
10499 return false;
10500 }
10501
10502 $.fn.extend({
10503 effect: function( /* effect, options, speed, callback */ ) {
10504 var args = _normalizeArguments.apply( this, arguments ),
10505 mode = args.mode,
10506 queue = args.queue,
10507 effectMethod = $.effects.effect[ args.effect ];
10508
10509 if ( $.fx.off || !effectMethod ) {
10510 // delegate to the original method (e.g., .show()) if possible
10511 if ( mode ) {
10512 return this[ mode ]( args.duration, args.complete );
10513 } else {
10514 return this.each( function() {
10515 if ( args.complete ) {
10516 args.complete.call( this );
10517 }
10518 });
10519 }
10520 }
10521
10522 function run( next ) {
10523 var elem = $( this ),
10524 complete = args.complete,
10525 mode = args.mode;
10526
10527 function done() {
10528 if ( $.isFunction( complete ) ) {
10529 complete.call( elem[0] );
10530 }
10531 if ( $.isFunction( next ) ) {
10532 next();
10533 }
10534 }
10535
10536 // If the element already has the correct final state, delegate to
10537 // the core methods so the internal tracking of "olddisplay" works.
10538 if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
10539 elem[ mode ]();
10540 done();
10541 } else {
10542 effectMethod.call( elem[0], args, done );
10543 }
10544 }
10545
10546 return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
10547 },
10548
10549 show: (function( orig ) {
10550 return function( option ) {
10551 if ( standardAnimationOption( option ) ) {
10552 return orig.apply( this, arguments );
10553 } else {
10554 var args = _normalizeArguments.apply( this, arguments );
10555 args.mode = "show";
10556 return this.effect.call( this, args );
10557 }
10558 };
10559 })( $.fn.show ),
10560
10561 hide: (function( orig ) {
10562 return function( option ) {
10563 if ( standardAnimationOption( option ) ) {
10564 return orig.apply( this, arguments );
10565 } else {
10566 var args = _normalizeArguments.apply( this, arguments );
10567 args.mode = "hide";
10568 return this.effect.call( this, args );
10569 }
10570 };
10571 })( $.fn.hide ),
10572
10573 toggle: (function( orig ) {
10574 return function( option ) {
10575 if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
10576 return orig.apply( this, arguments );
10577 } else {
10578 var args = _normalizeArguments.apply( this, arguments );
10579 args.mode = "toggle";
10580 return this.effect.call( this, args );
10581 }
10582 };
10583 })( $.fn.toggle ),
10584
10585 // helper functions
10586 cssUnit: function(key) {
10587 var style = this.css( key ),
10588 val = [];
10589
10590 $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
10591 if ( style.indexOf( unit ) > 0 ) {
10592 val = [ parseFloat( style ), unit ];
10593 }
10594 });
10595 return val;
10596 }
10597 });
10598
10599 })();
10600
10601 /******************************************************************************/
10602 /*********************************** EASING ***********************************/
10603 /******************************************************************************/
10604
10605 (function() {
10606
10607 // based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
10608
10609 var baseEasings = {};
10610
10611 $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
10612 baseEasings[ name ] = function( p ) {
10613 return Math.pow( p, i + 2 );
10614 };
10615 });
10616
10617 $.extend( baseEasings, {
10618 Sine: function( p ) {
10619 return 1 - Math.cos( p * Math.PI / 2 );
10620 },
10621 Circ: function( p ) {
10622 return 1 - Math.sqrt( 1 - p * p );
10623 },
10624 Elastic: function( p ) {
10625 return p === 0 || p === 1 ? p :
10626 -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 );
10627 },
10628 Back: function( p ) {
10629 return p * p * ( 3 * p - 2 );
10630 },
10631 Bounce: function( p ) {
10632 var pow2,
10633 bounce = 4;
10634
10635 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
10636 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
10637 }
10638 });
10639
10640 $.each( baseEasings, function( name, easeIn ) {
10641 $.easing[ "easeIn" + name ] = easeIn;
10642 $.easing[ "easeOut" + name ] = function( p ) {
10643 return 1 - easeIn( 1 - p );
10644 };
10645 $.easing[ "easeInOut" + name ] = function( p ) {
10646 return p < 0.5 ?
10647 easeIn( p * 2 ) / 2 :
10648 1 - easeIn( p * -2 + 2 ) / 2;
10649 };
10650 });
10651
10652 })();
10653
10654 var effect = $.effects;
10655
10656
10657 /*!
10658 * jQuery UI Effects Blind 1.11.3
10659 * http://jqueryui.com
10660 *
10661 * Copyright jQuery Foundation and other contributors
10662 * Released under the MIT license.
10663 * http://jquery.org/license
10664 *
10665 * http://api.jqueryui.com/blind-effect/
10666 */
10667
10668
10669 var effectBlind = $.effects.effect.blind = function( o, done ) {
10670 // Create element
10671 var el = $( this ),
10672 rvertical = /up|down|vertical/,
10673 rpositivemotion = /up|left|vertical|horizontal/,
10674 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10675 mode = $.effects.setMode( el, o.mode || "hide" ),
10676 direction = o.direction || "up",
10677 vertical = rvertical.test( direction ),
10678 ref = vertical ? "height" : "width",
10679 ref2 = vertical ? "top" : "left",
10680 motion = rpositivemotion.test( direction ),
10681 animation = {},
10682 show = mode === "show",
10683 wrapper, distance, margin;
10684
10685 // if already wrapped, the wrapper's properties are my property. #6245
10686 if ( el.parent().is( ".ui-effects-wrapper" ) ) {
10687 $.effects.save( el.parent(), props );
10688 } else {
10689 $.effects.save( el, props );
10690 }
10691 el.show();
10692 wrapper = $.effects.createWrapper( el ).css({
10693 overflow: "hidden"
10694 });
10695
10696 distance = wrapper[ ref ]();
10697 margin = parseFloat( wrapper.css( ref2 ) ) || 0;
10698
10699 animation[ ref ] = show ? distance : 0;
10700 if ( !motion ) {
10701 el
10702 .css( vertical ? "bottom" : "right", 0 )
10703 .css( vertical ? "top" : "left", "auto" )
10704 .css({ position: "absolute" });
10705
10706 animation[ ref2 ] = show ? margin : distance + margin;
10707 }
10708
10709 // start at 0 if we are showing
10710 if ( show ) {
10711 wrapper.css( ref, 0 );
10712 if ( !motion ) {
10713 wrapper.css( ref2, margin + distance );
10714 }
10715 }
10716
10717 // Animate
10718 wrapper.animate( animation, {
10719 duration: o.duration,
10720 easing: o.easing,
10721 queue: false,
10722 complete: function() {
10723 if ( mode === "hide" ) {
10724 el.hide();
10725 }
10726 $.effects.restore( el, props );
10727 $.effects.removeWrapper( el );
10728 done();
10729 }
10730 });
10731 };
10732
10733
10734 /*!
10735 * jQuery UI Effects Bounce 1.11.3
10736 * http://jqueryui.com
10737 *
10738 * Copyright jQuery Foundation and other contributors
10739 * Released under the MIT license.
10740 * http://jquery.org/license
10741 *
10742 * http://api.jqueryui.com/bounce-effect/
10743 */
10744
10745
10746 var effectBounce = $.effects.effect.bounce = function( o, done ) {
10747 var el = $( this ),
10748 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10749
10750 // defaults:
10751 mode = $.effects.setMode( el, o.mode || "effect" ),
10752 hide = mode === "hide",
10753 show = mode === "show",
10754 direction = o.direction || "up",
10755 distance = o.distance,
10756 times = o.times || 5,
10757
10758 // number of internal animations
10759 anims = times * 2 + ( show || hide ? 1 : 0 ),
10760 speed = o.duration / anims,
10761 easing = o.easing,
10762
10763 // utility:
10764 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
10765 motion = ( direction === "up" || direction === "left" ),
10766 i,
10767 upAnim,
10768 downAnim,
10769
10770 // we will need to re-assemble the queue to stack our animations in place
10771 queue = el.queue(),
10772 queuelen = queue.length;
10773
10774 // Avoid touching opacity to prevent clearType and PNG issues in IE
10775 if ( show || hide ) {
10776 props.push( "opacity" );
10777 }
10778
10779 $.effects.save( el, props );
10780 el.show();
10781 $.effects.createWrapper( el ); // Create Wrapper
10782
10783 // default distance for the BIGGEST bounce is the outer Distance / 3
10784 if ( !distance ) {
10785 distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
10786 }
10787
10788 if ( show ) {
10789 downAnim = { opacity: 1 };
10790 downAnim[ ref ] = 0;
10791
10792 // if we are showing, force opacity 0 and set the initial position
10793 // then do the "first" animation
10794 el.css( "opacity", 0 )
10795 .css( ref, motion ? -distance * 2 : distance * 2 )
10796 .animate( downAnim, speed, easing );
10797 }
10798
10799 // start at the smallest distance if we are hiding
10800 if ( hide ) {
10801 distance = distance / Math.pow( 2, times - 1 );
10802 }
10803
10804 downAnim = {};
10805 downAnim[ ref ] = 0;
10806 // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
10807 for ( i = 0; i < times; i++ ) {
10808 upAnim = {};
10809 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
10810
10811 el.animate( upAnim, speed, easing )
10812 .animate( downAnim, speed, easing );
10813
10814 distance = hide ? distance * 2 : distance / 2;
10815 }
10816
10817 // Last Bounce when Hiding
10818 if ( hide ) {
10819 upAnim = { opacity: 0 };
10820 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
10821
10822 el.animate( upAnim, speed, easing );
10823 }
10824
10825 el.queue(function() {
10826 if ( hide ) {
10827 el.hide();
10828 }
10829 $.effects.restore( el, props );
10830 $.effects.removeWrapper( el );
10831 done();
10832 });
10833
10834 // inject all the animations we just queued to be first in line (after "inprogress")
10835 if ( queuelen > 1) {
10836 queue.splice.apply( queue,
10837 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
10838 }
10839 el.dequeue();
10840
10841 };
10842
10843
10844 /*!
10845 * jQuery UI Effects Clip 1.11.3
10846 * http://jqueryui.com
10847 *
10848 * Copyright jQuery Foundation and other contributors
10849 * Released under the MIT license.
10850 * http://jquery.org/license
10851 *
10852 * http://api.jqueryui.com/clip-effect/
10853 */
10854
10855
10856 var effectClip = $.effects.effect.clip = function( o, done ) {
10857 // Create element
10858 var el = $( this ),
10859 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10860 mode = $.effects.setMode( el, o.mode || "hide" ),
10861 show = mode === "show",
10862 direction = o.direction || "vertical",
10863 vert = direction === "vertical",
10864 size = vert ? "height" : "width",
10865 position = vert ? "top" : "left",
10866 animation = {},
10867 wrapper, animate, distance;
10868
10869 // Save & Show
10870 $.effects.save( el, props );
10871 el.show();
10872
10873 // Create Wrapper
10874 wrapper = $.effects.createWrapper( el ).css({
10875 overflow: "hidden"
10876 });
10877 animate = ( el[0].tagName === "IMG" ) ? wrapper : el;
10878 distance = animate[ size ]();
10879
10880 // Shift
10881 if ( show ) {
10882 animate.css( size, 0 );
10883 animate.css( position, distance / 2 );
10884 }
10885
10886 // Create Animation Object:
10887 animation[ size ] = show ? distance : 0;
10888 animation[ position ] = show ? 0 : distance / 2;
10889
10890 // Animate
10891 animate.animate( animation, {
10892 queue: false,
10893 duration: o.duration,
10894 easing: o.easing,
10895 complete: function() {
10896 if ( !show ) {
10897 el.hide();
10898 }
10899 $.effects.restore( el, props );
10900 $.effects.removeWrapper( el );
10901 done();
10902 }
10903 });
10904
10905 };
10906
10907
10908 /*!
10909 * jQuery UI Effects Drop 1.11.3
10910 * http://jqueryui.com
10911 *
10912 * Copyright jQuery Foundation and other contributors
10913 * Released under the MIT license.
10914 * http://jquery.org/license
10915 *
10916 * http://api.jqueryui.com/drop-effect/
10917 */
10918
10919
10920 var effectDrop = $.effects.effect.drop = function( o, done ) {
10921
10922 var el = $( this ),
10923 props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
10924 mode = $.effects.setMode( el, o.mode || "hide" ),
10925 show = mode === "show",
10926 direction = o.direction || "left",
10927 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
10928 motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
10929 animation = {
10930 opacity: show ? 1 : 0
10931 },
10932 distance;
10933
10934 // Adjust
10935 $.effects.save( el, props );
10936 el.show();
10937 $.effects.createWrapper( el );
10938
10939 distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2;
10940
10941 if ( show ) {
10942 el
10943 .css( "opacity", 0 )
10944 .css( ref, motion === "pos" ? -distance : distance );
10945 }
10946
10947 // Animation
10948 animation[ ref ] = ( show ?
10949 ( motion === "pos" ? "+=" : "-=" ) :
10950 ( motion === "pos" ? "-=" : "+=" ) ) +
10951 distance;
10952
10953 // Animate
10954 el.animate( animation, {
10955 queue: false,
10956 duration: o.duration,
10957 easing: o.easing,
10958 complete: function() {
10959 if ( mode === "hide" ) {
10960 el.hide();
10961 }
10962 $.effects.restore( el, props );
10963 $.effects.removeWrapper( el );
10964 done();
10965 }
10966 });
10967 };
10968
10969
10970 /*!
10971 * jQuery UI Effects Explode 1.11.3
10972 * http://jqueryui.com
10973 *
10974 * Copyright jQuery Foundation and other contributors
10975 * Released under the MIT license.
10976 * http://jquery.org/license
10977 *
10978 * http://api.jqueryui.com/explode-effect/
10979 */
10980
10981
10982 var effectExplode = $.effects.effect.explode = function( o, done ) {
10983
10984 var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3,
10985 cells = rows,
10986 el = $( this ),
10987 mode = $.effects.setMode( el, o.mode || "hide" ),
10988 show = mode === "show",
10989
10990 // show and then visibility:hidden the element before calculating offset
10991 offset = el.show().css( "visibility", "hidden" ).offset(),
10992
10993 // width and height of a piece
10994 width = Math.ceil( el.outerWidth() / cells ),
10995 height = Math.ceil( el.outerHeight() / rows ),
10996 pieces = [],
10997
10998 // loop
10999 i, j, left, top, mx, my;
11000
11001 // children animate complete:
11002 function childComplete() {
11003 pieces.push( this );
11004 if ( pieces.length === rows * cells ) {
11005 animComplete();
11006 }
11007 }
11008
11009 // clone the element for each row and cell.
11010 for ( i = 0; i < rows ; i++ ) { // ===>
11011 top = offset.top + i * height;
11012 my = i - ( rows - 1 ) / 2 ;
11013
11014 for ( j = 0; j < cells ; j++ ) { // |||
11015 left = offset.left + j * width;
11016 mx = j - ( cells - 1 ) / 2 ;
11017
11018 // Create a clone of the now hidden main element that will be absolute positioned
11019 // within a wrapper div off the -left and -top equal to size of our pieces
11020 el
11021 .clone()
11022 .appendTo( "body" )
11023 .wrap( "<div></div>" )
11024 .css({
11025 position: "absolute",
11026 visibility: "visible",
11027 left: -j * width,
11028 top: -i * height
11029 })
11030
11031 // select the wrapper - make it overflow: hidden and absolute positioned based on
11032 // where the original was located +left and +top equal to the size of pieces
11033 .parent()
11034 .addClass( "ui-effects-explode" )
11035 .css({
11036 position: "absolute",
11037 overflow: "hidden",
11038 width: width,
11039 height: height,
11040 left: left + ( show ? mx * width : 0 ),
11041 top: top + ( show ? my * height : 0 ),
11042 opacity: show ? 0 : 1
11043 }).animate({
11044 left: left + ( show ? 0 : mx * width ),
11045 top: top + ( show ? 0 : my * height ),
11046 opacity: show ? 1 : 0
11047 }, o.duration || 500, o.easing, childComplete );
11048 }
11049 }
11050
11051 function animComplete() {
11052 el.css({
11053 visibility: "visible"
11054 });
11055 $( pieces ).remove();
11056 if ( !show ) {
11057 el.hide();
11058 }
11059 done();
11060 }
11061 };
11062
11063
11064 /*!
11065 * jQuery UI Effects Fade 1.11.3
11066 * http://jqueryui.com
11067 *
11068 * Copyright jQuery Foundation and other contributors
11069 * Released under the MIT license.
11070 * http://jquery.org/license
11071 *
11072 * http://api.jqueryui.com/fade-effect/
11073 */
11074
11075
11076 var effectFade = $.effects.effect.fade = function( o, done ) {
11077 var el = $( this ),
11078 mode = $.effects.setMode( el, o.mode || "toggle" );
11079
11080 el.animate({
11081 opacity: mode
11082 }, {
11083 queue: false,
11084 duration: o.duration,
11085 easing: o.easing,
11086 complete: done
11087 });
11088 };
11089
11090
11091 /*!
11092 * jQuery UI Effects Fold 1.11.3
11093 * http://jqueryui.com
11094 *
11095 * Copyright jQuery Foundation and other contributors
11096 * Released under the MIT license.
11097 * http://jquery.org/license
11098 *
11099 * http://api.jqueryui.com/fold-effect/
11100 */
11101
11102
11103 var effectFold = $.effects.effect.fold = function( o, done ) {
11104
11105 // Create element
11106 var el = $( this ),
11107 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
11108 mode = $.effects.setMode( el, o.mode || "hide" ),
11109 show = mode === "show",
11110 hide = mode === "hide",
11111 size = o.size || 15,
11112 percent = /([0-9]+)%/.exec( size ),
11113 horizFirst = !!o.horizFirst,
11114 widthFirst = show !== horizFirst,
11115 ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ],
11116 duration = o.duration / 2,
11117 wrapper, distance,
11118 animation1 = {},
11119 animation2 = {};
11120
11121 $.effects.save( el, props );
11122 el.show();
11123
11124 // Create Wrapper
11125 wrapper = $.effects.createWrapper( el ).css({
11126 overflow: "hidden"
11127 });
11128 distance = widthFirst ?
11129 [ wrapper.width(), wrapper.height() ] :
11130 [ wrapper.height(), wrapper.width() ];
11131
11132 if ( percent ) {
11133 size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
11134 }
11135 if ( show ) {
11136 wrapper.css( horizFirst ? {
11137 height: 0,
11138 width: size
11139 } : {
11140 height: size,
11141 width: 0
11142 });
11143 }
11144
11145 // Animation
11146 animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size;
11147 animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0;
11148
11149 // Animate
11150 wrapper
11151 .animate( animation1, duration, o.easing )
11152 .animate( animation2, duration, o.easing, function() {
11153 if ( hide ) {
11154 el.hide();
11155 }
11156 $.effects.restore( el, props );
11157 $.effects.removeWrapper( el );
11158 done();
11159 });
11160
11161 };
11162
11163
11164 /*!
11165 * jQuery UI Effects Highlight 1.11.3
11166 * http://jqueryui.com
11167 *
11168 * Copyright jQuery Foundation and other contributors
11169 * Released under the MIT license.
11170 * http://jquery.org/license
11171 *
11172 * http://api.jqueryui.com/highlight-effect/
11173 */
11174
11175
11176 var effectHighlight = $.effects.effect.highlight = function( o, done ) {
11177 var elem = $( this ),
11178 props = [ "backgroundImage", "backgroundColor", "opacity" ],
11179 mode = $.effects.setMode( elem, o.mode || "show" ),
11180 animation = {
11181 backgroundColor: elem.css( "backgroundColor" )
11182 };
11183
11184 if (mode === "hide") {
11185 animation.opacity = 0;
11186 }
11187
11188 $.effects.save( elem, props );
11189
11190 elem
11191 .show()
11192 .css({
11193 backgroundImage: "none",
11194 backgroundColor: o.color || "#ffff99"
11195 })
11196 .animate( animation, {
11197 queue: false,
11198 duration: o.duration,
11199 easing: o.easing,
11200 complete: function() {
11201 if ( mode === "hide" ) {
11202 elem.hide();
11203 }
11204 $.effects.restore( elem, props );
11205 done();
11206 }
11207 });
11208 };
11209
11210
11211 /*!
11212 * jQuery UI Effects Size 1.11.3
11213 * http://jqueryui.com
11214 *
11215 * Copyright jQuery Foundation and other contributors
11216 * Released under the MIT license.
11217 * http://jquery.org/license
11218 *
11219 * http://api.jqueryui.com/size-effect/
11220 */
11221
11222
11223 var effectSize = $.effects.effect.size = function( o, done ) {
11224
11225 // Create element
11226 var original, baseline, factor,
11227 el = $( this ),
11228 props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ],
11229
11230 // Always restore
11231 props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ],
11232
11233 // Copy for children
11234 props2 = [ "width", "height", "overflow" ],
11235 cProps = [ "fontSize" ],
11236 vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
11237 hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
11238
11239 // Set options
11240 mode = $.effects.setMode( el, o.mode || "effect" ),
11241 restore = o.restore || mode !== "effect",
11242 scale = o.scale || "both",
11243 origin = o.origin || [ "middle", "center" ],
11244 position = el.css( "position" ),
11245 props = restore ? props0 : props1,
11246 zero = {
11247 height: 0,
11248 width: 0,
11249 outerHeight: 0,
11250 outerWidth: 0
11251 };
11252
11253 if ( mode === "show" ) {
11254 el.show();
11255 }
11256 original = {
11257 height: el.height(),
11258 width: el.width(),
11259 outerHeight: el.outerHeight(),
11260 outerWidth: el.outerWidth()
11261 };
11262
11263 if ( o.mode === "toggle" && mode === "show" ) {
11264 el.from = o.to || zero;
11265 el.to = o.from || original;
11266 } else {
11267 el.from = o.from || ( mode === "show" ? zero : original );
11268 el.to = o.to || ( mode === "hide" ? zero : original );
11269 }
11270
11271 // Set scaling factor
11272 factor = {
11273 from: {
11274 y: el.from.height / original.height,
11275 x: el.from.width / original.width
11276 },
11277 to: {
11278 y: el.to.height / original.height,
11279 x: el.to.width / original.width
11280 }
11281 };
11282
11283 // Scale the css box
11284 if ( scale === "box" || scale === "both" ) {
11285
11286 // Vertical props scaling
11287 if ( factor.from.y !== factor.to.y ) {
11288 props = props.concat( vProps );
11289 el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
11290 el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
11291 }
11292
11293 // Horizontal props scaling
11294 if ( factor.from.x !== factor.to.x ) {
11295 props = props.concat( hProps );
11296 el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
11297 el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
11298 }
11299 }
11300
11301 // Scale the content
11302 if ( scale === "content" || scale === "both" ) {
11303
11304 // Vertical props scaling
11305 if ( factor.from.y !== factor.to.y ) {
11306 props = props.concat( cProps ).concat( props2 );
11307 el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
11308 el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
11309 }
11310 }
11311
11312 $.effects.save( el, props );
11313 el.show();
11314 $.effects.createWrapper( el );
11315 el.css( "overflow", "hidden" ).css( el.from );
11316
11317 // Adjust
11318 if (origin) { // Calculate baseline shifts
11319 baseline = $.effects.getBaseline( origin, original );
11320 el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
11321 el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
11322 el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
11323 el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
11324 }
11325 el.css( el.from ); // set top & left
11326
11327 // Animate
11328 if ( scale === "content" || scale === "both" ) { // Scale the children
11329
11330 // Add margins/font-size
11331 vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps);
11332 hProps = hProps.concat([ "marginLeft", "marginRight" ]);
11333 props2 = props0.concat(vProps).concat(hProps);
11334
11335 el.find( "*[width]" ).each( function() {
11336 var child = $( this ),
11337 c_original = {
11338 height: child.height(),
11339 width: child.width(),
11340 outerHeight: child.outerHeight(),
11341 outerWidth: child.outerWidth()
11342 };
11343 if (restore) {
11344 $.effects.save(child, props2);
11345 }
11346
11347 child.from = {
11348 height: c_original.height * factor.from.y,
11349 width: c_original.width * factor.from.x,
11350 outerHeight: c_original.outerHeight * factor.from.y,
11351 outerWidth: c_original.outerWidth * factor.from.x
11352 };
11353 child.to = {
11354 height: c_original.height * factor.to.y,
11355 width: c_original.width * factor.to.x,
11356 outerHeight: c_original.height * factor.to.y,
11357 outerWidth: c_original.width * factor.to.x
11358 };
11359
11360 // Vertical props scaling
11361 if ( factor.from.y !== factor.to.y ) {
11362 child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
11363 child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
11364 }
11365
11366 // Horizontal props scaling
11367 if ( factor.from.x !== factor.to.x ) {
11368 child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
11369 child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
11370 }
11371
11372 // Animate children
11373 child.css( child.from );
11374 child.animate( child.to, o.duration, o.easing, function() {
11375
11376 // Restore children
11377 if ( restore ) {
11378 $.effects.restore( child, props2 );
11379 }
11380 });
11381 });
11382 }
11383
11384 // Animate
11385 el.animate( el.to, {
11386 queue: false,
11387 duration: o.duration,
11388 easing: o.easing,
11389 complete: function() {
11390 if ( el.to.opacity === 0 ) {
11391 el.css( "opacity", el.from.opacity );
11392 }
11393 if ( mode === "hide" ) {
11394 el.hide();
11395 }
11396 $.effects.restore( el, props );
11397 if ( !restore ) {
11398
11399 // we need to calculate our new positioning based on the scaling
11400 if ( position === "static" ) {
11401 el.css({
11402 position: "relative",
11403 top: el.to.top,
11404 left: el.to.left
11405 });
11406 } else {
11407 $.each([ "top", "left" ], function( idx, pos ) {
11408 el.css( pos, function( _, str ) {
11409 var val = parseInt( str, 10 ),
11410 toRef = idx ? el.to.left : el.to.top;
11411
11412 // if original was "auto", recalculate the new value from wrapper
11413 if ( str === "auto" ) {
11414 return toRef + "px";
11415 }
11416
11417 return val + toRef + "px";
11418 });
11419 });
11420 }
11421 }
11422
11423 $.effects.removeWrapper( el );
11424 done();
11425 }
11426 });
11427
11428 };
11429
11430
11431 /*!
11432 * jQuery UI Effects Scale 1.11.3
11433 * http://jqueryui.com
11434 *
11435 * Copyright jQuery Foundation and other contributors
11436 * Released under the MIT license.
11437 * http://jquery.org/license
11438 *
11439 * http://api.jqueryui.com/scale-effect/
11440 */
11441
11442
11443 var effectScale = $.effects.effect.scale = function( o, done ) {
11444
11445 // Create element
11446 var el = $( this ),
11447 options = $.extend( true, {}, o ),
11448 mode = $.effects.setMode( el, o.mode || "effect" ),
11449 percent = parseInt( o.percent, 10 ) ||
11450 ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ),
11451 direction = o.direction || "both",
11452 origin = o.origin,
11453 original = {
11454 height: el.height(),
11455 width: el.width(),
11456 outerHeight: el.outerHeight(),
11457 outerWidth: el.outerWidth()
11458 },
11459 factor = {
11460 y: direction !== "horizontal" ? (percent / 100) : 1,
11461 x: direction !== "vertical" ? (percent / 100) : 1
11462 };
11463
11464 // We are going to pass this effect to the size effect:
11465 options.effect = "size";
11466 options.queue = false;
11467 options.complete = done;
11468
11469 // Set default origin and restore for show/hide
11470 if ( mode !== "effect" ) {
11471 options.origin = origin || [ "middle", "center" ];
11472 options.restore = true;
11473 }
11474
11475 options.from = o.from || ( mode === "show" ? {
11476 height: 0,
11477 width: 0,
11478 outerHeight: 0,
11479 outerWidth: 0
11480 } : original );
11481 options.to = {
11482 height: original.height * factor.y,
11483 width: original.width * factor.x,
11484 outerHeight: original.outerHeight * factor.y,
11485 outerWidth: original.outerWidth * factor.x
11486 };
11487
11488 // Fade option to support puff
11489 if ( options.fade ) {
11490 if ( mode === "show" ) {
11491 options.from.opacity = 0;
11492 options.to.opacity = 1;
11493 }
11494 if ( mode === "hide" ) {
11495 options.from.opacity = 1;
11496 options.to.opacity = 0;
11497 }
11498 }
11499
11500 // Animate
11501 el.effect( options );
11502
11503 };
11504
11505
11506 /*!
11507 * jQuery UI Effects Puff 1.11.3
11508 * http://jqueryui.com
11509 *
11510 * Copyright jQuery Foundation and other contributors
11511 * Released under the MIT license.
11512 * http://jquery.org/license
11513 *
11514 * http://api.jqueryui.com/puff-effect/
11515 */
11516
11517
11518 var effectPuff = $.effects.effect.puff = function( o, done ) {
11519 var elem = $( this ),
11520 mode = $.effects.setMode( elem, o.mode || "hide" ),
11521 hide = mode === "hide",
11522 percent = parseInt( o.percent, 10 ) || 150,
11523 factor = percent / 100,
11524 original = {
11525 height: elem.height(),
11526 width: elem.width(),
11527 outerHeight: elem.outerHeight(),
11528 outerWidth: elem.outerWidth()
11529 };
11530
11531 $.extend( o, {
11532 effect: "scale",
11533 queue: false,
11534 fade: true,
11535 mode: mode,
11536 complete: done,
11537 percent: hide ? percent : 100,
11538 from: hide ?
11539 original :
11540 {
11541 height: original.height * factor,
11542 width: original.width * factor,
11543 outerHeight: original.outerHeight * factor,
11544 outerWidth: original.outerWidth * factor
11545 }
11546 });
11547
11548 elem.effect( o );
11549 };
11550
11551
11552 /*!
11553 * jQuery UI Effects Pulsate 1.11.3
11554 * http://jqueryui.com
11555 *
11556 * Copyright jQuery Foundation and other contributors
11557 * Released under the MIT license.
11558 * http://jquery.org/license
11559 *
11560 * http://api.jqueryui.com/pulsate-effect/
11561 */
11562
11563
11564 var effectPulsate = $.effects.effect.pulsate = function( o, done ) {
11565 var elem = $( this ),
11566 mode = $.effects.setMode( elem, o.mode || "show" ),
11567 show = mode === "show",
11568 hide = mode === "hide",
11569 showhide = ( show || mode === "hide" ),
11570
11571 // showing or hiding leaves of the "last" animation
11572 anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
11573 duration = o.duration / anims,
11574 animateTo = 0,
11575 queue = elem.queue(),
11576 queuelen = queue.length,
11577 i;
11578
11579 if ( show || !elem.is(":visible")) {
11580 elem.css( "opacity", 0 ).show();
11581 animateTo = 1;
11582 }
11583
11584 // anims - 1 opacity "toggles"
11585 for ( i = 1; i < anims; i++ ) {
11586 elem.animate({
11587 opacity: animateTo
11588 }, duration, o.easing );
11589 animateTo = 1 - animateTo;
11590 }
11591
11592 elem.animate({
11593 opacity: animateTo
11594 }, duration, o.easing);
11595
11596 elem.queue(function() {
11597 if ( hide ) {
11598 elem.hide();
11599 }
11600 done();
11601 });
11602
11603 // We just queued up "anims" animations, we need to put them next in the queue
11604 if ( queuelen > 1 ) {
11605 queue.splice.apply( queue,
11606 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
11607 }
11608 elem.dequeue();
11609 };
11610
11611
11612 /*!
11613 * jQuery UI Effects Shake 1.11.3
11614 * http://jqueryui.com
11615 *
11616 * Copyright jQuery Foundation and other contributors
11617 * Released under the MIT license.
11618 * http://jquery.org/license
11619 *
11620 * http://api.jqueryui.com/shake-effect/
11621 */
11622
11623
11624 var effectShake = $.effects.effect.shake = function( o, done ) {
11625
11626 var el = $( this ),
11627 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
11628 mode = $.effects.setMode( el, o.mode || "effect" ),
11629 direction = o.direction || "left",
11630 distance = o.distance || 20,
11631 times = o.times || 3,
11632 anims = times * 2 + 1,
11633 speed = Math.round( o.duration / anims ),
11634 ref = (direction === "up" || direction === "down") ? "top" : "left",
11635 positiveMotion = (direction === "up" || direction === "left"),
11636 animation = {},
11637 animation1 = {},
11638 animation2 = {},
11639 i,
11640
11641 // we will need to re-assemble the queue to stack our animations in place
11642 queue = el.queue(),
11643 queuelen = queue.length;
11644
11645 $.effects.save( el, props );
11646 el.show();
11647 $.effects.createWrapper( el );
11648
11649 // Animation
11650 animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
11651 animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
11652 animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
11653
11654 // Animate
11655 el.animate( animation, speed, o.easing );
11656
11657 // Shakes
11658 for ( i = 1; i < times; i++ ) {
11659 el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing );
11660 }
11661 el
11662 .animate( animation1, speed, o.easing )
11663 .animate( animation, speed / 2, o.easing )
11664 .queue(function() {
11665 if ( mode === "hide" ) {
11666 el.hide();
11667 }
11668 $.effects.restore( el, props );
11669 $.effects.removeWrapper( el );
11670 done();
11671 });
11672
11673 // inject all the animations we just queued to be first in line (after "inprogress")
11674 if ( queuelen > 1) {
11675 queue.splice.apply( queue,
11676 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
11677 }
11678 el.dequeue();
11679
11680 };
11681
11682
11683 /*!
11684 * jQuery UI Effects Slide 1.11.3
11685 * http://jqueryui.com
11686 *
11687 * Copyright jQuery Foundation and other contributors
11688 * Released under the MIT license.
11689 * http://jquery.org/license
11690 *
11691 * http://api.jqueryui.com/slide-effect/
11692 */
11693
11694
11695 var effectSlide = $.effects.effect.slide = function( o, done ) {
11696
11697 // Create element
11698 var el = $( this ),
11699 props = [ "position", "top", "bottom", "left", "right", "width", "height" ],
11700 mode = $.effects.setMode( el, o.mode || "show" ),
11701 show = mode === "show",
11702 direction = o.direction || "left",
11703 ref = (direction === "up" || direction === "down") ? "top" : "left",
11704 positiveMotion = (direction === "up" || direction === "left"),
11705 distance,
11706 animation = {};
11707
11708 // Adjust
11709 $.effects.save( el, props );
11710 el.show();
11711 distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true );
11712
11713 $.effects.createWrapper( el ).css({
11714 overflow: "hidden"
11715 });
11716
11717 if ( show ) {
11718 el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance );
11719 }
11720
11721 // Animation
11722 animation[ ref ] = ( show ?
11723 ( positiveMotion ? "+=" : "-=") :
11724 ( positiveMotion ? "-=" : "+=")) +
11725 distance;
11726
11727 // Animate
11728 el.animate( animation, {
11729 queue: false,
11730 duration: o.duration,
11731 easing: o.easing,
11732 complete: function() {
11733 if ( mode === "hide" ) {
11734 el.hide();
11735 }
11736 $.effects.restore( el, props );
11737 $.effects.removeWrapper( el );
11738 done();
11739 }
11740 });
11741 };
11742
11743
11744 /*!
11745 * jQuery UI Effects Transfer 1.11.3
11746 * http://jqueryui.com
11747 *
11748 * Copyright jQuery Foundation and other contributors
11749 * Released under the MIT license.
11750 * http://jquery.org/license
11751 *
11752 * http://api.jqueryui.com/transfer-effect/
11753 */
11754
11755
11756 var effectTransfer = $.effects.effect.transfer = function( o, done ) {
11757 var elem = $( this ),
11758 target = $( o.to ),
11759 targetFixed = target.css( "position" ) === "fixed",
11760 body = $("body"),
11761 fixTop = targetFixed ? body.scrollTop() : 0,
11762 fixLeft = targetFixed ? body.scrollLeft() : 0,
11763 endPosition = target.offset(),
11764 animation = {
11765 top: endPosition.top - fixTop,
11766 left: endPosition.left - fixLeft,
11767 height: target.innerHeight(),
11768 width: target.innerWidth()
11769 },
11770 startPosition = elem.offset(),
11771 transfer = $( "<div class='ui-effects-transfer'></div>" )
11772 .appendTo( document.body )
11773 .addClass( o.className )
11774 .css({
11775 top: startPosition.top - fixTop,
11776 left: startPosition.left - fixLeft,
11777 height: elem.innerHeight(),
11778 width: elem.innerWidth(),
11779 position: targetFixed ? "fixed" : "absolute"
11780 })
11781 .animate( animation, o.duration, o.easing, function() {
11782 transfer.remove();
11783 done();
11784 });
11785 };
11786
11787
11788 /*!
11789 * jQuery UI Progressbar 1.11.3
11790 * http://jqueryui.com
11791 *
11792 * Copyright jQuery Foundation and other contributors
11793 * Released under the MIT license.
11794 * http://jquery.org/license
11795 *
11796 * http://api.jqueryui.com/progressbar/
11797 */
11798
11799
11800 var progressbar = $.widget( "ui.progressbar", {
11801 version: "1.11.3",
11802 options: {
11803 max: 100,
11804 value: 0,
11805
11806 change: null,
11807 complete: null
11808 },
11809
11810 min: 0,
11811
11812 _create: function() {
11813 // Constrain initial value
11814 this.oldValue = this.options.value = this._constrainedValue();
11815
11816 this.element
11817 .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
11818 .attr({
11819 // Only set static values, aria-valuenow and aria-valuemax are
11820 // set inside _refreshValue()
11821 role: "progressbar",
11822 "aria-valuemin": this.min
11823 });
11824
11825 this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
11826 .appendTo( this.element );
11827
11828 this._refreshValue();
11829 },
11830
11831 _destroy: function() {
11832 this.element
11833 .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
11834 .removeAttr( "role" )
11835 .removeAttr( "aria-valuemin" )
11836 .removeAttr( "aria-valuemax" )
11837 .removeAttr( "aria-valuenow" );
11838
11839 this.valueDiv.remove();
11840 },
11841
11842 value: function( newValue ) {
11843 if ( newValue === undefined ) {
11844 return this.options.value;
11845 }
11846
11847 this.options.value = this._constrainedValue( newValue );
11848 this._refreshValue();
11849 },
11850
11851 _constrainedValue: function( newValue ) {
11852 if ( newValue === undefined ) {
11853 newValue = this.options.value;
11854 }
11855
11856 this.indeterminate = newValue === false;
11857
11858 // sanitize value
11859 if ( typeof newValue !== "number" ) {
11860 newValue = 0;
11861 }
11862
11863 return this.indeterminate ? false :
11864 Math.min( this.options.max, Math.max( this.min, newValue ) );
11865 },
11866
11867 _setOptions: function( options ) {
11868 // Ensure "value" option is set after other values (like max)
11869 var value = options.value;
11870 delete options.value;
11871
11872 this._super( options );
11873
11874 this.options.value = this._constrainedValue( value );
11875 this._refreshValue();
11876 },
11877
11878 _setOption: function( key, value ) {
11879 if ( key === "max" ) {
11880 // Don't allow a max less than min
11881 value = Math.max( this.min, value );
11882 }
11883 if ( key === "disabled" ) {
11884 this.element
11885 .toggleClass( "ui-state-disabled", !!value )
11886 .attr( "aria-disabled", value );
11887 }
11888 this._super( key, value );
11889 },
11890
11891 _percentage: function() {
11892 return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
11893 },
11894
11895 _refreshValue: function() {
11896 var value = this.options.value,
11897 percentage = this._percentage();
11898
11899 this.valueDiv
11900 .toggle( this.indeterminate || value > this.min )
11901 .toggleClass( "ui-corner-right", value === this.options.max )
11902 .width( percentage.toFixed(0) + "%" );
11903
11904 this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate );
11905
11906 if ( this.indeterminate ) {
11907 this.element.removeAttr( "aria-valuenow" );
11908 if ( !this.overlayDiv ) {
11909 this.overlayDiv = $( "<div class='ui-progressbar-overlay'></div>" ).appendTo( this.valueDiv );
11910 }
11911 } else {
11912 this.element.attr({
11913 "aria-valuemax": this.options.max,
11914 "aria-valuenow": value
11915 });
11916 if ( this.overlayDiv ) {
11917 this.overlayDiv.remove();
11918 this.overlayDiv = null;
11919 }
11920 }
11921
11922 if ( this.oldValue !== value ) {
11923 this.oldValue = value;
11924 this._trigger( "change" );
11925 }
11926 if ( value === this.options.max ) {
11927 this._trigger( "complete" );
11928 }
11929 }
11930 });
11931
11932
11933 /*!
11934 * jQuery UI Selectable 1.11.3
11935 * http://jqueryui.com
11936 *
11937 * Copyright jQuery Foundation and other contributors
11938 * Released under the MIT license.
11939 * http://jquery.org/license
11940 *
11941 * http://api.jqueryui.com/selectable/
11942 */
11943
11944
11945 var selectable = $.widget("ui.selectable", $.ui.mouse, {
11946 version: "1.11.3",
11947 options: {
11948 appendTo: "body",
11949 autoRefresh: true,
11950 distance: 0,
11951 filter: "*",
11952 tolerance: "touch",
11953
11954 // callbacks
11955 selected: null,
11956 selecting: null,
11957 start: null,
11958 stop: null,
11959 unselected: null,
11960 unselecting: null
11961 },
11962 _create: function() {
11963 var selectees,
11964 that = this;
11965
11966 this.element.addClass("ui-selectable");
11967
11968 this.dragged = false;
11969
11970 // cache selectee children based on filter
11971 this.refresh = function() {
11972 selectees = $(that.options.filter, that.element[0]);
11973 selectees.addClass("ui-selectee");
11974 selectees.each(function() {
11975 var $this = $(this),
11976 pos = $this.offset();
11977 $.data(this, "selectable-item", {
11978 element: this,
11979 $element: $this,
11980 left: pos.left,
11981 top: pos.top,
11982 right: pos.left + $this.outerWidth(),
11983 bottom: pos.top + $this.outerHeight(),
11984 startselected: false,
11985 selected: $this.hasClass("ui-selected"),
11986 selecting: $this.hasClass("ui-selecting"),
11987 unselecting: $this.hasClass("ui-unselecting")
11988 });
11989 });
11990 };
11991 this.refresh();
11992
11993 this.selectees = selectees.addClass("ui-selectee");
11994
11995 this._mouseInit();
11996
11997 this.helper = $("<div class='ui-selectable-helper'></div>");
11998 },
11999
12000 _destroy: function() {
12001 this.selectees
12002 .removeClass("ui-selectee")
12003 .removeData("selectable-item");
12004 this.element
12005 .removeClass("ui-selectable ui-selectable-disabled");
12006 this._mouseDestroy();
12007 },
12008
12009 _mouseStart: function(event) {
12010 var that = this,
12011 options = this.options;
12012
12013 this.opos = [ event.pageX, event.pageY ];
12014
12015 if (this.options.disabled) {
12016 return;
12017 }
12018
12019 this.selectees = $(options.filter, this.element[0]);
12020
12021 this._trigger("start", event);
12022
12023 $(options.appendTo).append(this.helper);
12024 // position helper (lasso)
12025 this.helper.css({
12026 "left": event.pageX,
12027 "top": event.pageY,
12028 "width": 0,
12029 "height": 0
12030 });
12031
12032 if (options.autoRefresh) {
12033 this.refresh();
12034 }
12035
12036 this.selectees.filter(".ui-selected").each(function() {
12037 var selectee = $.data(this, "selectable-item");
12038 selectee.startselected = true;
12039 if (!event.metaKey && !event.ctrlKey) {
12040 selectee.$element.removeClass("ui-selected");
12041 selectee.selected = false;
12042 selectee.$element.addClass("ui-unselecting");
12043 selectee.unselecting = true;
12044 // selectable UNSELECTING callback
12045 that._trigger("unselecting", event, {
12046 unselecting: selectee.element
12047 });
12048 }
12049 });
12050
12051 $(event.target).parents().addBack().each(function() {
12052 var doSelect,
12053 selectee = $.data(this, "selectable-item");
12054 if (selectee) {
12055 doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected");
12056 selectee.$element
12057 .removeClass(doSelect ? "ui-unselecting" : "ui-selected")
12058 .addClass(doSelect ? "ui-selecting" : "ui-unselecting");
12059 selectee.unselecting = !doSelect;
12060 selectee.selecting = doSelect;
12061 selectee.selected = doSelect;
12062 // selectable (UN)SELECTING callback
12063 if (doSelect) {
12064 that._trigger("selecting", event, {
12065 selecting: selectee.element
12066 });
12067 } else {
12068 that._trigger("unselecting", event, {
12069 unselecting: selectee.element
12070 });
12071 }
12072 return false;
12073 }
12074 });
12075
12076 },
12077
12078 _mouseDrag: function(event) {
12079
12080 this.dragged = true;
12081
12082 if (this.options.disabled) {
12083 return;
12084 }
12085
12086 var tmp,
12087 that = this,
12088 options = this.options,
12089 x1 = this.opos[0],
12090 y1 = this.opos[1],
12091 x2 = event.pageX,
12092 y2 = event.pageY;
12093
12094 if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; }
12095 if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; }
12096 this.helper.css({ left: x1, top: y1, width: x2 - x1, height: y2 - y1 });
12097
12098 this.selectees.each(function() {
12099 var selectee = $.data(this, "selectable-item"),
12100 hit = false;
12101
12102 //prevent helper from being selected if appendTo: selectable
12103 if (!selectee || selectee.element === that.element[0]) {
12104 return;
12105 }
12106
12107 if (options.tolerance === "touch") {
12108 hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
12109 } else if (options.tolerance === "fit") {
12110 hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
12111 }
12112
12113 if (hit) {
12114 // SELECT
12115 if (selectee.selected) {
12116 selectee.$element.removeClass("ui-selected");
12117 selectee.selected = false;
12118 }
12119 if (selectee.unselecting) {
12120 selectee.$element.removeClass("ui-unselecting");
12121 selectee.unselecting = false;
12122 }
12123 if (!selectee.selecting) {
12124 selectee.$element.addClass("ui-selecting");
12125 selectee.selecting = true;
12126 // selectable SELECTING callback
12127 that._trigger("selecting", event, {
12128 selecting: selectee.element
12129 });
12130 }
12131 } else {
12132 // UNSELECT
12133 if (selectee.selecting) {
12134 if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
12135 selectee.$element.removeClass("ui-selecting");
12136 selectee.selecting = false;
12137 selectee.$element.addClass("ui-selected");
12138 selectee.selected = true;
12139 } else {
12140 selectee.$element.removeClass("ui-selecting");
12141 selectee.selecting = false;
12142 if (selectee.startselected) {
12143 selectee.$element.addClass("ui-unselecting");
12144 selectee.unselecting = true;
12145 }
12146 // selectable UNSELECTING callback
12147 that._trigger("unselecting", event, {
12148 unselecting: selectee.element
12149 });
12150 }
12151 }
12152 if (selectee.selected) {
12153 if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
12154 selectee.$element.removeClass("ui-selected");
12155 selectee.selected = false;
12156
12157 selectee.$element.addClass("ui-unselecting");
12158 selectee.unselecting = true;
12159 // selectable UNSELECTING callback
12160 that._trigger("unselecting", event, {
12161 unselecting: selectee.element
12162 });
12163 }
12164 }
12165 }
12166 });
12167
12168 return false;
12169 },
12170
12171 _mouseStop: function(event) {
12172 var that = this;
12173
12174 this.dragged = false;
12175
12176 $(".ui-unselecting", this.element[0]).each(function() {
12177 var selectee = $.data(this, "selectable-item");
12178 selectee.$element.removeClass("ui-unselecting");
12179 selectee.unselecting = false;
12180 selectee.startselected = false;
12181 that._trigger("unselected", event, {
12182 unselected: selectee.element
12183 });
12184 });
12185 $(".ui-selecting", this.element[0]).each(function() {
12186 var selectee = $.data(this, "selectable-item");
12187 selectee.$element.removeClass("ui-selecting").addClass("ui-selected");
12188 selectee.selecting = false;
12189 selectee.selected = true;
12190 selectee.startselected = true;
12191 that._trigger("selected", event, {
12192 selected: selectee.element
12193 });
12194 });
12195 this._trigger("stop", event);
12196
12197 this.helper.remove();
12198
12199 return false;
12200 }
12201
12202 });
12203
12204
12205 /*!
12206 * jQuery UI Selectmenu 1.11.3
12207 * http://jqueryui.com
12208 *
12209 * Copyright jQuery Foundation and other contributors
12210 * Released under the MIT license.
12211 * http://jquery.org/license
12212 *
12213 * http://api.jqueryui.com/selectmenu
12214 */
12215
12216
12217 var selectmenu = $.widget( "ui.selectmenu", {
12218 version: "1.11.3",
12219 defaultElement: "<select>",
12220 options: {
12221 appendTo: null,
12222 disabled: null,
12223 icons: {
12224 button: "ui-icon-triangle-1-s"
12225 },
12226 position: {
12227 my: "left top",
12228 at: "left bottom",
12229 collision: "none"
12230 },
12231 width: null,
12232
12233 // callbacks
12234 change: null,
12235 close: null,
12236 focus: null,
12237 open: null,
12238 select: null
12239 },
12240
12241 _create: function() {
12242 var selectmenuId = this.element.uniqueId().attr( "id" );
12243 this.ids = {
12244 element: selectmenuId,
12245 button: selectmenuId + "-button",
12246 menu: selectmenuId + "-menu"
12247 };
12248
12249 this._drawButton();
12250 this._drawMenu();
12251
12252 if ( this.options.disabled ) {
12253 this.disable();
12254 }
12255 },
12256
12257 _drawButton: function() {
12258 var that = this;
12259
12260 // Associate existing label with the new button
12261 this.label = $( "label[for='" + this.ids.element + "']" ).attr( "for", this.ids.button );
12262 this._on( this.label, {
12263 click: function( event ) {
12264 this.button.focus();
12265 event.preventDefault();
12266 }
12267 });
12268
12269 // Hide original select element
12270 this.element.hide();
12271
12272 // Create button
12273 this.button = $( "<span>", {
12274 "class": "ui-selectmenu-button ui-widget ui-state-default ui-corner-all",
12275 tabindex: this.options.disabled ? -1 : 0,
12276 id: this.ids.button,
12277 role: "combobox",
12278 "aria-expanded": "false",
12279 "aria-autocomplete": "list",
12280 "aria-owns": this.ids.menu,
12281 "aria-haspopup": "true"
12282 })
12283 .insertAfter( this.element );
12284
12285 $( "<span>", {
12286 "class": "ui-icon " + this.options.icons.button
12287 })
12288 .prependTo( this.button );
12289
12290 this.buttonText = $( "<span>", {
12291 "class": "ui-selectmenu-text"
12292 })
12293 .appendTo( this.button );
12294
12295 this._setText( this.buttonText, this.element.find( "option:selected" ).text() );
12296 this._resizeButton();
12297
12298 this._on( this.button, this._buttonEvents );
12299 this.button.one( "focusin", function() {
12300
12301 // Delay rendering the menu items until the button receives focus.
12302 // The menu may have already been rendered via a programmatic open.
12303 if ( !that.menuItems ) {
12304 that._refreshMenu();
12305 }
12306 });
12307 this._hoverable( this.button );
12308 this._focusable( this.button );
12309 },
12310
12311 _drawMenu: function() {
12312 var that = this;
12313
12314 // Create menu
12315 this.menu = $( "<ul>", {
12316 "aria-hidden": "true",
12317 "aria-labelledby": this.ids.button,
12318 id: this.ids.menu
12319 });
12320
12321 // Wrap menu
12322 this.menuWrap = $( "<div>", {
12323 "class": "ui-selectmenu-menu ui-front"
12324 })
12325 .append( this.menu )
12326 .appendTo( this._appendTo() );
12327
12328 // Initialize menu widget
12329 this.menuInstance = this.menu
12330 .menu({
12331 role: "listbox",
12332 select: function( event, ui ) {
12333 event.preventDefault();
12334
12335 // support: IE8
12336 // If the item was selected via a click, the text selection
12337 // will be destroyed in IE
12338 that._setSelection();
12339
12340 that._select( ui.item.data( "ui-selectmenu-item" ), event );
12341 },
12342 focus: function( event, ui ) {
12343 var item = ui.item.data( "ui-selectmenu-item" );
12344
12345 // Prevent inital focus from firing and check if its a newly focused item
12346 if ( that.focusIndex != null && item.index !== that.focusIndex ) {
12347 that._trigger( "focus", event, { item: item } );
12348 if ( !that.isOpen ) {
12349 that._select( item, event );
12350 }
12351 }
12352 that.focusIndex = item.index;
12353
12354 that.button.attr( "aria-activedescendant",
12355 that.menuItems.eq( item.index ).attr( "id" ) );
12356 }
12357 })
12358 .menu( "instance" );
12359
12360 // Adjust menu styles to dropdown
12361 this.menu
12362 .addClass( "ui-corner-bottom" )
12363 .removeClass( "ui-corner-all" );
12364
12365 // Don't close the menu on mouseleave
12366 this.menuInstance._off( this.menu, "mouseleave" );
12367
12368 // Cancel the menu's collapseAll on document click
12369 this.menuInstance._closeOnDocumentClick = function() {
12370 return false;
12371 };
12372
12373 // Selects often contain empty items, but never contain dividers
12374 this.menuInstance._isDivider = function() {
12375 return false;
12376 };
12377 },
12378
12379 refresh: function() {
12380 this._refreshMenu();
12381 this._setText( this.buttonText, this._getSelectedItem().text() );
12382 if ( !this.options.width ) {
12383 this._resizeButton();
12384 }
12385 },
12386
12387 _refreshMenu: function() {
12388 this.menu.empty();
12389
12390 var item,
12391 options = this.element.find( "option" );
12392
12393 if ( !options.length ) {
12394 return;
12395 }
12396
12397 this._parseOptions( options );
12398 this._renderMenu( this.menu, this.items );
12399
12400 this.menuInstance.refresh();
12401 this.menuItems = this.menu.find( "li" ).not( ".ui-selectmenu-optgroup" );
12402
12403 item = this._getSelectedItem();
12404
12405 // Update the menu to have the correct item focused
12406 this.menuInstance.focus( null, item );
12407 this._setAria( item.data( "ui-selectmenu-item" ) );
12408
12409 // Set disabled state
12410 this._setOption( "disabled", this.element.prop( "disabled" ) );
12411 },
12412
12413 open: function( event ) {
12414 if ( this.options.disabled ) {
12415 return;
12416 }
12417
12418 // If this is the first time the menu is being opened, render the items
12419 if ( !this.menuItems ) {
12420 this._refreshMenu();
12421 } else {
12422
12423 // Menu clears focus on close, reset focus to selected item
12424 this.menu.find( ".ui-state-focus" ).removeClass( "ui-state-focus" );
12425 this.menuInstance.focus( null, this._getSelectedItem() );
12426 }
12427
12428 this.isOpen = true;
12429 this._toggleAttr();
12430 this._resizeMenu();
12431 this._position();
12432
12433 this._on( this.document, this._documentClick );
12434
12435 this._trigger( "open", event );
12436 },
12437
12438 _position: function() {
12439 this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) );
12440 },
12441
12442 close: function( event ) {
12443 if ( !this.isOpen ) {
12444 return;
12445 }
12446
12447 this.isOpen = false;
12448 this._toggleAttr();
12449
12450 this.range = null;
12451 this._off( this.document );
12452
12453 this._trigger( "close", event );
12454 },
12455
12456 widget: function() {
12457 return this.button;
12458 },
12459
12460 menuWidget: function() {
12461 return this.menu;
12462 },
12463
12464 _renderMenu: function( ul, items ) {
12465 var that = this,
12466 currentOptgroup = "";
12467
12468 $.each( items, function( index, item ) {
12469 if ( item.optgroup !== currentOptgroup ) {
12470 $( "<li>", {
12471 "class": "ui-selectmenu-optgroup ui-menu-divider" +
12472 ( item.element.parent( "optgroup" ).prop( "disabled" ) ?
12473 " ui-state-disabled" :
12474 "" ),
12475 text: item.optgroup
12476 })
12477 .appendTo( ul );
12478
12479 currentOptgroup = item.optgroup;
12480 }
12481
12482 that._renderItemData( ul, item );
12483 });
12484 },
12485
12486 _renderItemData: function( ul, item ) {
12487 return this._renderItem( ul, item ).data( "ui-selectmenu-item", item );
12488 },
12489
12490 _renderItem: function( ul, item ) {
12491 var li = $( "<li>" );
12492
12493 if ( item.disabled ) {
12494 li.addClass( "ui-state-disabled" );
12495 }
12496 this._setText( li, item.label );
12497
12498 return li.appendTo( ul );
12499 },
12500
12501 _setText: function( element, value ) {
12502 if ( value ) {
12503 element.text( value );
12504 } else {
12505 element.html( "&#160;" );
12506 }
12507 },
12508
12509 _move: function( direction, event ) {
12510 var item, next,
12511 filter = ".ui-menu-item";
12512
12513 if ( this.isOpen ) {
12514 item = this.menuItems.eq( this.focusIndex );
12515 } else {
12516 item = this.menuItems.eq( this.element[ 0 ].selectedIndex );
12517 filter += ":not(.ui-state-disabled)";
12518 }
12519
12520 if ( direction === "first" || direction === "last" ) {
12521 next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 );
12522 } else {
12523 next = item[ direction + "All" ]( filter ).eq( 0 );
12524 }
12525
12526 if ( next.length ) {
12527 this.menuInstance.focus( event, next );
12528 }
12529 },
12530
12531 _getSelectedItem: function() {
12532 return this.menuItems.eq( this.element[ 0 ].selectedIndex );
12533 },
12534
12535 _toggle: function( event ) {
12536 this[ this.isOpen ? "close" : "open" ]( event );
12537 },
12538
12539 _setSelection: function() {
12540 var selection;
12541
12542 if ( !this.range ) {
12543 return;
12544 }
12545
12546 if ( window.getSelection ) {
12547 selection = window.getSelection();
12548 selection.removeAllRanges();
12549 selection.addRange( this.range );
12550
12551 // support: IE8
12552 } else {
12553 this.range.select();
12554 }
12555
12556 // support: IE
12557 // Setting the text selection kills the button focus in IE, but
12558 // restoring the focus doesn't kill the selection.
12559 this.button.focus();
12560 },
12561
12562 _documentClick: {
12563 mousedown: function( event ) {
12564 if ( !this.isOpen ) {
12565 return;
12566 }
12567
12568 if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" + this.ids.button ).length ) {
12569 this.close( event );
12570 }
12571 }
12572 },
12573
12574 _buttonEvents: {
12575
12576 // Prevent text selection from being reset when interacting with the selectmenu (#10144)
12577 mousedown: function() {
12578 var selection;
12579
12580 if ( window.getSelection ) {
12581 selection = window.getSelection();
12582 if ( selection.rangeCount ) {
12583 this.range = selection.getRangeAt( 0 );
12584 }
12585
12586 // support: IE8
12587 } else {
12588 this.range = document.selection.createRange();
12589 }
12590 },
12591
12592 click: function( event ) {
12593 this._setSelection();
12594 this._toggle( event );
12595 },
12596
12597 keydown: function( event ) {
12598 var preventDefault = true;
12599 switch ( event.keyCode ) {
12600 case $.ui.keyCode.TAB:
12601 case $.ui.keyCode.ESCAPE:
12602 this.close( event );
12603 preventDefault = false;
12604 break;
12605 case $.ui.keyCode.ENTER:
12606 if ( this.isOpen ) {
12607 this._selectFocusedItem( event );
12608 }
12609 break;
12610 case $.ui.keyCode.UP:
12611 if ( event.altKey ) {
12612 this._toggle( event );
12613 } else {
12614 this._move( "prev", event );
12615 }
12616 break;
12617 case $.ui.keyCode.DOWN:
12618 if ( event.altKey ) {
12619 this._toggle( event );
12620 } else {
12621 this._move( "next", event );
12622 }
12623 break;
12624 case $.ui.keyCode.SPACE:
12625 if ( this.isOpen ) {
12626 this._selectFocusedItem( event );
12627 } else {
12628 this._toggle( event );
12629 }
12630 break;
12631 case $.ui.keyCode.LEFT:
12632 this._move( "prev", event );
12633 break;
12634 case $.ui.keyCode.RIGHT:
12635 this._move( "next", event );
12636 break;
12637 case $.ui.keyCode.HOME:
12638 case $.ui.keyCode.PAGE_UP:
12639 this._move( "first", event );
12640 break;
12641 case $.ui.keyCode.END:
12642 case $.ui.keyCode.PAGE_DOWN:
12643 this._move( "last", event );
12644 break;
12645 default:
12646 this.menu.trigger( event );
12647 preventDefault = false;
12648 }
12649
12650 if ( preventDefault ) {
12651 event.preventDefault();
12652 }
12653 }
12654 },
12655
12656 _selectFocusedItem: function( event ) {
12657 var item = this.menuItems.eq( this.focusIndex );
12658 if ( !item.hasClass( "ui-state-disabled" ) ) {
12659 this._select( item.data( "ui-selectmenu-item" ), event );
12660 }
12661 },
12662
12663 _select: function( item, event ) {
12664 var oldIndex = this.element[ 0 ].selectedIndex;
12665
12666 // Change native select element
12667 this.element[ 0 ].selectedIndex = item.index;
12668 this._setText( this.buttonText, item.label );
12669 this._setAria( item );
12670 this._trigger( "select", event, { item: item } );
12671
12672 if ( item.index !== oldIndex ) {
12673 this._trigger( "change", event, { item: item } );
12674 }
12675
12676 this.close( event );
12677 },
12678
12679 _setAria: function( item ) {
12680 var id = this.menuItems.eq( item.index ).attr( "id" );
12681
12682 this.button.attr({
12683 "aria-labelledby": id,
12684 "aria-activedescendant": id
12685 });
12686 this.menu.attr( "aria-activedescendant", id );
12687 },
12688
12689 _setOption: function( key, value ) {
12690 if ( key === "icons" ) {
12691 this.button.find( "span.ui-icon" )
12692 .removeClass( this.options.icons.button )
12693 .addClass( value.button );
12694 }
12695
12696 this._super( key, value );
12697
12698 if ( key === "appendTo" ) {
12699 this.menuWrap.appendTo( this._appendTo() );
12700 }
12701
12702 if ( key === "disabled" ) {
12703 this.menuInstance.option( "disabled", value );
12704 this.button
12705 .toggleClass( "ui-state-disabled", value )
12706 .attr( "aria-disabled", value );
12707
12708 this.element.prop( "disabled", value );
12709 if ( value ) {
12710 this.button.attr( "tabindex", -1 );
12711 this.close();
12712 } else {
12713 this.button.attr( "tabindex", 0 );
12714 }
12715 }
12716
12717 if ( key === "width" ) {
12718 this._resizeButton();
12719 }
12720 },
12721
12722 _appendTo: function() {
12723 var element = this.options.appendTo;
12724
12725 if ( element ) {
12726 element = element.jquery || element.nodeType ?
12727 $( element ) :
12728 this.document.find( element ).eq( 0 );
12729 }
12730
12731 if ( !element || !element[ 0 ] ) {
12732 element = this.element.closest( ".ui-front" );
12733 }
12734
12735 if ( !element.length ) {
12736 element = this.document[ 0 ].body;
12737 }
12738
12739 return element;
12740 },
12741
12742 _toggleAttr: function() {
12743 this.button
12744 .toggleClass( "ui-corner-top", this.isOpen )
12745 .toggleClass( "ui-corner-all", !this.isOpen )
12746 .attr( "aria-expanded", this.isOpen );
12747 this.menuWrap.toggleClass( "ui-selectmenu-open", this.isOpen );
12748 this.menu.attr( "aria-hidden", !this.isOpen );
12749 },
12750
12751 _resizeButton: function() {
12752 var width = this.options.width;
12753
12754 if ( !width ) {
12755 width = this.element.show().outerWidth();
12756 this.element.hide();
12757 }
12758
12759 this.button.outerWidth( width );
12760 },
12761
12762 _resizeMenu: function() {
12763 this.menu.outerWidth( Math.max(
12764 this.button.outerWidth(),
12765
12766 // support: IE10
12767 // IE10 wraps long text (possibly a rounding bug)
12768 // so we add 1px to avoid the wrapping
12769 this.menu.width( "" ).outerWidth() + 1
12770 ) );
12771 },
12772
12773 _getCreateOptions: function() {
12774 return { disabled: this.element.prop( "disabled" ) };
12775 },
12776
12777 _parseOptions: function( options ) {
12778 var data = [];
12779 options.each(function( index, item ) {
12780 var option = $( item ),
12781 optgroup = option.parent( "optgroup" );
12782 data.push({
12783 element: option,
12784 index: index,
12785 value: option.val(),
12786 label: option.text(),
12787 optgroup: optgroup.attr( "label" ) || "",
12788 disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" )
12789 });
12790 });
12791 this.items = data;
12792 },
12793
12794 _destroy: function() {
12795 this.menuWrap.remove();
12796 this.button.remove();
12797 this.element.show();
12798 this.element.removeUniqueId();
12799 this.label.attr( "for", this.ids.element );
12800 }
12801 });
12802
12803
12804 /*!
12805 * jQuery UI Slider 1.11.3
12806 * http://jqueryui.com
12807 *
12808 * Copyright jQuery Foundation and other contributors
12809 * Released under the MIT license.
12810 * http://jquery.org/license
12811 *
12812 * http://api.jqueryui.com/slider/
12813 */
12814
12815
12816 var slider = $.widget( "ui.slider", $.ui.mouse, {
12817 version: "1.11.3",
12818 widgetEventPrefix: "slide",
12819
12820 options: {
12821 animate: false,
12822 distance: 0,
12823 max: 100,
12824 min: 0,
12825 orientation: "horizontal",
12826 range: false,
12827 step: 1,
12828 value: 0,
12829 values: null,
12830
12831 // callbacks
12832 change: null,
12833 slide: null,
12834 start: null,
12835 stop: null
12836 },
12837
12838 // number of pages in a slider
12839 // (how many times can you page up/down to go through the whole range)
12840 numPages: 5,
12841
12842 _create: function() {
12843 this._keySliding = false;
12844 this._mouseSliding = false;
12845 this._animateOff = true;
12846 this._handleIndex = null;
12847 this._detectOrientation();
12848 this._mouseInit();
12849 this._calculateNewMax();
12850
12851 this.element
12852 .addClass( "ui-slider" +
12853 " ui-slider-" + this.orientation +
12854 " ui-widget" +
12855 " ui-widget-content" +
12856 " ui-corner-all");
12857
12858 this._refresh();
12859 this._setOption( "disabled", this.options.disabled );
12860
12861 this._animateOff = false;
12862 },
12863
12864 _refresh: function() {
12865 this._createRange();
12866 this._createHandles();
12867 this._setupEvents();
12868 this._refreshValue();
12869 },
12870
12871 _createHandles: function() {
12872 var i, handleCount,
12873 options = this.options,
12874 existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
12875 handle = "<span class='ui-slider-handle ui-state-default ui-corner-all' tabindex='0'></span>",
12876 handles = [];
12877
12878 handleCount = ( options.values && options.values.length ) || 1;
12879
12880 if ( existingHandles.length > handleCount ) {
12881 existingHandles.slice( handleCount ).remove();
12882 existingHandles = existingHandles.slice( 0, handleCount );
12883 }
12884
12885 for ( i = existingHandles.length; i < handleCount; i++ ) {
12886 handles.push( handle );
12887 }
12888
12889 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
12890
12891 this.handle = this.handles.eq( 0 );
12892
12893 this.handles.each(function( i ) {
12894 $( this ).data( "ui-slider-handle-index", i );
12895 });
12896 },
12897
12898 _createRange: function() {
12899 var options = this.options,
12900 classes = "";
12901
12902 if ( options.range ) {
12903 if ( options.range === true ) {
12904 if ( !options.values ) {
12905 options.values = [ this._valueMin(), this._valueMin() ];
12906 } else if ( options.values.length && options.values.length !== 2 ) {
12907 options.values = [ options.values[0], options.values[0] ];
12908 } else if ( $.isArray( options.values ) ) {
12909 options.values = options.values.slice(0);
12910 }
12911 }
12912
12913 if ( !this.range || !this.range.length ) {
12914 this.range = $( "<div></div>" )
12915 .appendTo( this.element );
12916
12917 classes = "ui-slider-range" +
12918 // note: this isn't the most fittingly semantic framework class for this element,
12919 // but worked best visually with a variety of themes
12920 " ui-widget-header ui-corner-all";
12921 } else {
12922 this.range.removeClass( "ui-slider-range-min ui-slider-range-max" )
12923 // Handle range switching from true to min/max
12924 .css({
12925 "left": "",
12926 "bottom": ""
12927 });
12928 }
12929
12930 this.range.addClass( classes +
12931 ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) );
12932 } else {
12933 if ( this.range ) {
12934 this.range.remove();
12935 }
12936 this.range = null;
12937 }
12938 },
12939
12940 _setupEvents: function() {
12941 this._off( this.handles );
12942 this._on( this.handles, this._handleEvents );
12943 this._hoverable( this.handles );
12944 this._focusable( this.handles );
12945 },
12946
12947 _destroy: function() {
12948 this.handles.remove();
12949 if ( this.range ) {
12950 this.range.remove();
12951 }
12952
12953 this.element
12954 .removeClass( "ui-slider" +
12955 " ui-slider-horizontal" +
12956 " ui-slider-vertical" +
12957 " ui-widget" +
12958 " ui-widget-content" +
12959 " ui-corner-all" );
12960
12961 this._mouseDestroy();
12962 },
12963
12964 _mouseCapture: function( event ) {
12965 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
12966 that = this,
12967 o = this.options;
12968
12969 if ( o.disabled ) {
12970 return false;
12971 }
12972
12973 this.elementSize = {
12974 width: this.element.outerWidth(),
12975 height: this.element.outerHeight()
12976 };
12977 this.elementOffset = this.element.offset();
12978
12979 position = { x: event.pageX, y: event.pageY };
12980 normValue = this._normValueFromMouse( position );
12981 distance = this._valueMax() - this._valueMin() + 1;
12982 this.handles.each(function( i ) {
12983 var thisDistance = Math.abs( normValue - that.values(i) );
12984 if (( distance > thisDistance ) ||
12985 ( distance === thisDistance &&
12986 (i === that._lastChangedValue || that.values(i) === o.min ))) {
12987 distance = thisDistance;
12988 closestHandle = $( this );
12989 index = i;
12990 }
12991 });
12992
12993 allowed = this._start( event, index );
12994 if ( allowed === false ) {
12995 return false;
12996 }
12997 this._mouseSliding = true;
12998
12999 this._handleIndex = index;
13000
13001 closestHandle
13002 .addClass( "ui-state-active" )
13003 .focus();
13004
13005 offset = closestHandle.offset();
13006 mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
13007 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
13008 left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
13009 top: event.pageY - offset.top -
13010 ( closestHandle.height() / 2 ) -
13011 ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
13012 ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
13013 ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
13014 };
13015
13016 if ( !this.handles.hasClass( "ui-state-hover" ) ) {
13017 this._slide( event, index, normValue );
13018 }
13019 this._animateOff = true;
13020 return true;
13021 },
13022
13023 _mouseStart: function() {
13024 return true;
13025 },
13026
13027 _mouseDrag: function( event ) {
13028 var position = { x: event.pageX, y: event.pageY },
13029 normValue = this._normValueFromMouse( position );
13030
13031 this._slide( event, this._handleIndex, normValue );
13032
13033 return false;
13034 },
13035
13036 _mouseStop: function( event ) {
13037 this.handles.removeClass( "ui-state-active" );
13038 this._mouseSliding = false;
13039
13040 this._stop( event, this._handleIndex );
13041 this._change( event, this._handleIndex );
13042
13043 this._handleIndex = null;
13044 this._clickOffset = null;
13045 this._animateOff = false;
13046
13047 return false;
13048 },
13049
13050 _detectOrientation: function() {
13051 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
13052 },
13053
13054 _normValueFromMouse: function( position ) {
13055 var pixelTotal,
13056 pixelMouse,
13057 percentMouse,
13058 valueTotal,
13059 valueMouse;
13060
13061 if ( this.orientation === "horizontal" ) {
13062 pixelTotal = this.elementSize.width;
13063 pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
13064 } else {
13065 pixelTotal = this.elementSize.height;
13066 pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
13067 }
13068
13069 percentMouse = ( pixelMouse / pixelTotal );
13070 if ( percentMouse > 1 ) {
13071 percentMouse = 1;
13072 }
13073 if ( percentMouse < 0 ) {
13074 percentMouse = 0;
13075 }
13076 if ( this.orientation === "vertical" ) {
13077 percentMouse = 1 - percentMouse;
13078 }
13079
13080 valueTotal = this._valueMax() - this._valueMin();
13081 valueMouse = this._valueMin() + percentMouse * valueTotal;
13082
13083 return this._trimAlignValue( valueMouse );
13084 },
13085
13086 _start: function( event, index ) {
13087 var uiHash = {
13088 handle: this.handles[ index ],
13089 value: this.value()
13090 };
13091 if ( this.options.values && this.options.values.length ) {
13092 uiHash.value = this.values( index );
13093 uiHash.values = this.values();
13094 }
13095 return this._trigger( "start", event, uiHash );
13096 },
13097
13098 _slide: function( event, index, newVal ) {
13099 var otherVal,
13100 newValues,
13101 allowed;
13102
13103 if ( this.options.values && this.options.values.length ) {
13104 otherVal = this.values( index ? 0 : 1 );
13105
13106 if ( ( this.options.values.length === 2 && this.options.range === true ) &&
13107 ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
13108 ) {
13109 newVal = otherVal;
13110 }
13111
13112 if ( newVal !== this.values( index ) ) {
13113 newValues = this.values();
13114 newValues[ index ] = newVal;
13115 // A slide can be canceled by returning false from the slide callback
13116 allowed = this._trigger( "slide", event, {
13117 handle: this.handles[ index ],
13118 value: newVal,
13119 values: newValues
13120 } );
13121 otherVal = this.values( index ? 0 : 1 );
13122 if ( allowed !== false ) {
13123 this.values( index, newVal );
13124 }
13125 }
13126 } else {
13127 if ( newVal !== this.value() ) {
13128 // A slide can be canceled by returning false from the slide callback
13129 allowed = this._trigger( "slide", event, {
13130 handle: this.handles[ index ],
13131 value: newVal
13132 } );
13133 if ( allowed !== false ) {
13134 this.value( newVal );
13135 }
13136 }
13137 }
13138 },
13139
13140 _stop: function( event, index ) {
13141 var uiHash = {
13142 handle: this.handles[ index ],
13143 value: this.value()
13144 };
13145 if ( this.options.values && this.options.values.length ) {
13146 uiHash.value = this.values( index );
13147 uiHash.values = this.values();
13148 }
13149
13150 this._trigger( "stop", event, uiHash );
13151 },
13152
13153 _change: function( event, index ) {
13154 if ( !this._keySliding && !this._mouseSliding ) {
13155 var uiHash = {
13156 handle: this.handles[ index ],
13157 value: this.value()
13158 };
13159 if ( this.options.values && this.options.values.length ) {
13160 uiHash.value = this.values( index );
13161 uiHash.values = this.values();
13162 }
13163
13164 //store the last changed value index for reference when handles overlap
13165 this._lastChangedValue = index;
13166
13167 this._trigger( "change", event, uiHash );
13168 }
13169 },
13170
13171 value: function( newValue ) {
13172 if ( arguments.length ) {
13173 this.options.value = this._trimAlignValue( newValue );
13174 this._refreshValue();
13175 this._change( null, 0 );
13176 return;
13177 }
13178
13179 return this._value();
13180 },
13181
13182 values: function( index, newValue ) {
13183 var vals,
13184 newValues,
13185 i;
13186
13187 if ( arguments.length > 1 ) {
13188 this.options.values[ index ] = this._trimAlignValue( newValue );
13189 this._refreshValue();
13190 this._change( null, index );
13191 return;
13192 }
13193
13194 if ( arguments.length ) {
13195 if ( $.isArray( arguments[ 0 ] ) ) {
13196 vals = this.options.values;
13197 newValues = arguments[ 0 ];
13198 for ( i = 0; i < vals.length; i += 1 ) {
13199 vals[ i ] = this._trimAlignValue( newValues[ i ] );
13200 this._change( null, i );
13201 }
13202 this._refreshValue();
13203 } else {
13204 if ( this.options.values && this.options.values.length ) {
13205 return this._values( index );
13206 } else {
13207 return this.value();
13208 }
13209 }
13210 } else {
13211 return this._values();
13212 }
13213 },
13214
13215 _setOption: function( key, value ) {
13216 var i,
13217 valsLength = 0;
13218
13219 if ( key === "range" && this.options.range === true ) {
13220 if ( value === "min" ) {
13221 this.options.value = this._values( 0 );
13222 this.options.values = null;
13223 } else if ( value === "max" ) {
13224 this.options.value = this._values( this.options.values.length - 1 );
13225 this.options.values = null;
13226 }
13227 }
13228
13229 if ( $.isArray( this.options.values ) ) {
13230 valsLength = this.options.values.length;
13231 }
13232
13233 if ( key === "disabled" ) {
13234 this.element.toggleClass( "ui-state-disabled", !!value );
13235 }
13236
13237 this._super( key, value );
13238
13239 switch ( key ) {
13240 case "orientation":
13241 this._detectOrientation();
13242 this.element
13243 .removeClass( "ui-slider-horizontal ui-slider-vertical" )
13244 .addClass( "ui-slider-" + this.orientation );
13245 this._refreshValue();
13246
13247 // Reset positioning from previous orientation
13248 this.handles.css( value === "horizontal" ? "bottom" : "left", "" );
13249 break;
13250 case "value":
13251 this._animateOff = true;
13252 this._refreshValue();
13253 this._change( null, 0 );
13254 this._animateOff = false;
13255 break;
13256 case "values":
13257 this._animateOff = true;
13258 this._refreshValue();
13259 for ( i = 0; i < valsLength; i += 1 ) {
13260 this._change( null, i );
13261 }
13262 this._animateOff = false;
13263 break;
13264 case "step":
13265 case "min":
13266 case "max":
13267 this._animateOff = true;
13268 this._calculateNewMax();
13269 this._refreshValue();
13270 this._animateOff = false;
13271 break;
13272 case "range":
13273 this._animateOff = true;
13274 this._refresh();
13275 this._animateOff = false;
13276 break;
13277 }
13278 },
13279
13280 //internal value getter
13281 // _value() returns value trimmed by min and max, aligned by step
13282 _value: function() {
13283 var val = this.options.value;
13284 val = this._trimAlignValue( val );
13285
13286 return val;
13287 },
13288
13289 //internal values getter
13290 // _values() returns array of values trimmed by min and max, aligned by step
13291 // _values( index ) returns single value trimmed by min and max, aligned by step
13292 _values: function( index ) {
13293 var val,
13294 vals,
13295 i;
13296
13297 if ( arguments.length ) {
13298 val = this.options.values[ index ];
13299 val = this._trimAlignValue( val );
13300
13301 return val;
13302 } else if ( this.options.values && this.options.values.length ) {
13303 // .slice() creates a copy of the array
13304 // this copy gets trimmed by min and max and then returned
13305 vals = this.options.values.slice();
13306 for ( i = 0; i < vals.length; i += 1) {
13307 vals[ i ] = this._trimAlignValue( vals[ i ] );
13308 }
13309
13310 return vals;
13311 } else {
13312 return [];
13313 }
13314 },
13315
13316 // returns the step-aligned value that val is closest to, between (inclusive) min and max
13317 _trimAlignValue: function( val ) {
13318 if ( val <= this._valueMin() ) {
13319 return this._valueMin();
13320 }
13321 if ( val >= this._valueMax() ) {
13322 return this._valueMax();
13323 }
13324 var step = ( this.options.step > 0 ) ? this.options.step : 1,
13325 valModStep = (val - this._valueMin()) % step,
13326 alignValue = val - valModStep;
13327
13328 if ( Math.abs(valModStep) * 2 >= step ) {
13329 alignValue += ( valModStep > 0 ) ? step : ( -step );
13330 }
13331
13332 // Since JavaScript has problems with large floats, round
13333 // the final value to 5 digits after the decimal point (see #4124)
13334 return parseFloat( alignValue.toFixed(5) );
13335 },
13336
13337 _calculateNewMax: function() {
13338 var max = this.options.max,
13339 min = this._valueMin(),
13340 step = this.options.step,
13341 aboveMin = Math.floor( ( max - min ) / step ) * step;
13342 max = aboveMin + min;
13343 this.max = parseFloat( max.toFixed( this._precision() ) );
13344 },
13345
13346 _precision: function() {
13347 var precision = this._precisionOf( this.options.step );
13348 if ( this.options.min !== null ) {
13349 precision = Math.max( precision, this._precisionOf( this.options.min ) );
13350 }
13351 return precision;
13352 },
13353
13354 _precisionOf: function( num ) {
13355 var str = num.toString(),
13356 decimal = str.indexOf( "." );
13357 return decimal === -1 ? 0 : str.length - decimal - 1;
13358 },
13359
13360 _valueMin: function() {
13361 return this.options.min;
13362 },
13363
13364 _valueMax: function() {
13365 return this.max;
13366 },
13367
13368 _refreshValue: function() {
13369 var lastValPercent, valPercent, value, valueMin, valueMax,
13370 oRange = this.options.range,
13371 o = this.options,
13372 that = this,
13373 animate = ( !this._animateOff ) ? o.animate : false,
13374 _set = {};
13375
13376 if ( this.options.values && this.options.values.length ) {
13377 this.handles.each(function( i ) {
13378 valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
13379 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
13380 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
13381 if ( that.options.range === true ) {
13382 if ( that.orientation === "horizontal" ) {
13383 if ( i === 0 ) {
13384 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
13385 }
13386 if ( i === 1 ) {
13387 that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
13388 }
13389 } else {
13390 if ( i === 0 ) {
13391 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
13392 }
13393 if ( i === 1 ) {
13394 that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
13395 }
13396 }
13397 }
13398 lastValPercent = valPercent;
13399 });
13400 } else {
13401 value = this.value();
13402 valueMin = this._valueMin();
13403 valueMax = this._valueMax();
13404 valPercent = ( valueMax !== valueMin ) ?
13405 ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
13406 0;
13407 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
13408 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
13409
13410 if ( oRange === "min" && this.orientation === "horizontal" ) {
13411 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
13412 }
13413 if ( oRange === "max" && this.orientation === "horizontal" ) {
13414 this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
13415 }
13416 if ( oRange === "min" && this.orientation === "vertical" ) {
13417 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
13418 }
13419 if ( oRange === "max" && this.orientation === "vertical" ) {
13420 this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
13421 }
13422 }
13423 },
13424
13425 _handleEvents: {
13426 keydown: function( event ) {
13427 var allowed, curVal, newVal, step,
13428 index = $( event.target ).data( "ui-slider-handle-index" );
13429
13430 switch ( event.keyCode ) {
13431 case $.ui.keyCode.HOME:
13432 case $.ui.keyCode.END:
13433 case $.ui.keyCode.PAGE_UP:
13434 case $.ui.keyCode.PAGE_DOWN:
13435 case $.ui.keyCode.UP:
13436 case $.ui.keyCode.RIGHT:
13437 case $.ui.keyCode.DOWN:
13438 case $.ui.keyCode.LEFT:
13439 event.preventDefault();
13440 if ( !this._keySliding ) {
13441 this._keySliding = true;
13442 $( event.target ).addClass( "ui-state-active" );
13443 allowed = this._start( event, index );
13444 if ( allowed === false ) {
13445 return;
13446 }
13447 }
13448 break;
13449 }
13450
13451 step = this.options.step;
13452 if ( this.options.values && this.options.values.length ) {
13453 curVal = newVal = this.values( index );
13454 } else {
13455 curVal = newVal = this.value();
13456 }
13457
13458 switch ( event.keyCode ) {
13459 case $.ui.keyCode.HOME:
13460 newVal = this._valueMin();
13461 break;
13462 case $.ui.keyCode.END:
13463 newVal = this._valueMax();
13464 break;
13465 case $.ui.keyCode.PAGE_UP:
13466 newVal = this._trimAlignValue(
13467 curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages )
13468 );
13469 break;
13470 case $.ui.keyCode.PAGE_DOWN:
13471 newVal = this._trimAlignValue(
13472 curVal - ( (this._valueMax() - this._valueMin()) / this.numPages ) );
13473 break;
13474 case $.ui.keyCode.UP:
13475 case $.ui.keyCode.RIGHT:
13476 if ( curVal === this._valueMax() ) {
13477 return;
13478 }
13479 newVal = this._trimAlignValue( curVal + step );
13480 break;
13481 case $.ui.keyCode.DOWN:
13482 case $.ui.keyCode.LEFT:
13483 if ( curVal === this._valueMin() ) {
13484 return;
13485 }
13486 newVal = this._trimAlignValue( curVal - step );
13487 break;
13488 }
13489
13490 this._slide( event, index, newVal );
13491 },
13492 keyup: function( event ) {
13493 var index = $( event.target ).data( "ui-slider-handle-index" );
13494
13495 if ( this._keySliding ) {
13496 this._keySliding = false;
13497 this._stop( event, index );
13498 this._change( event, index );
13499 $( event.target ).removeClass( "ui-state-active" );
13500 }
13501 }
13502 }
13503 });
13504
13505
13506 /*!
13507 * jQuery UI Sortable 1.11.3
13508 * http://jqueryui.com
13509 *
13510 * Copyright jQuery Foundation and other contributors
13511 * Released under the MIT license.
13512 * http://jquery.org/license
13513 *
13514 * http://api.jqueryui.com/sortable/
13515 */
13516
13517
13518 var sortable = $.widget("ui.sortable", $.ui.mouse, {
13519 version: "1.11.3",
13520 widgetEventPrefix: "sort",
13521 ready: false,
13522 options: {
13523 appendTo: "parent",
13524 axis: false,
13525 connectWith: false,
13526 containment: false,
13527 cursor: "auto",
13528 cursorAt: false,
13529 dropOnEmpty: true,
13530 forcePlaceholderSize: false,
13531 forceHelperSize: false,
13532 grid: false,
13533 handle: false,
13534 helper: "original",
13535 items: "> *",
13536 opacity: false,
13537 placeholder: false,
13538 revert: false,
13539 scroll: true,
13540 scrollSensitivity: 20,
13541 scrollSpeed: 20,
13542 scope: "default",
13543 tolerance: "intersect",
13544 zIndex: 1000,
13545
13546 // callbacks
13547 activate: null,
13548 beforeStop: null,
13549 change: null,
13550 deactivate: null,
13551 out: null,
13552 over: null,
13553 receive: null,
13554 remove: null,
13555 sort: null,
13556 start: null,
13557 stop: null,
13558 update: null
13559 },
13560
13561 _isOverAxis: function( x, reference, size ) {
13562 return ( x >= reference ) && ( x < ( reference + size ) );
13563 },
13564
13565 _isFloating: function( item ) {
13566 return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display"));
13567 },
13568
13569 _create: function() {
13570
13571 var o = this.options;
13572 this.containerCache = {};
13573 this.element.addClass("ui-sortable");
13574
13575 //Get the items
13576 this.refresh();
13577
13578 //Let's determine if the items are being displayed horizontally
13579 this.floating = this.items.length ? o.axis === "x" || this._isFloating(this.items[0].item) : false;
13580
13581 //Let's determine the parent's offset
13582 this.offset = this.element.offset();
13583
13584 //Initialize mouse events for interaction
13585 this._mouseInit();
13586
13587 this._setHandleClassName();
13588
13589 //We're ready to go
13590 this.ready = true;
13591
13592 },
13593
13594 _setOption: function( key, value ) {
13595 this._super( key, value );
13596
13597 if ( key === "handle" ) {
13598 this._setHandleClassName();
13599 }
13600 },
13601
13602 _setHandleClassName: function() {
13603 this.element.find( ".ui-sortable-handle" ).removeClass( "ui-sortable-handle" );
13604 $.each( this.items, function() {
13605 ( this.instance.options.handle ?
13606 this.item.find( this.instance.options.handle ) : this.item )
13607 .addClass( "ui-sortable-handle" );
13608 });
13609 },
13610
13611 _destroy: function() {
13612 this.element
13613 .removeClass( "ui-sortable ui-sortable-disabled" )
13614 .find( ".ui-sortable-handle" )
13615 .removeClass( "ui-sortable-handle" );
13616 this._mouseDestroy();
13617
13618 for ( var i = this.items.length - 1; i >= 0; i-- ) {
13619 this.items[i].item.removeData(this.widgetName + "-item");
13620 }
13621
13622 return this;
13623 },
13624
13625 _mouseCapture: function(event, overrideHandle) {
13626 var currentItem = null,
13627 validHandle = false,
13628 that = this;
13629
13630 if (this.reverting) {
13631 return false;
13632 }
13633
13634 if(this.options.disabled || this.options.type === "static") {
13635 return false;
13636 }
13637
13638 //We have to refresh the items data once first
13639 this._refreshItems(event);
13640
13641 //Find out if the clicked node (or one of its parents) is a actual item in this.items
13642 $(event.target).parents().each(function() {
13643 if($.data(this, that.widgetName + "-item") === that) {
13644 currentItem = $(this);
13645 return false;
13646 }
13647 });
13648 if($.data(event.target, that.widgetName + "-item") === that) {
13649 currentItem = $(event.target);
13650 }
13651
13652 if(!currentItem) {
13653 return false;
13654 }
13655 if(this.options.handle && !overrideHandle) {
13656 $(this.options.handle, currentItem).find("*").addBack().each(function() {
13657 if(this === event.target) {
13658 validHandle = true;
13659 }
13660 });
13661 if(!validHandle) {
13662 return false;
13663 }
13664 }
13665
13666 this.currentItem = currentItem;
13667 this._removeCurrentsFromItems();
13668 return true;
13669
13670 },
13671
13672 _mouseStart: function(event, overrideHandle, noActivation) {
13673
13674 var i, body,
13675 o = this.options;
13676
13677 this.currentContainer = this;
13678
13679 //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
13680 this.refreshPositions();
13681
13682 //Create and append the visible helper
13683 this.helper = this._createHelper(event);
13684
13685 //Cache the helper size
13686 this._cacheHelperProportions();
13687
13688 /*
13689 * - Position generation -
13690 * This block generates everything position related - it's the core of draggables.
13691 */
13692
13693 //Cache the margins of the original element
13694 this._cacheMargins();
13695
13696 //Get the next scrolling parent
13697 this.scrollParent = this.helper.scrollParent();
13698
13699 //The element's absolute position on the page minus margins
13700 this.offset = this.currentItem.offset();
13701 this.offset = {
13702 top: this.offset.top - this.margins.top,
13703 left: this.offset.left - this.margins.left
13704 };
13705
13706 $.extend(this.offset, {
13707 click: { //Where the click happened, relative to the element
13708 left: event.pageX - this.offset.left,
13709 top: event.pageY - this.offset.top
13710 },
13711 parent: this._getParentOffset(),
13712 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
13713 });
13714
13715 // Only after we got the offset, we can change the helper's position to absolute
13716 // TODO: Still need to figure out a way to make relative sorting possible
13717 this.helper.css("position", "absolute");
13718 this.cssPosition = this.helper.css("position");
13719
13720 //Generate the original position
13721 this.originalPosition = this._generatePosition(event);
13722 this.originalPageX = event.pageX;
13723 this.originalPageY = event.pageY;
13724
13725 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
13726 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
13727
13728 //Cache the former DOM position
13729 this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
13730
13731 //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
13732 if(this.helper[0] !== this.currentItem[0]) {
13733 this.currentItem.hide();
13734 }
13735
13736 //Create the placeholder
13737 this._createPlaceholder();
13738
13739 //Set a containment if given in the options
13740 if(o.containment) {
13741 this._setContainment();
13742 }
13743
13744 if( o.cursor && o.cursor !== "auto" ) { // cursor option
13745 body = this.document.find( "body" );
13746
13747 // support: IE
13748 this.storedCursor = body.css( "cursor" );
13749 body.css( "cursor", o.cursor );
13750
13751 this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body );
13752 }
13753
13754 if(o.opacity) { // opacity option
13755 if (this.helper.css("opacity")) {
13756 this._storedOpacity = this.helper.css("opacity");
13757 }
13758 this.helper.css("opacity", o.opacity);
13759 }
13760
13761 if(o.zIndex) { // zIndex option
13762 if (this.helper.css("zIndex")) {
13763 this._storedZIndex = this.helper.css("zIndex");
13764 }
13765 this.helper.css("zIndex", o.zIndex);
13766 }
13767
13768 //Prepare scrolling
13769 if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") {
13770 this.overflowOffset = this.scrollParent.offset();
13771 }
13772
13773 //Call callbacks
13774 this._trigger("start", event, this._uiHash());
13775
13776 //Recache the helper size
13777 if(!this._preserveHelperProportions) {
13778 this._cacheHelperProportions();
13779 }
13780
13781
13782 //Post "activate" events to possible containers
13783 if( !noActivation ) {
13784 for ( i = this.containers.length - 1; i >= 0; i-- ) {
13785 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
13786 }
13787 }
13788
13789 //Prepare possible droppables
13790 if($.ui.ddmanager) {
13791 $.ui.ddmanager.current = this;
13792 }
13793
13794 if ($.ui.ddmanager && !o.dropBehaviour) {
13795 $.ui.ddmanager.prepareOffsets(this, event);
13796 }
13797
13798 this.dragging = true;
13799
13800 this.helper.addClass("ui-sortable-helper");
13801 this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
13802 return true;
13803
13804 },
13805
13806 _mouseDrag: function(event) {
13807 var i, item, itemElement, intersection,
13808 o = this.options,
13809 scrolled = false;
13810
13811 //Compute the helpers position
13812 this.position = this._generatePosition(event);
13813 this.positionAbs = this._convertPositionTo("absolute");
13814
13815 if (!this.lastPositionAbs) {
13816 this.lastPositionAbs = this.positionAbs;
13817 }
13818
13819 //Do scrolling
13820 if(this.options.scroll) {
13821 if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") {
13822
13823 if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
13824 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
13825 } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
13826 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
13827 }
13828
13829 if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
13830 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
13831 } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
13832 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
13833 }
13834
13835 } else {
13836
13837 if(event.pageY - this.document.scrollTop() < o.scrollSensitivity) {
13838 scrolled = this.document.scrollTop(this.document.scrollTop() - o.scrollSpeed);
13839 } else if(this.window.height() - (event.pageY - this.document.scrollTop()) < o.scrollSensitivity) {
13840 scrolled = this.document.scrollTop(this.document.scrollTop() + o.scrollSpeed);
13841 }
13842
13843 if(event.pageX - this.document.scrollLeft() < o.scrollSensitivity) {
13844 scrolled = this.document.scrollLeft(this.document.scrollLeft() - o.scrollSpeed);
13845 } else if(this.window.width() - (event.pageX - this.document.scrollLeft()) < o.scrollSensitivity) {
13846 scrolled = this.document.scrollLeft(this.document.scrollLeft() + o.scrollSpeed);
13847 }
13848
13849 }
13850
13851 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
13852 $.ui.ddmanager.prepareOffsets(this, event);
13853 }
13854 }
13855
13856 //Regenerate the absolute position used for position checks
13857 this.positionAbs = this._convertPositionTo("absolute");
13858
13859 //Set the helper position
13860 if(!this.options.axis || this.options.axis !== "y") {
13861 this.helper[0].style.left = this.position.left+"px";
13862 }
13863 if(!this.options.axis || this.options.axis !== "x") {
13864 this.helper[0].style.top = this.position.top+"px";
13865 }
13866
13867 //Rearrange
13868 for (i = this.items.length - 1; i >= 0; i--) {
13869
13870 //Cache variables and intersection, continue if no intersection
13871 item = this.items[i];
13872 itemElement = item.item[0];
13873 intersection = this._intersectsWithPointer(item);
13874 if (!intersection) {
13875 continue;
13876 }
13877
13878 // Only put the placeholder inside the current Container, skip all
13879 // items from other containers. This works because when moving
13880 // an item from one container to another the
13881 // currentContainer is switched before the placeholder is moved.
13882 //
13883 // Without this, moving items in "sub-sortables" can cause
13884 // the placeholder to jitter between the outer and inner container.
13885 if (item.instance !== this.currentContainer) {
13886 continue;
13887 }
13888
13889 // cannot intersect with itself
13890 // no useless actions that have been done before
13891 // no action if the item moved is the parent of the item checked
13892 if (itemElement !== this.currentItem[0] &&
13893 this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement &&
13894 !$.contains(this.placeholder[0], itemElement) &&
13895 (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true)
13896 ) {
13897
13898 this.direction = intersection === 1 ? "down" : "up";
13899
13900 if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
13901 this._rearrange(event, item);
13902 } else {
13903 break;
13904 }
13905
13906 this._trigger("change", event, this._uiHash());
13907 break;
13908 }
13909 }
13910
13911 //Post events to containers
13912 this._contactContainers(event);
13913
13914 //Interconnect with droppables
13915 if($.ui.ddmanager) {
13916 $.ui.ddmanager.drag(this, event);
13917 }
13918
13919 //Call callbacks
13920 this._trigger("sort", event, this._uiHash());
13921
13922 this.lastPositionAbs = this.positionAbs;
13923 return false;
13924
13925 },
13926
13927 _mouseStop: function(event, noPropagation) {
13928
13929 if(!event) {
13930 return;
13931 }
13932
13933 //If we are using droppables, inform the manager about the drop
13934 if ($.ui.ddmanager && !this.options.dropBehaviour) {
13935 $.ui.ddmanager.drop(this, event);
13936 }
13937
13938 if(this.options.revert) {
13939 var that = this,
13940 cur = this.placeholder.offset(),
13941 axis = this.options.axis,
13942 animation = {};
13943
13944 if ( !axis || axis === "x" ) {
13945 animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollLeft);
13946 }
13947 if ( !axis || axis === "y" ) {
13948 animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollTop);
13949 }
13950 this.reverting = true;
13951 $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() {
13952 that._clear(event);
13953 });
13954 } else {
13955 this._clear(event, noPropagation);
13956 }
13957
13958 return false;
13959
13960 },
13961
13962 cancel: function() {
13963
13964 if(this.dragging) {
13965
13966 this._mouseUp({ target: null });
13967
13968 if(this.options.helper === "original") {
13969 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
13970 } else {
13971 this.currentItem.show();
13972 }
13973
13974 //Post deactivating events to containers
13975 for (var i = this.containers.length - 1; i >= 0; i--){
13976 this.containers[i]._trigger("deactivate", null, this._uiHash(this));
13977 if(this.containers[i].containerCache.over) {
13978 this.containers[i]._trigger("out", null, this._uiHash(this));
13979 this.containers[i].containerCache.over = 0;
13980 }
13981 }
13982
13983 }
13984
13985 if (this.placeholder) {
13986 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
13987 if(this.placeholder[0].parentNode) {
13988 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
13989 }
13990 if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) {
13991 this.helper.remove();
13992 }
13993
13994 $.extend(this, {
13995 helper: null,
13996 dragging: false,
13997 reverting: false,
13998 _noFinalSort: null
13999 });
14000
14001 if(this.domPosition.prev) {
14002 $(this.domPosition.prev).after(this.currentItem);
14003 } else {
14004 $(this.domPosition.parent).prepend(this.currentItem);
14005 }
14006 }
14007
14008 return this;
14009
14010 },
14011
14012 serialize: function(o) {
14013
14014 var items = this._getItemsAsjQuery(o && o.connected),
14015 str = [];
14016 o = o || {};
14017
14018 $(items).each(function() {
14019 var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/));
14020 if (res) {
14021 str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2]));
14022 }
14023 });
14024
14025 if(!str.length && o.key) {
14026 str.push(o.key + "=");
14027 }
14028
14029 return str.join("&");
14030
14031 },
14032
14033 toArray: function(o) {
14034
14035 var items = this._getItemsAsjQuery(o && o.connected),
14036 ret = [];
14037
14038 o = o || {};
14039
14040 items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); });
14041 return ret;
14042
14043 },
14044
14045 /* Be careful with the following core functions */
14046 _intersectsWith: function(item) {
14047
14048 var x1 = this.positionAbs.left,
14049 x2 = x1 + this.helperProportions.width,
14050 y1 = this.positionAbs.top,
14051 y2 = y1 + this.helperProportions.height,
14052 l = item.left,
14053 r = l + item.width,
14054 t = item.top,
14055 b = t + item.height,
14056 dyClick = this.offset.click.top,
14057 dxClick = this.offset.click.left,
14058 isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ),
14059 isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ),
14060 isOverElement = isOverElementHeight && isOverElementWidth;
14061
14062 if ( this.options.tolerance === "pointer" ||
14063 this.options.forcePointerForContainers ||
14064 (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"])
14065 ) {
14066 return isOverElement;
14067 } else {
14068
14069 return (l < x1 + (this.helperProportions.width / 2) && // Right Half
14070 x2 - (this.helperProportions.width / 2) < r && // Left Half
14071 t < y1 + (this.helperProportions.height / 2) && // Bottom Half
14072 y2 - (this.helperProportions.height / 2) < b ); // Top Half
14073
14074 }
14075 },
14076
14077 _intersectsWithPointer: function(item) {
14078
14079 var isOverElementHeight = (this.options.axis === "x") || this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
14080 isOverElementWidth = (this.options.axis === "y") || this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
14081 isOverElement = isOverElementHeight && isOverElementWidth,
14082 verticalDirection = this._getDragVerticalDirection(),
14083 horizontalDirection = this._getDragHorizontalDirection();
14084
14085 if (!isOverElement) {
14086 return false;
14087 }
14088
14089 return this.floating ?
14090 ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 )
14091 : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) );
14092
14093 },
14094
14095 _intersectsWithSides: function(item) {
14096
14097 var isOverBottomHalf = this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
14098 isOverRightHalf = this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
14099 verticalDirection = this._getDragVerticalDirection(),
14100 horizontalDirection = this._getDragHorizontalDirection();
14101
14102 if (this.floating && horizontalDirection) {
14103 return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf));
14104 } else {
14105 return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf));
14106 }
14107
14108 },
14109
14110 _getDragVerticalDirection: function() {
14111 var delta = this.positionAbs.top - this.lastPositionAbs.top;
14112 return delta !== 0 && (delta > 0 ? "down" : "up");
14113 },
14114
14115 _getDragHorizontalDirection: function() {
14116 var delta = this.positionAbs.left - this.lastPositionAbs.left;
14117 return delta !== 0 && (delta > 0 ? "right" : "left");
14118 },
14119
14120 refresh: function(event) {
14121 this._refreshItems(event);
14122 this._setHandleClassName();
14123 this.refreshPositions();
14124 return this;
14125 },
14126
14127 _connectWith: function() {
14128 var options = this.options;
14129 return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith;
14130 },
14131
14132 _getItemsAsjQuery: function(connected) {
14133
14134 var i, j, cur, inst,
14135 items = [],
14136 queries = [],
14137 connectWith = this._connectWith();
14138
14139 if(connectWith && connected) {
14140 for (i = connectWith.length - 1; i >= 0; i--){
14141 cur = $(connectWith[i], this.document[0]);
14142 for ( j = cur.length - 1; j >= 0; j--){
14143 inst = $.data(cur[j], this.widgetFullName);
14144 if(inst && inst !== this && !inst.options.disabled) {
14145 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]);
14146 }
14147 }
14148 }
14149 }
14150
14151 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]);
14152
14153 function addItems() {
14154 items.push( this );
14155 }
14156 for (i = queries.length - 1; i >= 0; i--){
14157 queries[i][0].each( addItems );
14158 }
14159
14160 return $(items);
14161
14162 },
14163
14164 _removeCurrentsFromItems: function() {
14165
14166 var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
14167
14168 this.items = $.grep(this.items, function (item) {
14169 for (var j=0; j < list.length; j++) {
14170 if(list[j] === item.item[0]) {
14171 return false;
14172 }
14173 }
14174 return true;
14175 });
14176
14177 },
14178
14179 _refreshItems: function(event) {
14180
14181 this.items = [];
14182 this.containers = [this];
14183
14184 var i, j, cur, inst, targetData, _queries, item, queriesLength,
14185 items = this.items,
14186 queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]],
14187 connectWith = this._connectWith();
14188
14189 if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
14190 for (i = connectWith.length - 1; i >= 0; i--){
14191 cur = $(connectWith[i], this.document[0]);
14192 for (j = cur.length - 1; j >= 0; j--){
14193 inst = $.data(cur[j], this.widgetFullName);
14194 if(inst && inst !== this && !inst.options.disabled) {
14195 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
14196 this.containers.push(inst);
14197 }
14198 }
14199 }
14200 }
14201
14202 for (i = queries.length - 1; i >= 0; i--) {
14203 targetData = queries[i][1];
14204 _queries = queries[i][0];
14205
14206 for (j=0, queriesLength = _queries.length; j < queriesLength; j++) {
14207 item = $(_queries[j]);
14208
14209 item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager)
14210
14211 items.push({
14212 item: item,
14213 instance: targetData,
14214 width: 0, height: 0,
14215 left: 0, top: 0
14216 });
14217 }
14218 }
14219
14220 },
14221
14222 refreshPositions: function(fast) {
14223
14224 //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
14225 if(this.offsetParent && this.helper) {
14226 this.offset.parent = this._getParentOffset();
14227 }
14228
14229 var i, item, t, p;
14230
14231 for (i = this.items.length - 1; i >= 0; i--){
14232 item = this.items[i];
14233
14234 //We ignore calculating positions of all connected containers when we're not over them
14235 if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) {
14236 continue;
14237 }
14238
14239 t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
14240
14241 if (!fast) {
14242 item.width = t.outerWidth();
14243 item.height = t.outerHeight();
14244 }
14245
14246 p = t.offset();
14247 item.left = p.left;
14248 item.top = p.top;
14249 }
14250
14251 if(this.options.custom && this.options.custom.refreshContainers) {
14252 this.options.custom.refreshContainers.call(this);
14253 } else {
14254 for (i = this.containers.length - 1; i >= 0; i--){
14255 p = this.containers[i].element.offset();
14256 this.containers[i].containerCache.left = p.left;
14257 this.containers[i].containerCache.top = p.top;
14258 this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
14259 this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
14260 }
14261 }
14262
14263 return this;
14264 },
14265
14266 _createPlaceholder: function(that) {
14267 that = that || this;
14268 var className,
14269 o = that.options;
14270
14271 if(!o.placeholder || o.placeholder.constructor === String) {
14272 className = o.placeholder;
14273 o.placeholder = {
14274 element: function() {
14275
14276 var nodeName = that.currentItem[0].nodeName.toLowerCase(),
14277 element = $( "<" + nodeName + ">", that.document[0] )
14278 .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
14279 .removeClass("ui-sortable-helper");
14280
14281 if ( nodeName === "tr" ) {
14282 that.currentItem.children().each(function() {
14283 $( "<td>&#160;</td>", that.document[0] )
14284 .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
14285 .appendTo( element );
14286 });
14287 } else if ( nodeName === "img" ) {
14288 element.attr( "src", that.currentItem.attr( "src" ) );
14289 }
14290
14291 if ( !className ) {
14292 element.css( "visibility", "hidden" );
14293 }
14294
14295 return element;
14296 },
14297 update: function(container, p) {
14298
14299 // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
14300 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
14301 if(className && !o.forcePlaceholderSize) {
14302 return;
14303 }
14304
14305 //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
14306 if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); }
14307 if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); }
14308 }
14309 };
14310 }
14311
14312 //Create the placeholder
14313 that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));
14314
14315 //Append it after the actual current item
14316 that.currentItem.after(that.placeholder);
14317
14318 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
14319 o.placeholder.update(that, that.placeholder);
14320
14321 },
14322
14323 _contactContainers: function(event) {
14324 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom, floating, axis,
14325 innermostContainer = null,
14326 innermostIndex = null;
14327
14328 // get innermost container that intersects with item
14329 for (i = this.containers.length - 1; i >= 0; i--) {
14330
14331 // never consider a container that's located within the item itself
14332 if($.contains(this.currentItem[0], this.containers[i].element[0])) {
14333 continue;
14334 }
14335
14336 if(this._intersectsWith(this.containers[i].containerCache)) {
14337
14338 // if we've already found a container and it's more "inner" than this, then continue
14339 if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) {
14340 continue;
14341 }
14342
14343 innermostContainer = this.containers[i];
14344 innermostIndex = i;
14345
14346 } else {
14347 // container doesn't intersect. trigger "out" event if necessary
14348 if(this.containers[i].containerCache.over) {
14349 this.containers[i]._trigger("out", event, this._uiHash(this));
14350 this.containers[i].containerCache.over = 0;
14351 }
14352 }
14353
14354 }
14355
14356 // if no intersecting containers found, return
14357 if(!innermostContainer) {
14358 return;
14359 }
14360
14361 // move the item into the container if it's not there already
14362 if(this.containers.length === 1) {
14363 if (!this.containers[innermostIndex].containerCache.over) {
14364 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
14365 this.containers[innermostIndex].containerCache.over = 1;
14366 }
14367 } else {
14368
14369 //When entering a new container, we will find the item with the least distance and append our item near it
14370 dist = 10000;
14371 itemWithLeastDistance = null;
14372 floating = innermostContainer.floating || this._isFloating(this.currentItem);
14373 posProperty = floating ? "left" : "top";
14374 sizeProperty = floating ? "width" : "height";
14375 axis = floating ? "clientX" : "clientY";
14376
14377 for (j = this.items.length - 1; j >= 0; j--) {
14378 if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) {
14379 continue;
14380 }
14381 if(this.items[j].item[0] === this.currentItem[0]) {
14382 continue;
14383 }
14384
14385 cur = this.items[j].item.offset()[posProperty];
14386 nearBottom = false;
14387 if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
14388 nearBottom = true;
14389 }
14390
14391 if ( Math.abs( event[ axis ] - cur ) < dist ) {
14392 dist = Math.abs( event[ axis ] - cur );
14393 itemWithLeastDistance = this.items[ j ];
14394 this.direction = nearBottom ? "up": "down";
14395 }
14396 }
14397
14398 //Check if dropOnEmpty is enabled
14399 if(!itemWithLeastDistance && !this.options.dropOnEmpty) {
14400 return;
14401 }
14402
14403 if(this.currentContainer === this.containers[innermostIndex]) {
14404 if ( !this.currentContainer.containerCache.over ) {
14405 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
14406 this.currentContainer.containerCache.over = 1;
14407 }
14408 return;
14409 }
14410
14411 itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
14412 this._trigger("change", event, this._uiHash());
14413 this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
14414 this.currentContainer = this.containers[innermostIndex];
14415
14416 //Update the placeholder
14417 this.options.placeholder.update(this.currentContainer, this.placeholder);
14418
14419 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
14420 this.containers[innermostIndex].containerCache.over = 1;
14421 }
14422
14423
14424 },
14425
14426 _createHelper: function(event) {
14427
14428 var o = this.options,
14429 helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem);
14430
14431 //Add the helper to the DOM if that didn't happen already
14432 if(!helper.parents("body").length) {
14433 $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
14434 }
14435
14436 if(helper[0] === this.currentItem[0]) {
14437 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") };
14438 }
14439
14440 if(!helper[0].style.width || o.forceHelperSize) {
14441 helper.width(this.currentItem.width());
14442 }
14443 if(!helper[0].style.height || o.forceHelperSize) {
14444 helper.height(this.currentItem.height());
14445 }
14446
14447 return helper;
14448
14449 },
14450
14451 _adjustOffsetFromHelper: function(obj) {
14452 if (typeof obj === "string") {
14453 obj = obj.split(" ");
14454 }
14455 if ($.isArray(obj)) {
14456 obj = {left: +obj[0], top: +obj[1] || 0};
14457 }
14458 if ("left" in obj) {
14459 this.offset.click.left = obj.left + this.margins.left;
14460 }
14461 if ("right" in obj) {
14462 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
14463 }
14464 if ("top" in obj) {
14465 this.offset.click.top = obj.top + this.margins.top;
14466 }
14467 if ("bottom" in obj) {
14468 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
14469 }
14470 },
14471
14472 _getParentOffset: function() {
14473
14474
14475 //Get the offsetParent and cache its position
14476 this.offsetParent = this.helper.offsetParent();
14477 var po = this.offsetParent.offset();
14478
14479 // This is a special case where we need to modify a offset calculated on start, since the following happened:
14480 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
14481 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
14482 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
14483 if(this.cssPosition === "absolute" && this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) {
14484 po.left += this.scrollParent.scrollLeft();
14485 po.top += this.scrollParent.scrollTop();
14486 }
14487
14488 // This needs to be actually done for all browsers, since pageX/pageY includes this information
14489 // with an ugly IE fix
14490 if( this.offsetParent[0] === this.document[0].body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
14491 po = { top: 0, left: 0 };
14492 }
14493
14494 return {
14495 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
14496 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
14497 };
14498
14499 },
14500
14501 _getRelativeOffset: function() {
14502
14503 if(this.cssPosition === "relative") {
14504 var p = this.currentItem.position();
14505 return {
14506 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
14507 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
14508 };
14509 } else {
14510 return { top: 0, left: 0 };
14511 }
14512
14513 },
14514
14515 _cacheMargins: function() {
14516 this.margins = {
14517 left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
14518 top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
14519 };
14520 },
14521
14522 _cacheHelperProportions: function() {
14523 this.helperProportions = {
14524 width: this.helper.outerWidth(),
14525 height: this.helper.outerHeight()
14526 };
14527 },
14528
14529 _setContainment: function() {
14530
14531 var ce, co, over,
14532 o = this.options;
14533 if(o.containment === "parent") {
14534 o.containment = this.helper[0].parentNode;
14535 }
14536 if(o.containment === "document" || o.containment === "window") {
14537 this.containment = [
14538 0 - this.offset.relative.left - this.offset.parent.left,
14539 0 - this.offset.relative.top - this.offset.parent.top,
14540 o.containment === "document" ? this.document.width() : this.window.width() - this.helperProportions.width - this.margins.left,
14541 (o.containment === "document" ? this.document.width() : this.window.height() || this.document[0].body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
14542 ];
14543 }
14544
14545 if(!(/^(document|window|parent)$/).test(o.containment)) {
14546 ce = $(o.containment)[0];
14547 co = $(o.containment).offset();
14548 over = ($(ce).css("overflow") !== "hidden");
14549
14550 this.containment = [
14551 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
14552 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
14553 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,
14554 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
14555 ];
14556 }
14557
14558 },
14559
14560 _convertPositionTo: function(d, pos) {
14561
14562 if(!pos) {
14563 pos = this.position;
14564 }
14565 var mod = d === "absolute" ? 1 : -1,
14566 scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,
14567 scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
14568
14569 return {
14570 top: (
14571 pos.top + // The absolute mouse position
14572 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
14573 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
14574 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
14575 ),
14576 left: (
14577 pos.left + // The absolute mouse position
14578 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
14579 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
14580 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
14581 )
14582 };
14583
14584 },
14585
14586 _generatePosition: function(event) {
14587
14588 var top, left,
14589 o = this.options,
14590 pageX = event.pageX,
14591 pageY = event.pageY,
14592 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);
14593
14594 // This is another very weird special case that only happens for relative elements:
14595 // 1. If the css position is relative
14596 // 2. and the scroll parent is the document or similar to the offset parent
14597 // we have to refresh the relative offset during the scroll so there are no jumps
14598 if(this.cssPosition === "relative" && !(this.scrollParent[0] !== this.document[0] && this.scrollParent[0] !== this.offsetParent[0])) {
14599 this.offset.relative = this._getRelativeOffset();
14600 }
14601
14602 /*
14603 * - Position constraining -
14604 * Constrain the position to a mix of grid, containment.
14605 */
14606
14607 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
14608
14609 if(this.containment) {
14610 if(event.pageX - this.offset.click.left < this.containment[0]) {
14611 pageX = this.containment[0] + this.offset.click.left;
14612 }
14613 if(event.pageY - this.offset.click.top < this.containment[1]) {
14614 pageY = this.containment[1] + this.offset.click.top;
14615 }
14616 if(event.pageX - this.offset.click.left > this.containment[2]) {
14617 pageX = this.containment[2] + this.offset.click.left;
14618 }
14619 if(event.pageY - this.offset.click.top > this.containment[3]) {
14620 pageY = this.containment[3] + this.offset.click.top;
14621 }
14622 }
14623
14624 if(o.grid) {
14625 top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
14626 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;
14627
14628 left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
14629 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;
14630 }
14631
14632 }
14633
14634 return {
14635 top: (
14636 pageY - // The absolute mouse position
14637 this.offset.click.top - // Click offset (relative to the element)
14638 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
14639 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
14640 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
14641 ),
14642 left: (
14643 pageX - // The absolute mouse position
14644 this.offset.click.left - // Click offset (relative to the element)
14645 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
14646 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
14647 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
14648 )
14649 };
14650
14651 },
14652
14653 _rearrange: function(event, i, a, hardRefresh) {
14654
14655 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));
14656
14657 //Various things done here to improve the performance:
14658 // 1. we create a setTimeout, that calls refreshPositions
14659 // 2. on the instance, we have a counter variable, that get's higher after every append
14660 // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
14661 // 4. this lets only the last addition to the timeout stack through
14662 this.counter = this.counter ? ++this.counter : 1;
14663 var counter = this.counter;
14664
14665 this._delay(function() {
14666 if(counter === this.counter) {
14667 this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
14668 }
14669 });
14670
14671 },
14672
14673 _clear: function(event, noPropagation) {
14674
14675 this.reverting = false;
14676 // We delay all events that have to be triggered to after the point where the placeholder has been removed and
14677 // everything else normalized again
14678 var i,
14679 delayedTriggers = [];
14680
14681 // We first have to update the dom position of the actual currentItem
14682 // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
14683 if(!this._noFinalSort && this.currentItem.parent().length) {
14684 this.placeholder.before(this.currentItem);
14685 }
14686 this._noFinalSort = null;
14687
14688 if(this.helper[0] === this.currentItem[0]) {
14689 for(i in this._storedCSS) {
14690 if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") {
14691 this._storedCSS[i] = "";
14692 }
14693 }
14694 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
14695 } else {
14696 this.currentItem.show();
14697 }
14698
14699 if(this.fromOutside && !noPropagation) {
14700 delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
14701 }
14702 if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) {
14703 delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
14704 }
14705
14706 // Check if the items Container has Changed and trigger appropriate
14707 // events.
14708 if (this !== this.currentContainer) {
14709 if(!noPropagation) {
14710 delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
14711 delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
14712 delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
14713 }
14714 }
14715
14716
14717 //Post events to containers
14718 function delayEvent( type, instance, container ) {
14719 return function( event ) {
14720 container._trigger( type, event, instance._uiHash( instance ) );
14721 };
14722 }
14723 for (i = this.containers.length - 1; i >= 0; i--){
14724 if (!noPropagation) {
14725 delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
14726 }
14727 if(this.containers[i].containerCache.over) {
14728 delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
14729 this.containers[i].containerCache.over = 0;
14730 }
14731 }
14732
14733 //Do what was originally in plugins
14734 if ( this.storedCursor ) {
14735 this.document.find( "body" ).css( "cursor", this.storedCursor );
14736 this.storedStylesheet.remove();
14737 }
14738 if(this._storedOpacity) {
14739 this.helper.css("opacity", this._storedOpacity);
14740 }
14741 if(this._storedZIndex) {
14742 this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex);
14743 }
14744
14745 this.dragging = false;
14746
14747 if(!noPropagation) {
14748 this._trigger("beforeStop", event, this._uiHash());
14749 }
14750
14751 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
14752 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
14753
14754 if ( !this.cancelHelperRemoval ) {
14755 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
14756 this.helper.remove();
14757 }
14758 this.helper = null;
14759 }
14760
14761 if(!noPropagation) {
14762 for (i=0; i < delayedTriggers.length; i++) {
14763 delayedTriggers[i].call(this, event);
14764 } //Trigger all delayed events
14765 this._trigger("stop", event, this._uiHash());
14766 }
14767
14768 this.fromOutside = false;
14769 return !this.cancelHelperRemoval;
14770
14771 },
14772
14773 _trigger: function() {
14774 if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
14775 this.cancel();
14776 }
14777 },
14778
14779 _uiHash: function(_inst) {
14780 var inst = _inst || this;
14781 return {
14782 helper: inst.helper,
14783 placeholder: inst.placeholder || $([]),
14784 position: inst.position,
14785 originalPosition: inst.originalPosition,
14786 offset: inst.positionAbs,
14787 item: inst.currentItem,
14788 sender: _inst ? _inst.element : null
14789 };
14790 }
14791
14792 });
14793
14794
14795 /*!
14796 * jQuery UI Spinner 1.11.3
14797 * http://jqueryui.com
14798 *
14799 * Copyright jQuery Foundation and other contributors
14800 * Released under the MIT license.
14801 * http://jquery.org/license
14802 *
14803 * http://api.jqueryui.com/spinner/
14804 */
14805
14806
14807 function spinner_modifier( fn ) {
14808 return function() {
14809 var previous = this.element.val();
14810 fn.apply( this, arguments );
14811 this._refresh();
14812 if ( previous !== this.element.val() ) {
14813 this._trigger( "change" );
14814 }
14815 };
14816 }
14817
14818 var spinner = $.widget( "ui.spinner", {
14819 version: "1.11.3",
14820 defaultElement: "<input>",
14821 widgetEventPrefix: "spin",
14822 options: {
14823 culture: null,
14824 icons: {
14825 down: "ui-icon-triangle-1-s",
14826 up: "ui-icon-triangle-1-n"
14827 },
14828 incremental: true,
14829 max: null,
14830 min: null,
14831 numberFormat: null,
14832 page: 10,
14833 step: 1,
14834
14835 change: null,
14836 spin: null,
14837 start: null,
14838 stop: null
14839 },
14840
14841 _create: function() {
14842 // handle string values that need to be parsed
14843 this._setOption( "max", this.options.max );
14844 this._setOption( "min", this.options.min );
14845 this._setOption( "step", this.options.step );
14846
14847 // Only format if there is a value, prevents the field from being marked
14848 // as invalid in Firefox, see #9573.
14849 if ( this.value() !== "" ) {
14850 // Format the value, but don't constrain.
14851 this._value( this.element.val(), true );
14852 }
14853
14854 this._draw();
14855 this._on( this._events );
14856 this._refresh();
14857
14858 // turning off autocomplete prevents the browser from remembering the
14859 // value when navigating through history, so we re-enable autocomplete
14860 // if the page is unloaded before the widget is destroyed. #7790
14861 this._on( this.window, {
14862 beforeunload: function() {
14863 this.element.removeAttr( "autocomplete" );
14864 }
14865 });
14866 },
14867
14868 _getCreateOptions: function() {
14869 var options = {},
14870 element = this.element;
14871
14872 $.each( [ "min", "max", "step" ], function( i, option ) {
14873 var value = element.attr( option );
14874 if ( value !== undefined && value.length ) {
14875 options[ option ] = value;
14876 }
14877 });
14878
14879 return options;
14880 },
14881
14882 _events: {
14883 keydown: function( event ) {
14884 if ( this._start( event ) && this._keydown( event ) ) {
14885 event.preventDefault();
14886 }
14887 },
14888 keyup: "_stop",
14889 focus: function() {
14890 this.previous = this.element.val();
14891 },
14892 blur: function( event ) {
14893 if ( this.cancelBlur ) {
14894 delete this.cancelBlur;
14895 return;
14896 }
14897
14898 this._stop();
14899 this._refresh();
14900 if ( this.previous !== this.element.val() ) {
14901 this._trigger( "change", event );
14902 }
14903 },
14904 mousewheel: function( event, delta ) {
14905 if ( !delta ) {
14906 return;
14907 }
14908 if ( !this.spinning && !this._start( event ) ) {
14909 return false;
14910 }
14911
14912 this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
14913 clearTimeout( this.mousewheelTimer );
14914 this.mousewheelTimer = this._delay(function() {
14915 if ( this.spinning ) {
14916 this._stop( event );
14917 }
14918 }, 100 );
14919 event.preventDefault();
14920 },
14921 "mousedown .ui-spinner-button": function( event ) {
14922 var previous;
14923
14924 // We never want the buttons to have focus; whenever the user is
14925 // interacting with the spinner, the focus should be on the input.
14926 // If the input is focused then this.previous is properly set from
14927 // when the input first received focus. If the input is not focused
14928 // then we need to set this.previous based on the value before spinning.
14929 previous = this.element[0] === this.document[0].activeElement ?
14930 this.previous : this.element.val();
14931 function checkFocus() {
14932 var isActive = this.element[0] === this.document[0].activeElement;
14933 if ( !isActive ) {
14934 this.element.focus();
14935 this.previous = previous;
14936 // support: IE
14937 // IE sets focus asynchronously, so we need to check if focus
14938 // moved off of the input because the user clicked on the button.
14939 this._delay(function() {
14940 this.previous = previous;
14941 });
14942 }
14943 }
14944
14945 // ensure focus is on (or stays on) the text field
14946 event.preventDefault();
14947 checkFocus.call( this );
14948
14949 // support: IE
14950 // IE doesn't prevent moving focus even with event.preventDefault()
14951 // so we set a flag to know when we should ignore the blur event
14952 // and check (again) if focus moved off of the input.
14953 this.cancelBlur = true;
14954 this._delay(function() {
14955 delete this.cancelBlur;
14956 checkFocus.call( this );
14957 });
14958
14959 if ( this._start( event ) === false ) {
14960 return;
14961 }
14962
14963 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
14964 },
14965 "mouseup .ui-spinner-button": "_stop",
14966 "mouseenter .ui-spinner-button": function( event ) {
14967 // button will add ui-state-active if mouse was down while mouseleave and kept down
14968 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
14969 return;
14970 }
14971
14972 if ( this._start( event ) === false ) {
14973 return false;
14974 }
14975 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
14976 },
14977 // TODO: do we really want to consider this a stop?
14978 // shouldn't we just stop the repeater and wait until mouseup before
14979 // we trigger the stop event?
14980 "mouseleave .ui-spinner-button": "_stop"
14981 },
14982
14983 _draw: function() {
14984 var uiSpinner = this.uiSpinner = this.element
14985 .addClass( "ui-spinner-input" )
14986 .attr( "autocomplete", "off" )
14987 .wrap( this._uiSpinnerHtml() )
14988 .parent()
14989 // add buttons
14990 .append( this._buttonHtml() );
14991
14992 this.element.attr( "role", "spinbutton" );
14993
14994 // button bindings
14995 this.buttons = uiSpinner.find( ".ui-spinner-button" )
14996 .attr( "tabIndex", -1 )
14997 .button()
14998 .removeClass( "ui-corner-all" );
14999
15000 // IE 6 doesn't understand height: 50% for the buttons
15001 // unless the wrapper has an explicit height
15002 if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&
15003 uiSpinner.height() > 0 ) {
15004 uiSpinner.height( uiSpinner.height() );
15005 }
15006
15007 // disable spinner if element was already disabled
15008 if ( this.options.disabled ) {
15009 this.disable();
15010 }
15011 },
15012
15013 _keydown: function( event ) {
15014 var options = this.options,
15015 keyCode = $.ui.keyCode;
15016
15017 switch ( event.keyCode ) {
15018 case keyCode.UP:
15019 this._repeat( null, 1, event );
15020 return true;
15021 case keyCode.DOWN:
15022 this._repeat( null, -1, event );
15023 return true;
15024 case keyCode.PAGE_UP:
15025 this._repeat( null, options.page, event );
15026 return true;
15027 case keyCode.PAGE_DOWN:
15028 this._repeat( null, -options.page, event );
15029 return true;
15030 }
15031
15032 return false;
15033 },
15034
15035 _uiSpinnerHtml: function() {
15036 return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>";
15037 },
15038
15039 _buttonHtml: function() {
15040 return "" +
15041 "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" +
15042 "<span class='ui-icon " + this.options.icons.up + "'>&#9650;</span>" +
15043 "</a>" +
15044 "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" +
15045 "<span class='ui-icon " + this.options.icons.down + "'>&#9660;</span>" +
15046 "</a>";
15047 },
15048
15049 _start: function( event ) {
15050 if ( !this.spinning && this._trigger( "start", event ) === false ) {
15051 return false;
15052 }
15053
15054 if ( !this.counter ) {
15055 this.counter = 1;
15056 }
15057 this.spinning = true;
15058 return true;
15059 },
15060
15061 _repeat: function( i, steps, event ) {
15062 i = i || 500;
15063
15064 clearTimeout( this.timer );
15065 this.timer = this._delay(function() {
15066 this._repeat( 40, steps, event );
15067 }, i );
15068
15069 this._spin( steps * this.options.step, event );
15070 },
15071
15072 _spin: function( step, event ) {
15073 var value = this.value() || 0;
15074
15075 if ( !this.counter ) {
15076 this.counter = 1;
15077 }
15078
15079 value = this._adjustValue( value + step * this._increment( this.counter ) );
15080
15081 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) {
15082 this._value( value );
15083 this.counter++;
15084 }
15085 },
15086
15087 _increment: function( i ) {
15088 var incremental = this.options.incremental;
15089
15090 if ( incremental ) {
15091 return $.isFunction( incremental ) ?
15092 incremental( i ) :
15093 Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 );
15094 }
15095
15096 return 1;
15097 },
15098
15099 _precision: function() {
15100 var precision = this._precisionOf( this.options.step );
15101 if ( this.options.min !== null ) {
15102 precision = Math.max( precision, this._precisionOf( this.options.min ) );
15103 }
15104 return precision;
15105 },
15106
15107 _precisionOf: function( num ) {
15108 var str = num.toString(),
15109 decimal = str.indexOf( "." );
15110 return decimal === -1 ? 0 : str.length - decimal - 1;
15111 },
15112
15113 _adjustValue: function( value ) {
15114 var base, aboveMin,
15115 options = this.options;
15116
15117 // make sure we're at a valid step
15118 // - find out where we are relative to the base (min or 0)
15119 base = options.min !== null ? options.min : 0;
15120 aboveMin = value - base;
15121 // - round to the nearest step
15122 aboveMin = Math.round(aboveMin / options.step) * options.step;
15123 // - rounding is based on 0, so adjust back to our base
15124 value = base + aboveMin;
15125
15126 // fix precision from bad JS floating point math
15127 value = parseFloat( value.toFixed( this._precision() ) );
15128
15129 // clamp the value
15130 if ( options.max !== null && value > options.max) {
15131 return options.max;
15132 }
15133 if ( options.min !== null && value < options.min ) {
15134 return options.min;
15135 }
15136
15137 return value;
15138 },
15139
15140 _stop: function( event ) {
15141 if ( !this.spinning ) {
15142 return;
15143 }
15144
15145 clearTimeout( this.timer );
15146 clearTimeout( this.mousewheelTimer );
15147 this.counter = 0;
15148 this.spinning = false;
15149 this._trigger( "stop", event );
15150 },
15151
15152 _setOption: function( key, value ) {
15153 if ( key === "culture" || key === "numberFormat" ) {
15154 var prevValue = this._parse( this.element.val() );
15155 this.options[ key ] = value;
15156 this.element.val( this._format( prevValue ) );
15157 return;
15158 }
15159
15160 if ( key === "max" || key === "min" || key === "step" ) {
15161 if ( typeof value === "string" ) {
15162 value = this._parse( value );
15163 }
15164 }
15165 if ( key === "icons" ) {
15166 this.buttons.first().find( ".ui-icon" )
15167 .removeClass( this.options.icons.up )
15168 .addClass( value.up );
15169 this.buttons.last().find( ".ui-icon" )
15170 .removeClass( this.options.icons.down )
15171 .addClass( value.down );
15172 }
15173
15174 this._super( key, value );
15175
15176 if ( key === "disabled" ) {
15177 this.widget().toggleClass( "ui-state-disabled", !!value );
15178 this.element.prop( "disabled", !!value );
15179 this.buttons.button( value ? "disable" : "enable" );
15180 }
15181 },
15182
15183 _setOptions: spinner_modifier(function( options ) {
15184 this._super( options );
15185 }),
15186
15187 _parse: function( val ) {
15188 if ( typeof val === "string" && val !== "" ) {
15189 val = window.Globalize && this.options.numberFormat ?
15190 Globalize.parseFloat( val, 10, this.options.culture ) : +val;
15191 }
15192 return val === "" || isNaN( val ) ? null : val;
15193 },
15194
15195 _format: function( value ) {
15196 if ( value === "" ) {
15197 return "";
15198 }
15199 return window.Globalize && this.options.numberFormat ?
15200 Globalize.format( value, this.options.numberFormat, this.options.culture ) :
15201 value;
15202 },
15203
15204 _refresh: function() {
15205 this.element.attr({
15206 "aria-valuemin": this.options.min,
15207 "aria-valuemax": this.options.max,
15208 // TODO: what should we do with values that can't be parsed?
15209 "aria-valuenow": this._parse( this.element.val() )
15210 });
15211 },
15212
15213 isValid: function() {
15214 var value = this.value();
15215
15216 // null is invalid
15217 if ( value === null ) {
15218 return false;
15219 }
15220
15221 // if value gets adjusted, it's invalid
15222 return value === this._adjustValue( value );
15223 },
15224
15225 // update the value without triggering change
15226 _value: function( value, allowAny ) {
15227 var parsed;
15228 if ( value !== "" ) {
15229 parsed = this._parse( value );
15230 if ( parsed !== null ) {
15231 if ( !allowAny ) {
15232 parsed = this._adjustValue( parsed );
15233 }
15234 value = this._format( parsed );
15235 }
15236 }
15237 this.element.val( value );
15238 this._refresh();
15239 },
15240
15241 _destroy: function() {
15242 this.element
15243 .removeClass( "ui-spinner-input" )
15244 .prop( "disabled", false )
15245 .removeAttr( "autocomplete" )
15246 .removeAttr( "role" )
15247 .removeAttr( "aria-valuemin" )
15248 .removeAttr( "aria-valuemax" )
15249 .removeAttr( "aria-valuenow" );
15250 this.uiSpinner.replaceWith( this.element );
15251 },
15252
15253 stepUp: spinner_modifier(function( steps ) {
15254 this._stepUp( steps );
15255 }),
15256 _stepUp: function( steps ) {
15257 if ( this._start() ) {
15258 this._spin( (steps || 1) * this.options.step );
15259 this._stop();
15260 }
15261 },
15262
15263 stepDown: spinner_modifier(function( steps ) {
15264 this._stepDown( steps );
15265 }),
15266 _stepDown: function( steps ) {
15267 if ( this._start() ) {
15268 this._spin( (steps || 1) * -this.options.step );
15269 this._stop();
15270 }
15271 },
15272
15273 pageUp: spinner_modifier(function( pages ) {
15274 this._stepUp( (pages || 1) * this.options.page );
15275 }),
15276
15277 pageDown: spinner_modifier(function( pages ) {
15278 this._stepDown( (pages || 1) * this.options.page );
15279 }),
15280
15281 value: function( newVal ) {
15282 if ( !arguments.length ) {
15283 return this._parse( this.element.val() );
15284 }
15285 spinner_modifier( this._value ).call( this, newVal );
15286 },
15287
15288 widget: function() {
15289 return this.uiSpinner;
15290 }
15291 });
15292
15293
15294 /*!
15295 * jQuery UI Tabs 1.11.3
15296 * http://jqueryui.com
15297 *
15298 * Copyright jQuery Foundation and other contributors
15299 * Released under the MIT license.
15300 * http://jquery.org/license
15301 *
15302 * http://api.jqueryui.com/tabs/
15303 */
15304
15305
15306 var tabs = $.widget( "ui.tabs", {
15307 version: "1.11.3",
15308 delay: 300,
15309 options: {
15310 active: null,
15311 collapsible: false,
15312 event: "click",
15313 heightStyle: "content",
15314 hide: null,
15315 show: null,
15316
15317 // callbacks
15318 activate: null,
15319 beforeActivate: null,
15320 beforeLoad: null,
15321 load: null
15322 },
15323
15324 _isLocal: (function() {
15325 var rhash = /#.*$/;
15326
15327 return function( anchor ) {
15328 var anchorUrl, locationUrl;
15329
15330 // support: IE7
15331 // IE7 doesn't normalize the href property when set via script (#9317)
15332 anchor = anchor.cloneNode( false );
15333
15334 anchorUrl = anchor.href.replace( rhash, "" );
15335 locationUrl = location.href.replace( rhash, "" );
15336
15337 // decoding may throw an error if the URL isn't UTF-8 (#9518)
15338 try {
15339 anchorUrl = decodeURIComponent( anchorUrl );
15340 } catch ( error ) {}
15341 try {
15342 locationUrl = decodeURIComponent( locationUrl );
15343 } catch ( error ) {}
15344
15345 return anchor.hash.length > 1 && anchorUrl === locationUrl;
15346 };
15347 })(),
15348
15349 _create: function() {
15350 var that = this,
15351 options = this.options;
15352
15353 this.running = false;
15354
15355 this.element
15356 .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" )
15357 .toggleClass( "ui-tabs-collapsible", options.collapsible );
15358
15359 this._processTabs();
15360 options.active = this._initialActive();
15361
15362 // Take disabling tabs via class attribute from HTML
15363 // into account and update option properly.
15364 if ( $.isArray( options.disabled ) ) {
15365 options.disabled = $.unique( options.disabled.concat(
15366 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
15367 return that.tabs.index( li );
15368 })
15369 ) ).sort();
15370 }
15371
15372 // check for length avoids error when initializing empty list
15373 if ( this.options.active !== false && this.anchors.length ) {
15374 this.active = this._findActive( options.active );
15375 } else {
15376 this.active = $();
15377 }
15378
15379 this._refresh();
15380
15381 if ( this.active.length ) {
15382 this.load( options.active );
15383 }
15384 },
15385
15386 _initialActive: function() {
15387 var active = this.options.active,
15388 collapsible = this.options.collapsible,
15389 locationHash = location.hash.substring( 1 );
15390
15391 if ( active === null ) {
15392 // check the fragment identifier in the URL
15393 if ( locationHash ) {
15394 this.tabs.each(function( i, tab ) {
15395 if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
15396 active = i;
15397 return false;
15398 }
15399 });
15400 }
15401
15402 // check for a tab marked active via a class
15403 if ( active === null ) {
15404 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
15405 }
15406
15407 // no active tab, set to false
15408 if ( active === null || active === -1 ) {
15409 active = this.tabs.length ? 0 : false;
15410 }
15411 }
15412
15413 // handle numbers: negative, out of range
15414 if ( active !== false ) {
15415 active = this.tabs.index( this.tabs.eq( active ) );
15416 if ( active === -1 ) {
15417 active = collapsible ? false : 0;
15418 }
15419 }
15420
15421 // don't allow collapsible: false and active: false
15422 if ( !collapsible && active === false && this.anchors.length ) {
15423 active = 0;
15424 }
15425
15426 return active;
15427 },
15428
15429 _getCreateEventData: function() {
15430 return {
15431 tab: this.active,
15432 panel: !this.active.length ? $() : this._getPanelForTab( this.active )
15433 };
15434 },
15435
15436 _tabKeydown: function( event ) {
15437 var focusedTab = $( this.document[0].activeElement ).closest( "li" ),
15438 selectedIndex = this.tabs.index( focusedTab ),
15439 goingForward = true;
15440
15441 if ( this._handlePageNav( event ) ) {
15442 return;
15443 }
15444
15445 switch ( event.keyCode ) {
15446 case $.ui.keyCode.RIGHT:
15447 case $.ui.keyCode.DOWN:
15448 selectedIndex++;
15449 break;
15450 case $.ui.keyCode.UP:
15451 case $.ui.keyCode.LEFT:
15452 goingForward = false;
15453 selectedIndex--;
15454 break;
15455 case $.ui.keyCode.END:
15456 selectedIndex = this.anchors.length - 1;
15457 break;
15458 case $.ui.keyCode.HOME:
15459 selectedIndex = 0;
15460 break;
15461 case $.ui.keyCode.SPACE:
15462 // Activate only, no collapsing
15463 event.preventDefault();
15464 clearTimeout( this.activating );
15465 this._activate( selectedIndex );
15466 return;
15467 case $.ui.keyCode.ENTER:
15468 // Toggle (cancel delayed activation, allow collapsing)
15469 event.preventDefault();
15470 clearTimeout( this.activating );
15471 // Determine if we should collapse or activate
15472 this._activate( selectedIndex === this.options.active ? false : selectedIndex );
15473 return;
15474 default:
15475 return;
15476 }
15477
15478 // Focus the appropriate tab, based on which key was pressed
15479 event.preventDefault();
15480 clearTimeout( this.activating );
15481 selectedIndex = this._focusNextTab( selectedIndex, goingForward );
15482
15483 // Navigating with control/command key will prevent automatic activation
15484 if ( !event.ctrlKey && !event.metaKey ) {
15485
15486 // Update aria-selected immediately so that AT think the tab is already selected.
15487 // Otherwise AT may confuse the user by stating that they need to activate the tab,
15488 // but the tab will already be activated by the time the announcement finishes.
15489 focusedTab.attr( "aria-selected", "false" );
15490 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
15491
15492 this.activating = this._delay(function() {
15493 this.option( "active", selectedIndex );
15494 }, this.delay );
15495 }
15496 },
15497
15498 _panelKeydown: function( event ) {
15499 if ( this._handlePageNav( event ) ) {
15500 return;
15501 }
15502
15503 // Ctrl+up moves focus to the current tab
15504 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
15505 event.preventDefault();
15506 this.active.focus();
15507 }
15508 },
15509
15510 // Alt+page up/down moves focus to the previous/next tab (and activates)
15511 _handlePageNav: function( event ) {
15512 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
15513 this._activate( this._focusNextTab( this.options.active - 1, false ) );
15514 return true;
15515 }
15516 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
15517 this._activate( this._focusNextTab( this.options.active + 1, true ) );
15518 return true;
15519 }
15520 },
15521
15522 _findNextTab: function( index, goingForward ) {
15523 var lastTabIndex = this.tabs.length - 1;
15524
15525 function constrain() {
15526 if ( index > lastTabIndex ) {
15527 index = 0;
15528 }
15529 if ( index < 0 ) {
15530 index = lastTabIndex;
15531 }
15532 return index;
15533 }
15534
15535 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
15536 index = goingForward ? index + 1 : index - 1;
15537 }
15538
15539 return index;
15540 },
15541
15542 _focusNextTab: function( index, goingForward ) {
15543 index = this._findNextTab( index, goingForward );
15544 this.tabs.eq( index ).focus();
15545 return index;
15546 },
15547
15548 _setOption: function( key, value ) {
15549 if ( key === "active" ) {
15550 // _activate() will handle invalid values and update this.options
15551 this._activate( value );
15552 return;
15553 }
15554
15555 if ( key === "disabled" ) {
15556 // don't use the widget factory's disabled handling
15557 this._setupDisabled( value );
15558 return;
15559 }
15560
15561 this._super( key, value);
15562
15563 if ( key === "collapsible" ) {
15564 this.element.toggleClass( "ui-tabs-collapsible", value );
15565 // Setting collapsible: false while collapsed; open first panel
15566 if ( !value && this.options.active === false ) {
15567 this._activate( 0 );
15568 }
15569 }
15570
15571 if ( key === "event" ) {
15572 this._setupEvents( value );
15573 }
15574
15575 if ( key === "heightStyle" ) {
15576 this._setupHeightStyle( value );
15577 }
15578 },
15579
15580 _sanitizeSelector: function( hash ) {
15581 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
15582 },
15583
15584 refresh: function() {
15585 var options = this.options,
15586 lis = this.tablist.children( ":has(a[href])" );
15587
15588 // get disabled tabs from class attribute from HTML
15589 // this will get converted to a boolean if needed in _refresh()
15590 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
15591 return lis.index( tab );
15592 });
15593
15594 this._processTabs();
15595
15596 // was collapsed or no tabs
15597 if ( options.active === false || !this.anchors.length ) {
15598 options.active = false;
15599 this.active = $();
15600 // was active, but active tab is gone
15601 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
15602 // all remaining tabs are disabled
15603 if ( this.tabs.length === options.disabled.length ) {
15604 options.active = false;
15605 this.active = $();
15606 // activate previous tab
15607 } else {
15608 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
15609 }
15610 // was active, active tab still exists
15611 } else {
15612 // make sure active index is correct
15613 options.active = this.tabs.index( this.active );
15614 }
15615
15616 this._refresh();
15617 },
15618
15619 _refresh: function() {
15620 this._setupDisabled( this.options.disabled );
15621 this._setupEvents( this.options.event );
15622 this._setupHeightStyle( this.options.heightStyle );
15623
15624 this.tabs.not( this.active ).attr({
15625 "aria-selected": "false",
15626 "aria-expanded": "false",
15627 tabIndex: -1
15628 });
15629 this.panels.not( this._getPanelForTab( this.active ) )
15630 .hide()
15631 .attr({
15632 "aria-hidden": "true"
15633 });
15634
15635 // Make sure one tab is in the tab order
15636 if ( !this.active.length ) {
15637 this.tabs.eq( 0 ).attr( "tabIndex", 0 );
15638 } else {
15639 this.active
15640 .addClass( "ui-tabs-active ui-state-active" )
15641 .attr({
15642 "aria-selected": "true",
15643 "aria-expanded": "true",
15644 tabIndex: 0
15645 });
15646 this._getPanelForTab( this.active )
15647 .show()
15648 .attr({
15649 "aria-hidden": "false"
15650 });
15651 }
15652 },
15653
15654 _processTabs: function() {
15655 var that = this,
15656 prevTabs = this.tabs,
15657 prevAnchors = this.anchors,
15658 prevPanels = this.panels;
15659
15660 this.tablist = this._getList()
15661 .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
15662 .attr( "role", "tablist" )
15663
15664 // Prevent users from focusing disabled tabs via click
15665 .delegate( "> li", "mousedown" + this.eventNamespace, function( event ) {
15666 if ( $( this ).is( ".ui-state-disabled" ) ) {
15667 event.preventDefault();
15668 }
15669 })
15670
15671 // support: IE <9
15672 // Preventing the default action in mousedown doesn't prevent IE
15673 // from focusing the element, so if the anchor gets focused, blur.
15674 // We don't have to worry about focusing the previously focused
15675 // element since clicking on a non-focusable element should focus
15676 // the body anyway.
15677 .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() {
15678 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
15679 this.blur();
15680 }
15681 });
15682
15683 this.tabs = this.tablist.find( "> li:has(a[href])" )
15684 .addClass( "ui-state-default ui-corner-top" )
15685 .attr({
15686 role: "tab",
15687 tabIndex: -1
15688 });
15689
15690 this.anchors = this.tabs.map(function() {
15691 return $( "a", this )[ 0 ];
15692 })
15693 .addClass( "ui-tabs-anchor" )
15694 .attr({
15695 role: "presentation",
15696 tabIndex: -1
15697 });
15698
15699 this.panels = $();
15700
15701 this.anchors.each(function( i, anchor ) {
15702 var selector, panel, panelId,
15703 anchorId = $( anchor ).uniqueId().attr( "id" ),
15704 tab = $( anchor ).closest( "li" ),
15705 originalAriaControls = tab.attr( "aria-controls" );
15706
15707 // inline tab
15708 if ( that._isLocal( anchor ) ) {
15709 selector = anchor.hash;
15710 panelId = selector.substring( 1 );
15711 panel = that.element.find( that._sanitizeSelector( selector ) );
15712 // remote tab
15713 } else {
15714 // If the tab doesn't already have aria-controls,
15715 // generate an id by using a throw-away element
15716 panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
15717 selector = "#" + panelId;
15718 panel = that.element.find( selector );
15719 if ( !panel.length ) {
15720 panel = that._createPanel( panelId );
15721 panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
15722 }
15723 panel.attr( "aria-live", "polite" );
15724 }
15725
15726 if ( panel.length) {
15727 that.panels = that.panels.add( panel );
15728 }
15729 if ( originalAriaControls ) {
15730 tab.data( "ui-tabs-aria-controls", originalAriaControls );
15731 }
15732 tab.attr({
15733 "aria-controls": panelId,
15734 "aria-labelledby": anchorId
15735 });
15736 panel.attr( "aria-labelledby", anchorId );
15737 });
15738
15739 this.panels
15740 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
15741 .attr( "role", "tabpanel" );
15742
15743 // Avoid memory leaks (#10056)
15744 if ( prevTabs ) {
15745 this._off( prevTabs.not( this.tabs ) );
15746 this._off( prevAnchors.not( this.anchors ) );
15747 this._off( prevPanels.not( this.panels ) );
15748 }
15749 },
15750
15751 // allow overriding how to find the list for rare usage scenarios (#7715)
15752 _getList: function() {
15753 return this.tablist || this.element.find( "ol,ul" ).eq( 0 );
15754 },
15755
15756 _createPanel: function( id ) {
15757 return $( "<div>" )
15758 .attr( "id", id )
15759 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
15760 .data( "ui-tabs-destroy", true );
15761 },
15762
15763 _setupDisabled: function( disabled ) {
15764 if ( $.isArray( disabled ) ) {
15765 if ( !disabled.length ) {
15766 disabled = false;
15767 } else if ( disabled.length === this.anchors.length ) {
15768 disabled = true;
15769 }
15770 }
15771
15772 // disable tabs
15773 for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {
15774 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
15775 $( li )
15776 .addClass( "ui-state-disabled" )
15777 .attr( "aria-disabled", "true" );
15778 } else {
15779 $( li )
15780 .removeClass( "ui-state-disabled" )
15781 .removeAttr( "aria-disabled" );
15782 }
15783 }
15784
15785 this.options.disabled = disabled;
15786 },
15787
15788 _setupEvents: function( event ) {
15789 var events = {};
15790 if ( event ) {
15791 $.each( event.split(" "), function( index, eventName ) {
15792 events[ eventName ] = "_eventHandler";
15793 });
15794 }
15795
15796 this._off( this.anchors.add( this.tabs ).add( this.panels ) );
15797 // Always prevent the default action, even when disabled
15798 this._on( true, this.anchors, {
15799 click: function( event ) {
15800 event.preventDefault();
15801 }
15802 });
15803 this._on( this.anchors, events );
15804 this._on( this.tabs, { keydown: "_tabKeydown" } );
15805 this._on( this.panels, { keydown: "_panelKeydown" } );
15806
15807 this._focusable( this.tabs );
15808 this._hoverable( this.tabs );
15809 },
15810
15811 _setupHeightStyle: function( heightStyle ) {
15812 var maxHeight,
15813 parent = this.element.parent();
15814
15815 if ( heightStyle === "fill" ) {
15816 maxHeight = parent.height();
15817 maxHeight -= this.element.outerHeight() - this.element.height();
15818
15819 this.element.siblings( ":visible" ).each(function() {
15820 var elem = $( this ),
15821 position = elem.css( "position" );
15822
15823 if ( position === "absolute" || position === "fixed" ) {
15824 return;
15825 }
15826 maxHeight -= elem.outerHeight( true );
15827 });
15828
15829 this.element.children().not( this.panels ).each(function() {
15830 maxHeight -= $( this ).outerHeight( true );
15831 });
15832
15833 this.panels.each(function() {
15834 $( this ).height( Math.max( 0, maxHeight -
15835 $( this ).innerHeight() + $( this ).height() ) );
15836 })
15837 .css( "overflow", "auto" );
15838 } else if ( heightStyle === "auto" ) {
15839 maxHeight = 0;
15840 this.panels.each(function() {
15841 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
15842 }).height( maxHeight );
15843 }
15844 },
15845
15846 _eventHandler: function( event ) {
15847 var options = this.options,
15848 active = this.active,
15849 anchor = $( event.currentTarget ),
15850 tab = anchor.closest( "li" ),
15851 clickedIsActive = tab[ 0 ] === active[ 0 ],
15852 collapsing = clickedIsActive && options.collapsible,
15853 toShow = collapsing ? $() : this._getPanelForTab( tab ),
15854 toHide = !active.length ? $() : this._getPanelForTab( active ),
15855 eventData = {
15856 oldTab: active,
15857 oldPanel: toHide,
15858 newTab: collapsing ? $() : tab,
15859 newPanel: toShow
15860 };
15861
15862 event.preventDefault();
15863
15864 if ( tab.hasClass( "ui-state-disabled" ) ||
15865 // tab is already loading
15866 tab.hasClass( "ui-tabs-loading" ) ||
15867 // can't switch durning an animation
15868 this.running ||
15869 // click on active header, but not collapsible
15870 ( clickedIsActive && !options.collapsible ) ||
15871 // allow canceling activation
15872 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
15873 return;
15874 }
15875
15876 options.active = collapsing ? false : this.tabs.index( tab );
15877
15878 this.active = clickedIsActive ? $() : tab;
15879 if ( this.xhr ) {
15880 this.xhr.abort();
15881 }
15882
15883 if ( !toHide.length && !toShow.length ) {
15884 $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
15885 }
15886
15887 if ( toShow.length ) {
15888 this.load( this.tabs.index( tab ), event );
15889 }
15890 this._toggle( event, eventData );
15891 },
15892
15893 // handles show/hide for selecting tabs
15894 _toggle: function( event, eventData ) {
15895 var that = this,
15896 toShow = eventData.newPanel,
15897 toHide = eventData.oldPanel;
15898
15899 this.running = true;
15900
15901 function complete() {
15902 that.running = false;
15903 that._trigger( "activate", event, eventData );
15904 }
15905
15906 function show() {
15907 eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
15908
15909 if ( toShow.length && that.options.show ) {
15910 that._show( toShow, that.options.show, complete );
15911 } else {
15912 toShow.show();
15913 complete();
15914 }
15915 }
15916
15917 // start out by hiding, then showing, then completing
15918 if ( toHide.length && this.options.hide ) {
15919 this._hide( toHide, this.options.hide, function() {
15920 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
15921 show();
15922 });
15923 } else {
15924 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
15925 toHide.hide();
15926 show();
15927 }
15928
15929 toHide.attr( "aria-hidden", "true" );
15930 eventData.oldTab.attr({
15931 "aria-selected": "false",
15932 "aria-expanded": "false"
15933 });
15934 // If we're switching tabs, remove the old tab from the tab order.
15935 // If we're opening from collapsed state, remove the previous tab from the tab order.
15936 // If we're collapsing, then keep the collapsing tab in the tab order.
15937 if ( toShow.length && toHide.length ) {
15938 eventData.oldTab.attr( "tabIndex", -1 );
15939 } else if ( toShow.length ) {
15940 this.tabs.filter(function() {
15941 return $( this ).attr( "tabIndex" ) === 0;
15942 })
15943 .attr( "tabIndex", -1 );
15944 }
15945
15946 toShow.attr( "aria-hidden", "false" );
15947 eventData.newTab.attr({
15948 "aria-selected": "true",
15949 "aria-expanded": "true",
15950 tabIndex: 0
15951 });
15952 },
15953
15954 _activate: function( index ) {
15955 var anchor,
15956 active = this._findActive( index );
15957
15958 // trying to activate the already active panel
15959 if ( active[ 0 ] === this.active[ 0 ] ) {
15960 return;
15961 }
15962
15963 // trying to collapse, simulate a click on the current active header
15964 if ( !active.length ) {
15965 active = this.active;
15966 }
15967
15968 anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
15969 this._eventHandler({
15970 target: anchor,
15971 currentTarget: anchor,
15972 preventDefault: $.noop
15973 });
15974 },
15975
15976 _findActive: function( index ) {
15977 return index === false ? $() : this.tabs.eq( index );
15978 },
15979
15980 _getIndex: function( index ) {
15981 // meta-function to give users option to provide a href string instead of a numerical index.
15982 if ( typeof index === "string" ) {
15983 index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) );
15984 }
15985
15986 return index;
15987 },
15988
15989 _destroy: function() {
15990 if ( this.xhr ) {
15991 this.xhr.abort();
15992 }
15993
15994 this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" );
15995
15996 this.tablist
15997 .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
15998 .removeAttr( "role" );
15999
16000 this.anchors
16001 .removeClass( "ui-tabs-anchor" )
16002 .removeAttr( "role" )
16003 .removeAttr( "tabIndex" )
16004 .removeUniqueId();
16005
16006 this.tablist.unbind( this.eventNamespace );
16007
16008 this.tabs.add( this.panels ).each(function() {
16009 if ( $.data( this, "ui-tabs-destroy" ) ) {
16010 $( this ).remove();
16011 } else {
16012 $( this )
16013 .removeClass( "ui-state-default ui-state-active ui-state-disabled " +
16014 "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" )
16015 .removeAttr( "tabIndex" )
16016 .removeAttr( "aria-live" )
16017 .removeAttr( "aria-busy" )
16018 .removeAttr( "aria-selected" )
16019 .removeAttr( "aria-labelledby" )
16020 .removeAttr( "aria-hidden" )
16021 .removeAttr( "aria-expanded" )
16022 .removeAttr( "role" );
16023 }
16024 });
16025
16026 this.tabs.each(function() {
16027 var li = $( this ),
16028 prev = li.data( "ui-tabs-aria-controls" );
16029 if ( prev ) {
16030 li
16031 .attr( "aria-controls", prev )
16032 .removeData( "ui-tabs-aria-controls" );
16033 } else {
16034 li.removeAttr( "aria-controls" );
16035 }
16036 });
16037
16038 this.panels.show();
16039
16040 if ( this.options.heightStyle !== "content" ) {
16041 this.panels.css( "height", "" );
16042 }
16043 },
16044
16045 enable: function( index ) {
16046 var disabled = this.options.disabled;
16047 if ( disabled === false ) {
16048 return;
16049 }
16050
16051 if ( index === undefined ) {
16052 disabled = false;
16053 } else {
16054 index = this._getIndex( index );
16055 if ( $.isArray( disabled ) ) {
16056 disabled = $.map( disabled, function( num ) {
16057 return num !== index ? num : null;
16058 });
16059 } else {
16060 disabled = $.map( this.tabs, function( li, num ) {
16061 return num !== index ? num : null;
16062 });
16063 }
16064 }
16065 this._setupDisabled( disabled );
16066 },
16067
16068 disable: function( index ) {
16069 var disabled = this.options.disabled;
16070 if ( disabled === true ) {
16071 return;
16072 }
16073
16074 if ( index === undefined ) {
16075 disabled = true;
16076 } else {
16077 index = this._getIndex( index );
16078 if ( $.inArray( index, disabled ) !== -1 ) {
16079 return;
16080 }
16081 if ( $.isArray( disabled ) ) {
16082 disabled = $.merge( [ index ], disabled ).sort();
16083 } else {
16084 disabled = [ index ];
16085 }
16086 }
16087 this._setupDisabled( disabled );
16088 },
16089
16090 load: function( index, event ) {
16091 index = this._getIndex( index );
16092 var that = this,
16093 tab = this.tabs.eq( index ),
16094 anchor = tab.find( ".ui-tabs-anchor" ),
16095 panel = this._getPanelForTab( tab ),
16096 eventData = {
16097 tab: tab,
16098 panel: panel
16099 };
16100
16101 // not remote
16102 if ( this._isLocal( anchor[ 0 ] ) ) {
16103 return;
16104 }
16105
16106 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
16107
16108 // support: jQuery <1.8
16109 // jQuery <1.8 returns false if the request is canceled in beforeSend,
16110 // but as of 1.8, $.ajax() always returns a jqXHR object.
16111 if ( this.xhr && this.xhr.statusText !== "canceled" ) {
16112 tab.addClass( "ui-tabs-loading" );
16113 panel.attr( "aria-busy", "true" );
16114
16115 this.xhr
16116 .success(function( response ) {
16117 // support: jQuery <1.8
16118 // http://bugs.jquery.com/ticket/11778
16119 setTimeout(function() {
16120 panel.html( response );
16121 that._trigger( "load", event, eventData );
16122 }, 1 );
16123 })
16124 .complete(function( jqXHR, status ) {
16125 // support: jQuery <1.8
16126 // http://bugs.jquery.com/ticket/11778
16127 setTimeout(function() {
16128 if ( status === "abort" ) {
16129 that.panels.stop( false, true );
16130 }
16131
16132 tab.removeClass( "ui-tabs-loading" );
16133 panel.removeAttr( "aria-busy" );
16134
16135 if ( jqXHR === that.xhr ) {
16136 delete that.xhr;
16137 }
16138 }, 1 );
16139 });
16140 }
16141 },
16142
16143 _ajaxSettings: function( anchor, event, eventData ) {
16144 var that = this;
16145 return {
16146 url: anchor.attr( "href" ),
16147 beforeSend: function( jqXHR, settings ) {
16148 return that._trigger( "beforeLoad", event,
16149 $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
16150 }
16151 };
16152 },
16153
16154 _getPanelForTab: function( tab ) {
16155 var id = $( tab ).attr( "aria-controls" );
16156 return this.element.find( this._sanitizeSelector( "#" + id ) );
16157 }
16158 });
16159
16160
16161 /*!
16162 * jQuery UI Tooltip 1.11.3
16163 * http://jqueryui.com
16164 *
16165 * Copyright jQuery Foundation and other contributors
16166 * Released under the MIT license.
16167 * http://jquery.org/license
16168 *
16169 * http://api.jqueryui.com/tooltip/
16170 */
16171
16172
16173 var tooltip = $.widget( "ui.tooltip", {
16174 version: "1.11.3",
16175 options: {
16176 content: function() {
16177 // support: IE<9, Opera in jQuery <1.7
16178 // .text() can't accept undefined, so coerce to a string
16179 var title = $( this ).attr( "title" ) || "";
16180 // Escape title, since we're going from an attribute to raw HTML
16181 return $( "<a>" ).text( title ).html();
16182 },
16183 hide: true,
16184 // Disabled elements have inconsistent behavior across browsers (#8661)
16185 items: "[title]:not([disabled])",
16186 position: {
16187 my: "left top+15",
16188 at: "left bottom",
16189 collision: "flipfit flip"
16190 },
16191 show: true,
16192 tooltipClass: null,
16193 track: false,
16194
16195 // callbacks
16196 close: null,
16197 open: null
16198 },
16199
16200 _addDescribedBy: function( elem, id ) {
16201 var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ );
16202 describedby.push( id );
16203 elem
16204 .data( "ui-tooltip-id", id )
16205 .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
16206 },
16207
16208 _removeDescribedBy: function( elem ) {
16209 var id = elem.data( "ui-tooltip-id" ),
16210 describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ),
16211 index = $.inArray( id, describedby );
16212
16213 if ( index !== -1 ) {
16214 describedby.splice( index, 1 );
16215 }
16216
16217 elem.removeData( "ui-tooltip-id" );
16218 describedby = $.trim( describedby.join( " " ) );
16219 if ( describedby ) {
16220 elem.attr( "aria-describedby", describedby );
16221 } else {
16222 elem.removeAttr( "aria-describedby" );
16223 }
16224 },
16225
16226 _create: function() {
16227 this._on({
16228 mouseover: "open",
16229 focusin: "open"
16230 });
16231
16232 // IDs of generated tooltips, needed for destroy
16233 this.tooltips = {};
16234
16235 // IDs of parent tooltips where we removed the title attribute
16236 this.parents = {};
16237
16238 if ( this.options.disabled ) {
16239 this._disable();
16240 }
16241
16242 // Append the aria-live region so tooltips announce correctly
16243 this.liveRegion = $( "<div>" )
16244 .attr({
16245 role: "log",
16246 "aria-live": "assertive",
16247 "aria-relevant": "additions"
16248 })
16249 .addClass( "ui-helper-hidden-accessible" )
16250 .appendTo( this.document[ 0 ].body );
16251 },
16252
16253 _setOption: function( key, value ) {
16254 var that = this;
16255
16256 if ( key === "disabled" ) {
16257 this[ value ? "_disable" : "_enable" ]();
16258 this.options[ key ] = value;
16259 // disable element style changes
16260 return;
16261 }
16262
16263 this._super( key, value );
16264
16265 if ( key === "content" ) {
16266 $.each( this.tooltips, function( id, tooltipData ) {
16267 that._updateContent( tooltipData.element );
16268 });
16269 }
16270 },
16271
16272 _disable: function() {
16273 var that = this;
16274
16275 // close open tooltips
16276 $.each( this.tooltips, function( id, tooltipData ) {
16277 var event = $.Event( "blur" );
16278 event.target = event.currentTarget = tooltipData.element[ 0 ];
16279 that.close( event, true );
16280 });
16281
16282 // remove title attributes to prevent native tooltips
16283 this.element.find( this.options.items ).addBack().each(function() {
16284 var element = $( this );
16285 if ( element.is( "[title]" ) ) {
16286 element
16287 .data( "ui-tooltip-title", element.attr( "title" ) )
16288 .removeAttr( "title" );
16289 }
16290 });
16291 },
16292
16293 _enable: function() {
16294 // restore title attributes
16295 this.element.find( this.options.items ).addBack().each(function() {
16296 var element = $( this );
16297 if ( element.data( "ui-tooltip-title" ) ) {
16298 element.attr( "title", element.data( "ui-tooltip-title" ) );
16299 }
16300 });
16301 },
16302
16303 open: function( event ) {
16304 var that = this,
16305 target = $( event ? event.target : this.element )
16306 // we need closest here due to mouseover bubbling,
16307 // but always pointing at the same event target
16308 .closest( this.options.items );
16309
16310 // No element to show a tooltip for or the tooltip is already open
16311 if ( !target.length || target.data( "ui-tooltip-id" ) ) {
16312 return;
16313 }
16314
16315 if ( target.attr( "title" ) ) {
16316 target.data( "ui-tooltip-title", target.attr( "title" ) );
16317 }
16318
16319 target.data( "ui-tooltip-open", true );
16320
16321 // kill parent tooltips, custom or native, for hover
16322 if ( event && event.type === "mouseover" ) {
16323 target.parents().each(function() {
16324 var parent = $( this ),
16325 blurEvent;
16326 if ( parent.data( "ui-tooltip-open" ) ) {
16327 blurEvent = $.Event( "blur" );
16328 blurEvent.target = blurEvent.currentTarget = this;
16329 that.close( blurEvent, true );
16330 }
16331 if ( parent.attr( "title" ) ) {
16332 parent.uniqueId();
16333 that.parents[ this.id ] = {
16334 element: this,
16335 title: parent.attr( "title" )
16336 };
16337 parent.attr( "title", "" );
16338 }
16339 });
16340 }
16341
16342 this._updateContent( target, event );
16343 },
16344
16345 _updateContent: function( target, event ) {
16346 var content,
16347 contentOption = this.options.content,
16348 that = this,
16349 eventType = event ? event.type : null;
16350
16351 if ( typeof contentOption === "string" ) {
16352 return this._open( event, target, contentOption );
16353 }
16354
16355 content = contentOption.call( target[0], function( response ) {
16356 // ignore async response if tooltip was closed already
16357 if ( !target.data( "ui-tooltip-open" ) ) {
16358 return;
16359 }
16360 // IE may instantly serve a cached response for ajax requests
16361 // delay this call to _open so the other call to _open runs first
16362 that._delay(function() {
16363 // jQuery creates a special event for focusin when it doesn't
16364 // exist natively. To improve performance, the native event
16365 // object is reused and the type is changed. Therefore, we can't
16366 // rely on the type being correct after the event finished
16367 // bubbling, so we set it back to the previous value. (#8740)
16368 if ( event ) {
16369 event.type = eventType;
16370 }
16371 this._open( event, target, response );
16372 });
16373 });
16374 if ( content ) {
16375 this._open( event, target, content );
16376 }
16377 },
16378
16379 _open: function( event, target, content ) {
16380 var tooltipData, tooltip, events, delayedShow, a11yContent,
16381 positionOption = $.extend( {}, this.options.position );
16382
16383 if ( !content ) {
16384 return;
16385 }
16386
16387 // Content can be updated multiple times. If the tooltip already
16388 // exists, then just update the content and bail.
16389 tooltipData = this._find( target );
16390 if ( tooltipData ) {
16391 tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content );
16392 return;
16393 }
16394
16395 // if we have a title, clear it to prevent the native tooltip
16396 // we have to check first to avoid defining a title if none exists
16397 // (we don't want to cause an element to start matching [title])
16398 //
16399 // We use removeAttr only for key events, to allow IE to export the correct
16400 // accessible attributes. For mouse events, set to empty string to avoid
16401 // native tooltip showing up (happens only when removing inside mouseover).
16402 if ( target.is( "[title]" ) ) {
16403 if ( event && event.type === "mouseover" ) {
16404 target.attr( "title", "" );
16405 } else {
16406 target.removeAttr( "title" );
16407 }
16408 }
16409
16410 tooltipData = this._tooltip( target );
16411 tooltip = tooltipData.tooltip;
16412 this._addDescribedBy( target, tooltip.attr( "id" ) );
16413 tooltip.find( ".ui-tooltip-content" ).html( content );
16414
16415 // Support: Voiceover on OS X, JAWS on IE <= 9
16416 // JAWS announces deletions even when aria-relevant="additions"
16417 // Voiceover will sometimes re-read the entire log region's contents from the beginning
16418 this.liveRegion.children().hide();
16419 if ( content.clone ) {
16420 a11yContent = content.clone();
16421 a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" );
16422 } else {
16423 a11yContent = content;
16424 }
16425 $( "<div>" ).html( a11yContent ).appendTo( this.liveRegion );
16426
16427 function position( event ) {
16428 positionOption.of = event;
16429 if ( tooltip.is( ":hidden" ) ) {
16430 return;
16431 }
16432 tooltip.position( positionOption );
16433 }
16434 if ( this.options.track && event && /^mouse/.test( event.type ) ) {
16435 this._on( this.document, {
16436 mousemove: position
16437 });
16438 // trigger once to override element-relative positioning
16439 position( event );
16440 } else {
16441 tooltip.position( $.extend({
16442 of: target
16443 }, this.options.position ) );
16444 }
16445
16446 tooltip.hide();
16447
16448 this._show( tooltip, this.options.show );
16449 // Handle tracking tooltips that are shown with a delay (#8644). As soon
16450 // as the tooltip is visible, position the tooltip using the most recent
16451 // event.
16452 if ( this.options.show && this.options.show.delay ) {
16453 delayedShow = this.delayedShow = setInterval(function() {
16454 if ( tooltip.is( ":visible" ) ) {
16455 position( positionOption.of );
16456 clearInterval( delayedShow );
16457 }
16458 }, $.fx.interval );
16459 }
16460
16461 this._trigger( "open", event, { tooltip: tooltip } );
16462
16463 events = {
16464 keyup: function( event ) {
16465 if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
16466 var fakeEvent = $.Event(event);
16467 fakeEvent.currentTarget = target[0];
16468 this.close( fakeEvent, true );
16469 }
16470 }
16471 };
16472
16473 // Only bind remove handler for delegated targets. Non-delegated
16474 // tooltips will handle this in destroy.
16475 if ( target[ 0 ] !== this.element[ 0 ] ) {
16476 events.remove = function() {
16477 this._removeTooltip( tooltip );
16478 };
16479 }
16480
16481 if ( !event || event.type === "mouseover" ) {
16482 events.mouseleave = "close";
16483 }
16484 if ( !event || event.type === "focusin" ) {
16485 events.focusout = "close";
16486 }
16487 this._on( true, target, events );
16488 },
16489
16490 close: function( event ) {
16491 var tooltip,
16492 that = this,
16493 target = $( event ? event.currentTarget : this.element ),
16494 tooltipData = this._find( target );
16495
16496 // The tooltip may already be closed
16497 if ( !tooltipData ) {
16498 return;
16499 }
16500
16501 tooltip = tooltipData.tooltip;
16502
16503 // disabling closes the tooltip, so we need to track when we're closing
16504 // to avoid an infinite loop in case the tooltip becomes disabled on close
16505 if ( tooltipData.closing ) {
16506 return;
16507 }
16508
16509 // Clear the interval for delayed tracking tooltips
16510 clearInterval( this.delayedShow );
16511
16512 // only set title if we had one before (see comment in _open())
16513 // If the title attribute has changed since open(), don't restore
16514 if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
16515 target.attr( "title", target.data( "ui-tooltip-title" ) );
16516 }
16517
16518 this._removeDescribedBy( target );
16519
16520 tooltipData.hiding = true;
16521 tooltip.stop( true );
16522 this._hide( tooltip, this.options.hide, function() {
16523 that._removeTooltip( $( this ) );
16524 });
16525
16526 target.removeData( "ui-tooltip-open" );
16527 this._off( target, "mouseleave focusout keyup" );
16528
16529 // Remove 'remove' binding only on delegated targets
16530 if ( target[ 0 ] !== this.element[ 0 ] ) {
16531 this._off( target, "remove" );
16532 }
16533 this._off( this.document, "mousemove" );
16534
16535 if ( event && event.type === "mouseleave" ) {
16536 $.each( this.parents, function( id, parent ) {
16537 $( parent.element ).attr( "title", parent.title );
16538 delete that.parents[ id ];
16539 });
16540 }
16541
16542 tooltipData.closing = true;
16543 this._trigger( "close", event, { tooltip: tooltip } );
16544 if ( !tooltipData.hiding ) {
16545 tooltipData.closing = false;
16546 }
16547 },
16548
16549 _tooltip: function( element ) {
16550 var tooltip = $( "<div>" )
16551 .attr( "role", "tooltip" )
16552 .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " +
16553 ( this.options.tooltipClass || "" ) ),
16554 id = tooltip.uniqueId().attr( "id" );
16555
16556 $( "<div>" )
16557 .addClass( "ui-tooltip-content" )
16558 .appendTo( tooltip );
16559
16560 tooltip.appendTo( this.document[0].body );
16561
16562 return this.tooltips[ id ] = {
16563 element: element,
16564 tooltip: tooltip
16565 };
16566 },
16567
16568 _find: function( target ) {
16569 var id = target.data( "ui-tooltip-id" );
16570 return id ? this.tooltips[ id ] : null;
16571 },
16572
16573 _removeTooltip: function( tooltip ) {
16574 tooltip.remove();
16575 delete this.tooltips[ tooltip.attr( "id" ) ];
16576 },
16577
16578 _destroy: function() {
16579 var that = this;
16580
16581 // close open tooltips
16582 $.each( this.tooltips, function( id, tooltipData ) {
16583 // Delegate to close method to handle common cleanup
16584 var event = $.Event( "blur" ),
16585 element = tooltipData.element;
16586 event.target = event.currentTarget = element[ 0 ];
16587 that.close( event, true );
16588
16589 // Remove immediately; destroying an open tooltip doesn't use the
16590 // hide animation
16591 $( "#" + id ).remove();
16592
16593 // Restore the title
16594 if ( element.data( "ui-tooltip-title" ) ) {
16595 // If the title attribute has changed since open(), don't restore
16596 if ( !element.attr( "title" ) ) {
16597 element.attr( "title", element.data( "ui-tooltip-title" ) );
16598 }
16599 element.removeData( "ui-tooltip-title" );
16600 }
16601 });
16602 this.liveRegion.remove();
16603 }
16604 });
16605
16606
16607
16608 }));