/[svn]/doc/tmpl/js/jquery-ui.js
ViewVC logotype

Contents of /doc/tmpl/js/jquery-ui.js

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2732 - (show annotations) (download) (as text)
Sun Apr 26 20:54:00 2015 UTC (8 years, 11 months ago) by schoenebeck
File MIME type: application/javascript
File size: 471445 byte(s)
* Initial import of doc.linuxsampler.org.

1 /*! jQuery UI - v1.11.4 - 2015-03-11
2 * http://jqueryui.com
3 * Includes: core.js, widget.js, mouse.js, position.js, accordion.js, autocomplete.js, button.js, datepicker.js, dialog.js, draggable.js, droppable.js, effect.js, effect-blind.js, effect-bounce.js, effect-clip.js, effect-drop.js, effect-explode.js, effect-fade.js, effect-fold.js, effect-highlight.js, effect-puff.js, effect-pulsate.js, effect-scale.js, effect-shake.js, effect-size.js, effect-slide.js, effect-transfer.js, menu.js, progressbar.js, resizable.js, selectable.js, selectmenu.js, slider.js, sortable.js, spinner.js, tabs.js, tooltip.js
4 * Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */
5
6 /*
7 * Modifications by Christian Schoenebeck:
8 *
9 * 2015-04-05: Collision detection algorithm now adds a respective
10 * 'ui-collision-*' CSS class to the element, so one can write
11 * separate CSS rules if some widget got flipped.
12 *
13 * 2015-04-06: Tooltips: Added support for HTML markup to "title" attribute.
14 */
15
16 (function( factory ) {
17 if ( typeof define === "function" && define.amd ) {
18
19 // AMD. Register as an anonymous module.
20 define([ "jquery" ], factory );
21 } else {
22
23 // Browser globals
24 factory( jQuery );
25 }
26 }(function( $ ) {
27 /*!
28 * jQuery UI Core 1.11.4
29 * http://jqueryui.com
30 *
31 * Copyright jQuery Foundation and other contributors
32 * Released under the MIT license.
33 * http://jquery.org/license
34 *
35 * http://api.jqueryui.com/category/ui-core/
36 */
37
38
39 // $.ui might exist from components with no dependencies, e.g., $.ui.position
40 $.ui = $.ui || {};
41
42 $.extend( $.ui, {
43 version: "1.11.4",
44
45 keyCode: {
46 BACKSPACE: 8,
47 COMMA: 188,
48 DELETE: 46,
49 DOWN: 40,
50 END: 35,
51 ENTER: 13,
52 ESCAPE: 27,
53 HOME: 36,
54 LEFT: 37,
55 PAGE_DOWN: 34,
56 PAGE_UP: 33,
57 PERIOD: 190,
58 RIGHT: 39,
59 SPACE: 32,
60 TAB: 9,
61 UP: 38
62 }
63 });
64
65 // plugins
66 $.fn.extend({
67 scrollParent: function( includeHidden ) {
68 var position = this.css( "position" ),
69 excludeStaticParent = position === "absolute",
70 overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/,
71 scrollParent = this.parents().filter( function() {
72 var parent = $( this );
73 if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
74 return false;
75 }
76 return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + parent.css( "overflow-x" ) );
77 }).eq( 0 );
78
79 return position === "fixed" || !scrollParent.length ? $( this[ 0 ].ownerDocument || document ) : scrollParent;
80 },
81
82 uniqueId: (function() {
83 var uuid = 0;
84
85 return function() {
86 return this.each(function() {
87 if ( !this.id ) {
88 this.id = "ui-id-" + ( ++uuid );
89 }
90 });
91 };
92 })(),
93
94 removeUniqueId: function() {
95 return this.each(function() {
96 if ( /^ui-id-\d+$/.test( this.id ) ) {
97 $( this ).removeAttr( "id" );
98 }
99 });
100 }
101 });
102
103 // selectors
104 function focusable( element, isTabIndexNotNaN ) {
105 var map, mapName, img,
106 nodeName = element.nodeName.toLowerCase();
107 if ( "area" === nodeName ) {
108 map = element.parentNode;
109 mapName = map.name;
110 if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
111 return false;
112 }
113 img = $( "img[usemap='#" + mapName + "']" )[ 0 ];
114 return !!img && visible( img );
115 }
116 return ( /^(input|select|textarea|button|object)$/.test( nodeName ) ?
117 !element.disabled :
118 "a" === nodeName ?
119 element.href || isTabIndexNotNaN :
120 isTabIndexNotNaN) &&
121 // the element and all of its ancestors must be visible
122 visible( element );
123 }
124
125 function visible( element ) {
126 return $.expr.filters.visible( element ) &&
127 !$( element ).parents().addBack().filter(function() {
128 return $.css( this, "visibility" ) === "hidden";
129 }).length;
130 }
131
132 $.extend( $.expr[ ":" ], {
133 data: $.expr.createPseudo ?
134 $.expr.createPseudo(function( dataName ) {
135 return function( elem ) {
136 return !!$.data( elem, dataName );
137 };
138 }) :
139 // support: jQuery <1.8
140 function( elem, i, match ) {
141 return !!$.data( elem, match[ 3 ] );
142 },
143
144 focusable: function( element ) {
145 return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
146 },
147
148 tabbable: function( element ) {
149 var tabIndex = $.attr( element, "tabindex" ),
150 isTabIndexNaN = isNaN( tabIndex );
151 return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
152 }
153 });
154
155 // support: jQuery <1.8
156 if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
157 $.each( [ "Width", "Height" ], function( i, name ) {
158 var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
159 type = name.toLowerCase(),
160 orig = {
161 innerWidth: $.fn.innerWidth,
162 innerHeight: $.fn.innerHeight,
163 outerWidth: $.fn.outerWidth,
164 outerHeight: $.fn.outerHeight
165 };
166
167 function reduce( elem, size, border, margin ) {
168 $.each( side, function() {
169 size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
170 if ( border ) {
171 size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
172 }
173 if ( margin ) {
174 size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
175 }
176 });
177 return size;
178 }
179
180 $.fn[ "inner" + name ] = function( size ) {
181 if ( size === undefined ) {
182 return orig[ "inner" + name ].call( this );
183 }
184
185 return this.each(function() {
186 $( this ).css( type, reduce( this, size ) + "px" );
187 });
188 };
189
190 $.fn[ "outer" + name] = function( size, margin ) {
191 if ( typeof size !== "number" ) {
192 return orig[ "outer" + name ].call( this, size );
193 }
194
195 return this.each(function() {
196 $( this).css( type, reduce( this, size, true, margin ) + "px" );
197 });
198 };
199 });
200 }
201
202 // support: jQuery <1.8
203 if ( !$.fn.addBack ) {
204 $.fn.addBack = function( selector ) {
205 return this.add( selector == null ?
206 this.prevObject : this.prevObject.filter( selector )
207 );
208 };
209 }
210
211 // support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
212 if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
213 $.fn.removeData = (function( removeData ) {
214 return function( key ) {
215 if ( arguments.length ) {
216 return removeData.call( this, $.camelCase( key ) );
217 } else {
218 return removeData.call( this );
219 }
220 };
221 })( $.fn.removeData );
222 }
223
224 // deprecated
225 $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
226
227 $.fn.extend({
228 focus: (function( orig ) {
229 return function( delay, fn ) {
230 return typeof delay === "number" ?
231 this.each(function() {
232 var elem = this;
233 setTimeout(function() {
234 $( elem ).focus();
235 if ( fn ) {
236 fn.call( elem );
237 }
238 }, delay );
239 }) :
240 orig.apply( this, arguments );
241 };
242 })( $.fn.focus ),
243
244 disableSelection: (function() {
245 var eventType = "onselectstart" in document.createElement( "div" ) ?
246 "selectstart" :
247 "mousedown";
248
249 return function() {
250 return this.bind( eventType + ".ui-disableSelection", function( event ) {
251 event.preventDefault();
252 });
253 };
254 })(),
255
256 enableSelection: function() {
257 return this.unbind( ".ui-disableSelection" );
258 },
259
260 zIndex: function( zIndex ) {
261 if ( zIndex !== undefined ) {
262 return this.css( "zIndex", zIndex );
263 }
264
265 if ( this.length ) {
266 var elem = $( this[ 0 ] ), position, value;
267 while ( elem.length && elem[ 0 ] !== document ) {
268 // Ignore z-index if position is set to a value where z-index is ignored by the browser
269 // This makes behavior of this function consistent across browsers
270 // WebKit always returns auto if the element is positioned
271 position = elem.css( "position" );
272 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
273 // IE returns 0 when zIndex is not specified
274 // other browsers return a string
275 // we ignore the case of nested elements with an explicit value of 0
276 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
277 value = parseInt( elem.css( "zIndex" ), 10 );
278 if ( !isNaN( value ) && value !== 0 ) {
279 return value;
280 }
281 }
282 elem = elem.parent();
283 }
284 }
285
286 return 0;
287 }
288 });
289
290 // $.ui.plugin is deprecated. Use $.widget() extensions instead.
291 $.ui.plugin = {
292 add: function( module, option, set ) {
293 var i,
294 proto = $.ui[ module ].prototype;
295 for ( i in set ) {
296 proto.plugins[ i ] = proto.plugins[ i ] || [];
297 proto.plugins[ i ].push( [ option, set[ i ] ] );
298 }
299 },
300 call: function( instance, name, args, allowDisconnected ) {
301 var i,
302 set = instance.plugins[ name ];
303
304 if ( !set ) {
305 return;
306 }
307
308 if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) ) {
309 return;
310 }
311
312 for ( i = 0; i < set.length; i++ ) {
313 if ( instance.options[ set[ i ][ 0 ] ] ) {
314 set[ i ][ 1 ].apply( instance.element, args );
315 }
316 }
317 }
318 };
319
320
321 /*!
322 * jQuery UI Widget 1.11.4
323 * http://jqueryui.com
324 *
325 * Copyright jQuery Foundation and other contributors
326 * Released under the MIT license.
327 * http://jquery.org/license
328 *
329 * http://api.jqueryui.com/jQuery.widget/
330 */
331
332
333 var widget_uuid = 0,
334 widget_slice = Array.prototype.slice;
335
336 $.cleanData = (function( orig ) {
337 return function( elems ) {
338 var events, elem, i;
339 for ( i = 0; (elem = elems[i]) != null; i++ ) {
340 try {
341
342 // Only trigger remove when necessary to save time
343 events = $._data( elem, "events" );
344 if ( events && events.remove ) {
345 $( elem ).triggerHandler( "remove" );
346 }
347
348 // http://bugs.jquery.com/ticket/8235
349 } catch ( e ) {}
350 }
351 orig( elems );
352 };
353 })( $.cleanData );
354
355 $.widget = function( name, base, prototype ) {
356 var fullName, existingConstructor, constructor, basePrototype,
357 // proxiedPrototype allows the provided prototype to remain unmodified
358 // so that it can be used as a mixin for multiple widgets (#8876)
359 proxiedPrototype = {},
360 namespace = name.split( "." )[ 0 ];
361
362 name = name.split( "." )[ 1 ];
363 fullName = namespace + "-" + name;
364
365 if ( !prototype ) {
366 prototype = base;
367 base = $.Widget;
368 }
369
370 // create selector for plugin
371 $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
372 return !!$.data( elem, fullName );
373 };
374
375 $[ namespace ] = $[ namespace ] || {};
376 existingConstructor = $[ namespace ][ name ];
377 constructor = $[ namespace ][ name ] = function( options, element ) {
378 // allow instantiation without "new" keyword
379 if ( !this._createWidget ) {
380 return new constructor( options, element );
381 }
382
383 // allow instantiation without initializing for simple inheritance
384 // must use "new" keyword (the code above always passes args)
385 if ( arguments.length ) {
386 this._createWidget( options, element );
387 }
388 };
389 // extend with the existing constructor to carry over any static properties
390 $.extend( constructor, existingConstructor, {
391 version: prototype.version,
392 // copy the object used to create the prototype in case we need to
393 // redefine the widget later
394 _proto: $.extend( {}, prototype ),
395 // track widgets that inherit from this widget in case this widget is
396 // redefined after a widget inherits from it
397 _childConstructors: []
398 });
399
400 basePrototype = new base();
401 // we need to make the options hash a property directly on the new instance
402 // otherwise we'll modify the options hash on the prototype that we're
403 // inheriting from
404 basePrototype.options = $.widget.extend( {}, basePrototype.options );
405 $.each( prototype, function( prop, value ) {
406 if ( !$.isFunction( value ) ) {
407 proxiedPrototype[ prop ] = value;
408 return;
409 }
410 proxiedPrototype[ prop ] = (function() {
411 var _super = function() {
412 return base.prototype[ prop ].apply( this, arguments );
413 },
414 _superApply = function( args ) {
415 return base.prototype[ prop ].apply( this, args );
416 };
417 return function() {
418 var __super = this._super,
419 __superApply = this._superApply,
420 returnValue;
421
422 this._super = _super;
423 this._superApply = _superApply;
424
425 returnValue = value.apply( this, arguments );
426
427 this._super = __super;
428 this._superApply = __superApply;
429
430 return returnValue;
431 };
432 })();
433 });
434 constructor.prototype = $.widget.extend( basePrototype, {
435 // TODO: remove support for widgetEventPrefix
436 // always use the name + a colon as the prefix, e.g., draggable:start
437 // don't prefix for widgets that aren't DOM-based
438 widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name
439 }, proxiedPrototype, {
440 constructor: constructor,
441 namespace: namespace,
442 widgetName: name,
443 widgetFullName: fullName
444 });
445
446 // If this widget is being redefined then we need to find all widgets that
447 // are inheriting from it and redefine all of them so that they inherit from
448 // the new version of this widget. We're essentially trying to replace one
449 // level in the prototype chain.
450 if ( existingConstructor ) {
451 $.each( existingConstructor._childConstructors, function( i, child ) {
452 var childPrototype = child.prototype;
453
454 // redefine the child widget using the same prototype that was
455 // originally used, but inherit from the new version of the base
456 $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
457 });
458 // remove the list of existing child constructors from the old constructor
459 // so the old child constructors can be garbage collected
460 delete existingConstructor._childConstructors;
461 } else {
462 base._childConstructors.push( constructor );
463 }
464
465 $.widget.bridge( name, constructor );
466
467 return constructor;
468 };
469
470 $.widget.extend = function( target ) {
471 var input = widget_slice.call( arguments, 1 ),
472 inputIndex = 0,
473 inputLength = input.length,
474 key,
475 value;
476 for ( ; inputIndex < inputLength; inputIndex++ ) {
477 for ( key in input[ inputIndex ] ) {
478 value = input[ inputIndex ][ key ];
479 if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
480 // Clone objects
481 if ( $.isPlainObject( value ) ) {
482 target[ key ] = $.isPlainObject( target[ key ] ) ?
483 $.widget.extend( {}, target[ key ], value ) :
484 // Don't extend strings, arrays, etc. with objects
485 $.widget.extend( {}, value );
486 // Copy everything else by reference
487 } else {
488 target[ key ] = value;
489 }
490 }
491 }
492 }
493 return target;
494 };
495
496 $.widget.bridge = function( name, object ) {
497 var fullName = object.prototype.widgetFullName || name;
498 $.fn[ name ] = function( options ) {
499 var isMethodCall = typeof options === "string",
500 args = widget_slice.call( arguments, 1 ),
501 returnValue = this;
502
503 if ( isMethodCall ) {
504 this.each(function() {
505 var methodValue,
506 instance = $.data( this, fullName );
507 if ( options === "instance" ) {
508 returnValue = instance;
509 return false;
510 }
511 if ( !instance ) {
512 return $.error( "cannot call methods on " + name + " prior to initialization; " +
513 "attempted to call method '" + options + "'" );
514 }
515 if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
516 return $.error( "no such method '" + options + "' for " + name + " widget instance" );
517 }
518 methodValue = instance[ options ].apply( instance, args );
519 if ( methodValue !== instance && methodValue !== undefined ) {
520 returnValue = methodValue && methodValue.jquery ?
521 returnValue.pushStack( methodValue.get() ) :
522 methodValue;
523 return false;
524 }
525 });
526 } else {
527
528 // Allow multiple hashes to be passed on init
529 if ( args.length ) {
530 options = $.widget.extend.apply( null, [ options ].concat(args) );
531 }
532
533 this.each(function() {
534 var instance = $.data( this, fullName );
535 if ( instance ) {
536 instance.option( options || {} );
537 if ( instance._init ) {
538 instance._init();
539 }
540 } else {
541 $.data( this, fullName, new object( options, this ) );
542 }
543 });
544 }
545
546 return returnValue;
547 };
548 };
549
550 $.Widget = function( /* options, element */ ) {};
551 $.Widget._childConstructors = [];
552
553 $.Widget.prototype = {
554 widgetName: "widget",
555 widgetEventPrefix: "",
556 defaultElement: "<div>",
557 options: {
558 disabled: false,
559
560 // callbacks
561 create: null
562 },
563 _createWidget: function( options, element ) {
564 element = $( element || this.defaultElement || this )[ 0 ];
565 this.element = $( element );
566 this.uuid = widget_uuid++;
567 this.eventNamespace = "." + this.widgetName + this.uuid;
568
569 this.bindings = $();
570 this.hoverable = $();
571 this.focusable = $();
572
573 if ( element !== this ) {
574 $.data( element, this.widgetFullName, this );
575 this._on( true, this.element, {
576 remove: function( event ) {
577 if ( event.target === element ) {
578 this.destroy();
579 }
580 }
581 });
582 this.document = $( element.style ?
583 // element within the document
584 element.ownerDocument :
585 // element is window or document
586 element.document || element );
587 this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
588 }
589
590 this.options = $.widget.extend( {},
591 this.options,
592 this._getCreateOptions(),
593 options );
594
595 this._create();
596 this._trigger( "create", null, this._getCreateEventData() );
597 this._init();
598 },
599 _getCreateOptions: $.noop,
600 _getCreateEventData: $.noop,
601 _create: $.noop,
602 _init: $.noop,
603
604 destroy: function() {
605 this._destroy();
606 // we can probably remove the unbind calls in 2.0
607 // all event bindings should go through this._on()
608 this.element
609 .unbind( this.eventNamespace )
610 .removeData( this.widgetFullName )
611 // support: jquery <1.6.3
612 // http://bugs.jquery.com/ticket/9413
613 .removeData( $.camelCase( this.widgetFullName ) );
614 this.widget()
615 .unbind( this.eventNamespace )
616 .removeAttr( "aria-disabled" )
617 .removeClass(
618 this.widgetFullName + "-disabled " +
619 "ui-state-disabled" );
620
621 // clean up events and states
622 this.bindings.unbind( this.eventNamespace );
623 this.hoverable.removeClass( "ui-state-hover" );
624 this.focusable.removeClass( "ui-state-focus" );
625 },
626 _destroy: $.noop,
627
628 widget: function() {
629 return this.element;
630 },
631
632 option: function( key, value ) {
633 var options = key,
634 parts,
635 curOption,
636 i;
637
638 if ( arguments.length === 0 ) {
639 // don't return a reference to the internal hash
640 return $.widget.extend( {}, this.options );
641 }
642
643 if ( typeof key === "string" ) {
644 // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
645 options = {};
646 parts = key.split( "." );
647 key = parts.shift();
648 if ( parts.length ) {
649 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
650 for ( i = 0; i < parts.length - 1; i++ ) {
651 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
652 curOption = curOption[ parts[ i ] ];
653 }
654 key = parts.pop();
655 if ( arguments.length === 1 ) {
656 return curOption[ key ] === undefined ? null : curOption[ key ];
657 }
658 curOption[ key ] = value;
659 } else {
660 if ( arguments.length === 1 ) {
661 return this.options[ key ] === undefined ? null : this.options[ key ];
662 }
663 options[ key ] = value;
664 }
665 }
666
667 this._setOptions( options );
668
669 return this;
670 },
671 _setOptions: function( options ) {
672 var key;
673
674 for ( key in options ) {
675 this._setOption( key, options[ key ] );
676 }
677
678 return this;
679 },
680 _setOption: function( key, value ) {
681 this.options[ key ] = value;
682
683 if ( key === "disabled" ) {
684 this.widget()
685 .toggleClass( this.widgetFullName + "-disabled", !!value );
686
687 // If the widget is becoming disabled, then nothing is interactive
688 if ( value ) {
689 this.hoverable.removeClass( "ui-state-hover" );
690 this.focusable.removeClass( "ui-state-focus" );
691 }
692 }
693
694 return this;
695 },
696
697 enable: function() {
698 return this._setOptions({ disabled: false });
699 },
700 disable: function() {
701 return this._setOptions({ disabled: true });
702 },
703
704 _on: function( suppressDisabledCheck, element, handlers ) {
705 var delegateElement,
706 instance = this;
707
708 // no suppressDisabledCheck flag, shuffle arguments
709 if ( typeof suppressDisabledCheck !== "boolean" ) {
710 handlers = element;
711 element = suppressDisabledCheck;
712 suppressDisabledCheck = false;
713 }
714
715 // no element argument, shuffle and use this.element
716 if ( !handlers ) {
717 handlers = element;
718 element = this.element;
719 delegateElement = this.widget();
720 } else {
721 element = delegateElement = $( element );
722 this.bindings = this.bindings.add( element );
723 }
724
725 $.each( handlers, function( event, handler ) {
726 function handlerProxy() {
727 // allow widgets to customize the disabled handling
728 // - disabled as an array instead of boolean
729 // - disabled class as method for disabling individual parts
730 if ( !suppressDisabledCheck &&
731 ( instance.options.disabled === true ||
732 $( this ).hasClass( "ui-state-disabled" ) ) ) {
733 return;
734 }
735 return ( typeof handler === "string" ? instance[ handler ] : handler )
736 .apply( instance, arguments );
737 }
738
739 // copy the guid so direct unbinding works
740 if ( typeof handler !== "string" ) {
741 handlerProxy.guid = handler.guid =
742 handler.guid || handlerProxy.guid || $.guid++;
743 }
744
745 var match = event.match( /^([\w:-]*)\s*(.*)$/ ),
746 eventName = match[1] + instance.eventNamespace,
747 selector = match[2];
748 if ( selector ) {
749 delegateElement.delegate( selector, eventName, handlerProxy );
750 } else {
751 element.bind( eventName, handlerProxy );
752 }
753 });
754 },
755
756 _off: function( element, eventName ) {
757 eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) +
758 this.eventNamespace;
759 element.unbind( eventName ).undelegate( eventName );
760
761 // Clear the stack to avoid memory leaks (#10056)
762 this.bindings = $( this.bindings.not( element ).get() );
763 this.focusable = $( this.focusable.not( element ).get() );
764 this.hoverable = $( this.hoverable.not( element ).get() );
765 },
766
767 _delay: function( handler, delay ) {
768 function handlerProxy() {
769 return ( typeof handler === "string" ? instance[ handler ] : handler )
770 .apply( instance, arguments );
771 }
772 var instance = this;
773 return setTimeout( handlerProxy, delay || 0 );
774 },
775
776 _hoverable: function( element ) {
777 this.hoverable = this.hoverable.add( element );
778 this._on( element, {
779 mouseenter: function( event ) {
780 $( event.currentTarget ).addClass( "ui-state-hover" );
781 },
782 mouseleave: function( event ) {
783 $( event.currentTarget ).removeClass( "ui-state-hover" );
784 }
785 });
786 },
787
788 _focusable: function( element ) {
789 this.focusable = this.focusable.add( element );
790 this._on( element, {
791 focusin: function( event ) {
792 $( event.currentTarget ).addClass( "ui-state-focus" );
793 },
794 focusout: function( event ) {
795 $( event.currentTarget ).removeClass( "ui-state-focus" );
796 }
797 });
798 },
799
800 _trigger: function( type, event, data ) {
801 var prop, orig,
802 callback = this.options[ type ];
803
804 data = data || {};
805 event = $.Event( event );
806 event.type = ( type === this.widgetEventPrefix ?
807 type :
808 this.widgetEventPrefix + type ).toLowerCase();
809 // the original event may come from any element
810 // so we need to reset the target on the new event
811 event.target = this.element[ 0 ];
812
813 // copy original event properties over to the new event
814 orig = event.originalEvent;
815 if ( orig ) {
816 for ( prop in orig ) {
817 if ( !( prop in event ) ) {
818 event[ prop ] = orig[ prop ];
819 }
820 }
821 }
822
823 this.element.trigger( event, data );
824 return !( $.isFunction( callback ) &&
825 callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
826 event.isDefaultPrevented() );
827 }
828 };
829
830 $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
831 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
832 if ( typeof options === "string" ) {
833 options = { effect: options };
834 }
835 var hasOptions,
836 effectName = !options ?
837 method :
838 options === true || typeof options === "number" ?
839 defaultEffect :
840 options.effect || defaultEffect;
841 options = options || {};
842 if ( typeof options === "number" ) {
843 options = { duration: options };
844 }
845 hasOptions = !$.isEmptyObject( options );
846 options.complete = callback;
847 if ( options.delay ) {
848 element.delay( options.delay );
849 }
850 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
851 element[ method ]( options );
852 } else if ( effectName !== method && element[ effectName ] ) {
853 element[ effectName ]( options.duration, options.easing, callback );
854 } else {
855 element.queue(function( next ) {
856 $( this )[ method ]();
857 if ( callback ) {
858 callback.call( element[ 0 ] );
859 }
860 next();
861 });
862 }
863 };
864 });
865
866 var widget = $.widget;
867
868
869 /*!
870 * jQuery UI Mouse 1.11.4
871 * http://jqueryui.com
872 *
873 * Copyright jQuery Foundation and other contributors
874 * Released under the MIT license.
875 * http://jquery.org/license
876 *
877 * http://api.jqueryui.com/mouse/
878 */
879
880
881 var mouseHandled = false;
882 $( document ).mouseup( function() {
883 mouseHandled = false;
884 });
885
886 var mouse = $.widget("ui.mouse", {
887 version: "1.11.4",
888 options: {
889 cancel: "input,textarea,button,select,option",
890 distance: 1,
891 delay: 0
892 },
893 _mouseInit: function() {
894 var that = this;
895
896 this.element
897 .bind("mousedown." + this.widgetName, function(event) {
898 return that._mouseDown(event);
899 })
900 .bind("click." + this.widgetName, function(event) {
901 if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) {
902 $.removeData(event.target, that.widgetName + ".preventClickEvent");
903 event.stopImmediatePropagation();
904 return false;
905 }
906 });
907
908 this.started = false;
909 },
910
911 // TODO: make sure destroying one instance of mouse doesn't mess with
912 // other instances of mouse
913 _mouseDestroy: function() {
914 this.element.unbind("." + this.widgetName);
915 if ( this._mouseMoveDelegate ) {
916 this.document
917 .unbind("mousemove." + this.widgetName, this._mouseMoveDelegate)
918 .unbind("mouseup." + this.widgetName, this._mouseUpDelegate);
919 }
920 },
921
922 _mouseDown: function(event) {
923 // don't let more than one widget handle mouseStart
924 if ( mouseHandled ) {
925 return;
926 }
927
928 this._mouseMoved = false;
929
930 // we may have missed mouseup (out of window)
931 (this._mouseStarted && this._mouseUp(event));
932
933 this._mouseDownEvent = event;
934
935 var that = this,
936 btnIsLeft = (event.which === 1),
937 // event.target.nodeName works around a bug in IE 8 with
938 // disabled inputs (#7620)
939 elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
940 if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
941 return true;
942 }
943
944 this.mouseDelayMet = !this.options.delay;
945 if (!this.mouseDelayMet) {
946 this._mouseDelayTimer = setTimeout(function() {
947 that.mouseDelayMet = true;
948 }, this.options.delay);
949 }
950
951 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
952 this._mouseStarted = (this._mouseStart(event) !== false);
953 if (!this._mouseStarted) {
954 event.preventDefault();
955 return true;
956 }
957 }
958
959 // Click event may never have fired (Gecko & Opera)
960 if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) {
961 $.removeData(event.target, this.widgetName + ".preventClickEvent");
962 }
963
964 // these delegates are required to keep context
965 this._mouseMoveDelegate = function(event) {
966 return that._mouseMove(event);
967 };
968 this._mouseUpDelegate = function(event) {
969 return that._mouseUp(event);
970 };
971
972 this.document
973 .bind( "mousemove." + this.widgetName, this._mouseMoveDelegate )
974 .bind( "mouseup." + this.widgetName, this._mouseUpDelegate );
975
976 event.preventDefault();
977
978 mouseHandled = true;
979 return true;
980 },
981
982 _mouseMove: function(event) {
983 // Only check for mouseups outside the document if you've moved inside the document
984 // at least once. This prevents the firing of mouseup in the case of IE<9, which will
985 // fire a mousemove event if content is placed under the cursor. See #7778
986 // Support: IE <9
987 if ( this._mouseMoved ) {
988 // IE mouseup check - mouseup happened when mouse was out of window
989 if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) {
990 return this._mouseUp(event);
991
992 // Iframe mouseup check - mouseup occurred in another document
993 } else if ( !event.which ) {
994 return this._mouseUp( event );
995 }
996 }
997
998 if ( event.which || event.button ) {
999 this._mouseMoved = true;
1000 }
1001
1002 if (this._mouseStarted) {
1003 this._mouseDrag(event);
1004 return event.preventDefault();
1005 }
1006
1007 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
1008 this._mouseStarted =
1009 (this._mouseStart(this._mouseDownEvent, event) !== false);
1010 (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
1011 }
1012
1013 return !this._mouseStarted;
1014 },
1015
1016 _mouseUp: function(event) {
1017 this.document
1018 .unbind( "mousemove." + this.widgetName, this._mouseMoveDelegate )
1019 .unbind( "mouseup." + this.widgetName, this._mouseUpDelegate );
1020
1021 if (this._mouseStarted) {
1022 this._mouseStarted = false;
1023
1024 if (event.target === this._mouseDownEvent.target) {
1025 $.data(event.target, this.widgetName + ".preventClickEvent", true);
1026 }
1027
1028 this._mouseStop(event);
1029 }
1030
1031 mouseHandled = false;
1032 return false;
1033 },
1034
1035 _mouseDistanceMet: function(event) {
1036 return (Math.max(
1037 Math.abs(this._mouseDownEvent.pageX - event.pageX),
1038 Math.abs(this._mouseDownEvent.pageY - event.pageY)
1039 ) >= this.options.distance
1040 );
1041 },
1042
1043 _mouseDelayMet: function(/* event */) {
1044 return this.mouseDelayMet;
1045 },
1046
1047 // These are placeholder methods, to be overriden by extending plugin
1048 _mouseStart: function(/* event */) {},
1049 _mouseDrag: function(/* event */) {},
1050 _mouseStop: function(/* event */) {},
1051 _mouseCapture: function(/* event */) { return true; }
1052 });
1053
1054
1055 /*!
1056 * jQuery UI Position 1.11.4
1057 * http://jqueryui.com
1058 *
1059 * Copyright jQuery Foundation and other contributors
1060 * Released under the MIT license.
1061 * http://jquery.org/license
1062 *
1063 * http://api.jqueryui.com/position/
1064 */
1065
1066 (function() {
1067
1068 $.ui = $.ui || {};
1069
1070 var cachedScrollbarWidth, supportsOffsetFractions,
1071 max = Math.max,
1072 abs = Math.abs,
1073 round = Math.round,
1074 rhorizontal = /left|center|right/,
1075 rvertical = /top|center|bottom/,
1076 roffset = /[\+\-]\d+(\.[\d]+)?%?/,
1077 rposition = /^\w+/,
1078 rpercent = /%$/,
1079 _position = $.fn.position;
1080
1081 function getOffsets( offsets, width, height ) {
1082 return [
1083 parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
1084 parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
1085 ];
1086 }
1087
1088 function parseCss( element, property ) {
1089 return parseInt( $.css( element, property ), 10 ) || 0;
1090 }
1091
1092 function getDimensions( elem ) {
1093 var raw = elem[0];
1094 if ( raw.nodeType === 9 ) {
1095 return {
1096 width: elem.width(),
1097 height: elem.height(),
1098 offset: { top: 0, left: 0 }
1099 };
1100 }
1101 if ( $.isWindow( raw ) ) {
1102 return {
1103 width: elem.width(),
1104 height: elem.height(),
1105 offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
1106 };
1107 }
1108 if ( raw.preventDefault ) {
1109 return {
1110 width: 0,
1111 height: 0,
1112 offset: { top: raw.pageY, left: raw.pageX }
1113 };
1114 }
1115 return {
1116 width: elem.outerWidth(),
1117 height: elem.outerHeight(),
1118 offset: elem.offset()
1119 };
1120 }
1121
1122 $.position = {
1123 scrollbarWidth: function() {
1124 if ( cachedScrollbarWidth !== undefined ) {
1125 return cachedScrollbarWidth;
1126 }
1127 var w1, w2,
1128 div = $( "<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
1129 innerDiv = div.children()[0];
1130
1131 $( "body" ).append( div );
1132 w1 = innerDiv.offsetWidth;
1133 div.css( "overflow", "scroll" );
1134
1135 w2 = innerDiv.offsetWidth;
1136
1137 if ( w1 === w2 ) {
1138 w2 = div[0].clientWidth;
1139 }
1140
1141 div.remove();
1142
1143 return (cachedScrollbarWidth = w1 - w2);
1144 },
1145 getScrollInfo: function( within ) {
1146 var overflowX = within.isWindow || within.isDocument ? "" :
1147 within.element.css( "overflow-x" ),
1148 overflowY = within.isWindow || within.isDocument ? "" :
1149 within.element.css( "overflow-y" ),
1150 hasOverflowX = overflowX === "scroll" ||
1151 ( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
1152 hasOverflowY = overflowY === "scroll" ||
1153 ( overflowY === "auto" && within.height < within.element[0].scrollHeight );
1154 return {
1155 width: hasOverflowY ? $.position.scrollbarWidth() : 0,
1156 height: hasOverflowX ? $.position.scrollbarWidth() : 0
1157 };
1158 },
1159 getWithinInfo: function( element ) {
1160 var withinElement = $( element || window ),
1161 isWindow = $.isWindow( withinElement[0] ),
1162 isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9;
1163 return {
1164 element: withinElement,
1165 isWindow: isWindow,
1166 isDocument: isDocument,
1167 offset: withinElement.offset() || { left: 0, top: 0 },
1168 scrollLeft: withinElement.scrollLeft(),
1169 scrollTop: withinElement.scrollTop(),
1170
1171 // support: jQuery 1.6.x
1172 // jQuery 1.6 doesn't support .outerWidth/Height() on documents or windows
1173 width: isWindow || isDocument ? withinElement.width() : withinElement.outerWidth(),
1174 height: isWindow || isDocument ? withinElement.height() : withinElement.outerHeight()
1175 };
1176 }
1177 };
1178
1179 $.fn.position = function( options ) {
1180 if ( !options || !options.of ) {
1181 return _position.apply( this, arguments );
1182 }
1183
1184 // make a copy, we don't want to modify arguments
1185 options = $.extend( {}, options );
1186
1187 var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
1188 target = $( options.of ),
1189 within = $.position.getWithinInfo( options.within ),
1190 scrollInfo = $.position.getScrollInfo( within ),
1191 collision = ( options.collision || "flip" ).split( " " ),
1192 offsets = {};
1193
1194 dimensions = getDimensions( target );
1195 if ( target[0].preventDefault ) {
1196 // force left top to allow flipping
1197 options.at = "left top";
1198 }
1199 targetWidth = dimensions.width;
1200 targetHeight = dimensions.height;
1201 targetOffset = dimensions.offset;
1202 // clone to reuse original targetOffset later
1203 basePosition = $.extend( {}, targetOffset );
1204
1205 // force my and at to have valid horizontal and vertical positions
1206 // if a value is missing or invalid, it will be converted to center
1207 $.each( [ "my", "at" ], function() {
1208 var pos = ( options[ this ] || "" ).split( " " ),
1209 horizontalOffset,
1210 verticalOffset;
1211
1212 if ( pos.length === 1) {
1213 pos = rhorizontal.test( pos[ 0 ] ) ?
1214 pos.concat( [ "center" ] ) :
1215 rvertical.test( pos[ 0 ] ) ?
1216 [ "center" ].concat( pos ) :
1217 [ "center", "center" ];
1218 }
1219 pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
1220 pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
1221
1222 // calculate offsets
1223 horizontalOffset = roffset.exec( pos[ 0 ] );
1224 verticalOffset = roffset.exec( pos[ 1 ] );
1225 offsets[ this ] = [
1226 horizontalOffset ? horizontalOffset[ 0 ] : 0,
1227 verticalOffset ? verticalOffset[ 0 ] : 0
1228 ];
1229
1230 // reduce to just the positions without the offsets
1231 options[ this ] = [
1232 rposition.exec( pos[ 0 ] )[ 0 ],
1233 rposition.exec( pos[ 1 ] )[ 0 ]
1234 ];
1235 });
1236
1237 // normalize collision option
1238 if ( collision.length === 1 ) {
1239 collision[ 1 ] = collision[ 0 ];
1240 }
1241
1242 if ( options.at[ 0 ] === "right" ) {
1243 basePosition.left += targetWidth;
1244 } else if ( options.at[ 0 ] === "center" ) {
1245 basePosition.left += targetWidth / 2;
1246 }
1247
1248 if ( options.at[ 1 ] === "bottom" ) {
1249 basePosition.top += targetHeight;
1250 } else if ( options.at[ 1 ] === "center" ) {
1251 basePosition.top += targetHeight / 2;
1252 }
1253
1254 atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
1255 basePosition.left += atOffset[ 0 ];
1256 basePosition.top += atOffset[ 1 ];
1257
1258 return this.each(function() {
1259 var collisionPosition, using,
1260 elem = $( this ),
1261 elemWidth = elem.outerWidth(),
1262 elemHeight = elem.outerHeight(),
1263 marginLeft = parseCss( this, "marginLeft" ),
1264 marginTop = parseCss( this, "marginTop" ),
1265 collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
1266 collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
1267 position = $.extend( {}, basePosition ),
1268 myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
1269
1270 if ( options.my[ 0 ] === "right" ) {
1271 position.left -= elemWidth;
1272 } else if ( options.my[ 0 ] === "center" ) {
1273 position.left -= elemWidth / 2;
1274 }
1275
1276 if ( options.my[ 1 ] === "bottom" ) {
1277 position.top -= elemHeight;
1278 } else if ( options.my[ 1 ] === "center" ) {
1279 position.top -= elemHeight / 2;
1280 }
1281
1282 position.left += myOffset[ 0 ];
1283 position.top += myOffset[ 1 ];
1284
1285 // if the browser doesn't support fractions, then round for consistent results
1286 if ( !supportsOffsetFractions ) {
1287 position.left = round( position.left );
1288 position.top = round( position.top );
1289 }
1290
1291 collisionPosition = {
1292 marginLeft: marginLeft,
1293 marginTop: marginTop
1294 };
1295
1296 $.each( [ "left", "top" ], function( i, dir ) {
1297 if ( $.ui.position[ collision[ i ] ] ) {
1298 $.ui.position[ collision[ i ] ][ dir ]( position, {
1299 targetWidth: targetWidth,
1300 targetHeight: targetHeight,
1301 elemWidth: elemWidth,
1302 elemHeight: elemHeight,
1303 collisionPosition: collisionPosition,
1304 collisionWidth: collisionWidth,
1305 collisionHeight: collisionHeight,
1306 offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
1307 my: options.my,
1308 at: options.at,
1309 within: within,
1310 elem: elem
1311 });
1312 }
1313 });
1314
1315 if ( options.using ) {
1316 // adds feedback as second argument to using callback, if present
1317 using = function( props ) {
1318 var left = targetOffset.left - position.left,
1319 right = left + targetWidth - elemWidth,
1320 top = targetOffset.top - position.top,
1321 bottom = top + targetHeight - elemHeight,
1322 feedback = {
1323 target: {
1324 element: target,
1325 left: targetOffset.left,
1326 top: targetOffset.top,
1327 width: targetWidth,
1328 height: targetHeight
1329 },
1330 element: {
1331 element: elem,
1332 left: position.left,
1333 top: position.top,
1334 width: elemWidth,
1335 height: elemHeight
1336 },
1337 horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
1338 vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
1339 };
1340 if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
1341 feedback.horizontal = "center";
1342 }
1343 if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
1344 feedback.vertical = "middle";
1345 }
1346 if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
1347 feedback.important = "horizontal";
1348 } else {
1349 feedback.important = "vertical";
1350 }
1351 options.using.call( this, props, feedback );
1352 };
1353 }
1354
1355 elem.offset( $.extend( position, { using: using } ) );
1356 });
1357 };
1358
1359 $.ui.position = {
1360 fit: {
1361 left: function( position, data ) {
1362 var within = data.within,
1363 withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
1364 outerWidth = within.width,
1365 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1366 overLeft = withinOffset - collisionPosLeft,
1367 overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
1368 newOverRight;
1369
1370 // element is wider than within
1371 if ( data.collisionWidth > outerWidth ) {
1372 // element is initially over the left side of within
1373 if ( overLeft > 0 && overRight <= 0 ) {
1374 newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
1375 position.left += overLeft - newOverRight;
1376 // element is initially over right side of within
1377 } else if ( overRight > 0 && overLeft <= 0 ) {
1378 position.left = withinOffset;
1379 // element is initially over both left and right sides of within
1380 } else {
1381 if ( overLeft > overRight ) {
1382 position.left = withinOffset + outerWidth - data.collisionWidth;
1383 } else {
1384 position.left = withinOffset;
1385 }
1386 }
1387 // too far left -> align with left edge
1388 } else if ( overLeft > 0 ) {
1389 position.left += overLeft;
1390 // too far right -> align with right edge
1391 } else if ( overRight > 0 ) {
1392 position.left -= overRight;
1393 // adjust based on position and margin
1394 } else {
1395 position.left = max( position.left - collisionPosLeft, position.left );
1396 }
1397 },
1398 top: function( position, data ) {
1399 var within = data.within,
1400 withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
1401 outerHeight = data.within.height,
1402 collisionPosTop = position.top - data.collisionPosition.marginTop,
1403 overTop = withinOffset - collisionPosTop,
1404 overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
1405 newOverBottom;
1406
1407 // element is taller than within
1408 if ( data.collisionHeight > outerHeight ) {
1409 // element is initially over the top of within
1410 if ( overTop > 0 && overBottom <= 0 ) {
1411 newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
1412 position.top += overTop - newOverBottom;
1413 // element is initially over bottom of within
1414 } else if ( overBottom > 0 && overTop <= 0 ) {
1415 position.top = withinOffset;
1416 // element is initially over both top and bottom of within
1417 } else {
1418 if ( overTop > overBottom ) {
1419 position.top = withinOffset + outerHeight - data.collisionHeight;
1420 } else {
1421 position.top = withinOffset;
1422 }
1423 }
1424 // too far up -> align with top
1425 } else if ( overTop > 0 ) {
1426 position.top += overTop;
1427 // too far down -> align with bottom edge
1428 } else if ( overBottom > 0 ) {
1429 position.top -= overBottom;
1430 // adjust based on position and margin
1431 } else {
1432 position.top = max( position.top - collisionPosTop, position.top );
1433 }
1434 }
1435 },
1436 flip: {
1437 left: function( position, data ) {
1438 var within = data.within,
1439 withinOffset = within.offset.left + within.scrollLeft,
1440 outerWidth = within.width,
1441 offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
1442 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1443 overLeft = collisionPosLeft - offsetLeft,
1444 overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
1445 myOffset = data.my[ 0 ] === "left" ?
1446 -data.elemWidth :
1447 data.my[ 0 ] === "right" ?
1448 data.elemWidth :
1449 0,
1450 atOffset = data.at[ 0 ] === "left" ?
1451 data.targetWidth :
1452 data.at[ 0 ] === "right" ?
1453 -data.targetWidth :
1454 0,
1455 offset = -2 * data.offset[ 0 ],
1456 newOverRight,
1457 newOverLeft;
1458
1459 if ( overLeft < 0 ) {
1460 newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
1461 if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
1462 position.left += myOffset + atOffset + offset;
1463 }
1464 $(data.elem).addClass('ui-collision-left');
1465 } else if ( overRight > 0 ) {
1466 newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
1467 if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
1468 position.left += myOffset + atOffset + offset;
1469 }
1470 $(data.elem).addClass('ui-collision-right');
1471 } else {
1472 $(data.elem).addClass('ui-no-horizontal-collision');
1473 }
1474 },
1475 top: function( position, data ) {
1476 var within = data.within,
1477 withinOffset = within.offset.top + within.scrollTop,
1478 outerHeight = within.height,
1479 offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
1480 collisionPosTop = position.top - data.collisionPosition.marginTop,
1481 overTop = collisionPosTop - offsetTop,
1482 overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
1483 top = data.my[ 1 ] === "top",
1484 myOffset = top ?
1485 -data.elemHeight :
1486 data.my[ 1 ] === "bottom" ?
1487 data.elemHeight :
1488 0,
1489 atOffset = data.at[ 1 ] === "top" ?
1490 data.targetHeight :
1491 data.at[ 1 ] === "bottom" ?
1492 -data.targetHeight :
1493 0,
1494 offset = -2 * data.offset[ 1 ],
1495 newOverTop,
1496 newOverBottom;
1497 if ( overTop < 0 ) {
1498 newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
1499 if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) {
1500 position.top += myOffset + atOffset + offset;
1501 }
1502 $(data.elem).addClass('ui-collision-top');
1503 } else if ( overBottom > 0 ) {
1504 newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
1505 if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) {
1506 position.top += myOffset + atOffset + offset;
1507 }
1508 $(data.elem).addClass('ui-collision-bottom');
1509 } else {
1510 $(data.elem).addClass('ui-no-vertical-collision');
1511 }
1512 }
1513 },
1514 flipfit: {
1515 left: function() {
1516 $.ui.position.flip.left.apply( this, arguments );
1517 $.ui.position.fit.left.apply( this, arguments );
1518 },
1519 top: function() {
1520 $.ui.position.flip.top.apply( this, arguments );
1521 $.ui.position.fit.top.apply( this, arguments );
1522 }
1523 }
1524 };
1525
1526 // fraction support test
1527 (function() {
1528 var testElement, testElementParent, testElementStyle, offsetLeft, i,
1529 body = document.getElementsByTagName( "body" )[ 0 ],
1530 div = document.createElement( "div" );
1531
1532 //Create a "fake body" for testing based on method used in jQuery.support
1533 testElement = document.createElement( body ? "div" : "body" );
1534 testElementStyle = {
1535 visibility: "hidden",
1536 width: 0,
1537 height: 0,
1538 border: 0,
1539 margin: 0,
1540 background: "none"
1541 };
1542 if ( body ) {
1543 $.extend( testElementStyle, {
1544 position: "absolute",
1545 left: "-1000px",
1546 top: "-1000px"
1547 });
1548 }
1549 for ( i in testElementStyle ) {
1550 testElement.style[ i ] = testElementStyle[ i ];
1551 }
1552 testElement.appendChild( div );
1553 testElementParent = body || document.documentElement;
1554 testElementParent.insertBefore( testElement, testElementParent.firstChild );
1555
1556 div.style.cssText = "position: absolute; left: 10.7432222px;";
1557
1558 offsetLeft = $( div ).offset().left;
1559 supportsOffsetFractions = offsetLeft > 10 && offsetLeft < 11;
1560
1561 testElement.innerHTML = "";
1562 testElementParent.removeChild( testElement );
1563 })();
1564
1565 })();
1566
1567 var position = $.ui.position;
1568
1569
1570 /*!
1571 * jQuery UI Accordion 1.11.4
1572 * http://jqueryui.com
1573 *
1574 * Copyright jQuery Foundation and other contributors
1575 * Released under the MIT license.
1576 * http://jquery.org/license
1577 *
1578 * http://api.jqueryui.com/accordion/
1579 */
1580
1581
1582 var accordion = $.widget( "ui.accordion", {
1583 version: "1.11.4",
1584 options: {
1585 active: 0,
1586 animate: {},
1587 collapsible: false,
1588 event: "click",
1589 header: "> li > :first-child,> :not(li):even",
1590 heightStyle: "auto",
1591 icons: {
1592 activeHeader: "ui-icon-triangle-1-s",
1593 header: "ui-icon-triangle-1-e"
1594 },
1595
1596 // callbacks
1597 activate: null,
1598 beforeActivate: null
1599 },
1600
1601 hideProps: {
1602 borderTopWidth: "hide",
1603 borderBottomWidth: "hide",
1604 paddingTop: "hide",
1605 paddingBottom: "hide",
1606 height: "hide"
1607 },
1608
1609 showProps: {
1610 borderTopWidth: "show",
1611 borderBottomWidth: "show",
1612 paddingTop: "show",
1613 paddingBottom: "show",
1614 height: "show"
1615 },
1616
1617 _create: function() {
1618 var options = this.options;
1619 this.prevShow = this.prevHide = $();
1620 this.element.addClass( "ui-accordion ui-widget ui-helper-reset" )
1621 // ARIA
1622 .attr( "role", "tablist" );
1623
1624 // don't allow collapsible: false and active: false / null
1625 if ( !options.collapsible && (options.active === false || options.active == null) ) {
1626 options.active = 0;
1627 }
1628
1629 this._processPanels();
1630 // handle negative values
1631 if ( options.active < 0 ) {
1632 options.active += this.headers.length;
1633 }
1634 this._refresh();
1635 },
1636
1637 _getCreateEventData: function() {
1638 return {
1639 header: this.active,
1640 panel: !this.active.length ? $() : this.active.next()
1641 };
1642 },
1643
1644 _createIcons: function() {
1645 var icons = this.options.icons;
1646 if ( icons ) {
1647 $( "<span>" )
1648 .addClass( "ui-accordion-header-icon ui-icon " + icons.header )
1649 .prependTo( this.headers );
1650 this.active.children( ".ui-accordion-header-icon" )
1651 .removeClass( icons.header )
1652 .addClass( icons.activeHeader );
1653 this.headers.addClass( "ui-accordion-icons" );
1654 }
1655 },
1656
1657 _destroyIcons: function() {
1658 this.headers
1659 .removeClass( "ui-accordion-icons" )
1660 .children( ".ui-accordion-header-icon" )
1661 .remove();
1662 },
1663
1664 _destroy: function() {
1665 var contents;
1666
1667 // clean up main element
1668 this.element
1669 .removeClass( "ui-accordion ui-widget ui-helper-reset" )
1670 .removeAttr( "role" );
1671
1672 // clean up headers
1673 this.headers
1674 .removeClass( "ui-accordion-header ui-accordion-header-active ui-state-default " +
1675 "ui-corner-all ui-state-active ui-state-disabled ui-corner-top" )
1676 .removeAttr( "role" )
1677 .removeAttr( "aria-expanded" )
1678 .removeAttr( "aria-selected" )
1679 .removeAttr( "aria-controls" )
1680 .removeAttr( "tabIndex" )
1681 .removeUniqueId();
1682
1683 this._destroyIcons();
1684
1685 // clean up content panels
1686 contents = this.headers.next()
1687 .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom " +
1688 "ui-accordion-content ui-accordion-content-active ui-state-disabled" )
1689 .css( "display", "" )
1690 .removeAttr( "role" )
1691 .removeAttr( "aria-hidden" )
1692 .removeAttr( "aria-labelledby" )
1693 .removeUniqueId();
1694
1695 if ( this.options.heightStyle !== "content" ) {
1696 contents.css( "height", "" );
1697 }
1698 },
1699
1700 _setOption: function( key, value ) {
1701 if ( key === "active" ) {
1702 // _activate() will handle invalid values and update this.options
1703 this._activate( value );
1704 return;
1705 }
1706
1707 if ( key === "event" ) {
1708 if ( this.options.event ) {
1709 this._off( this.headers, this.options.event );
1710 }
1711 this._setupEvents( value );
1712 }
1713
1714 this._super( key, value );
1715
1716 // setting collapsible: false while collapsed; open first panel
1717 if ( key === "collapsible" && !value && this.options.active === false ) {
1718 this._activate( 0 );
1719 }
1720
1721 if ( key === "icons" ) {
1722 this._destroyIcons();
1723 if ( value ) {
1724 this._createIcons();
1725 }
1726 }
1727
1728 // #5332 - opacity doesn't cascade to positioned elements in IE
1729 // so we need to add the disabled class to the headers and panels
1730 if ( key === "disabled" ) {
1731 this.element
1732 .toggleClass( "ui-state-disabled", !!value )
1733 .attr( "aria-disabled", value );
1734 this.headers.add( this.headers.next() )
1735 .toggleClass( "ui-state-disabled", !!value );
1736 }
1737 },
1738
1739 _keydown: function( event ) {
1740 if ( event.altKey || event.ctrlKey ) {
1741 return;
1742 }
1743
1744 var keyCode = $.ui.keyCode,
1745 length = this.headers.length,
1746 currentIndex = this.headers.index( event.target ),
1747 toFocus = false;
1748
1749 switch ( event.keyCode ) {
1750 case keyCode.RIGHT:
1751 case keyCode.DOWN:
1752 toFocus = this.headers[ ( currentIndex + 1 ) % length ];
1753 break;
1754 case keyCode.LEFT:
1755 case keyCode.UP:
1756 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
1757 break;
1758 case keyCode.SPACE:
1759 case keyCode.ENTER:
1760 this._eventHandler( event );
1761 break;
1762 case keyCode.HOME:
1763 toFocus = this.headers[ 0 ];
1764 break;
1765 case keyCode.END:
1766 toFocus = this.headers[ length - 1 ];
1767 break;
1768 }
1769
1770 if ( toFocus ) {
1771 $( event.target ).attr( "tabIndex", -1 );
1772 $( toFocus ).attr( "tabIndex", 0 );
1773 toFocus.focus();
1774 event.preventDefault();
1775 }
1776 },
1777
1778 _panelKeyDown: function( event ) {
1779 if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
1780 $( event.currentTarget ).prev().focus();
1781 }
1782 },
1783
1784 refresh: function() {
1785 var options = this.options;
1786 this._processPanels();
1787
1788 // was collapsed or no panel
1789 if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) {
1790 options.active = false;
1791 this.active = $();
1792 // active false only when collapsible is true
1793 } else if ( options.active === false ) {
1794 this._activate( 0 );
1795 // was active, but active panel is gone
1796 } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
1797 // all remaining panel are disabled
1798 if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) {
1799 options.active = false;
1800 this.active = $();
1801 // activate previous panel
1802 } else {
1803 this._activate( Math.max( 0, options.active - 1 ) );
1804 }
1805 // was active, active panel still exists
1806 } else {
1807 // make sure active index is correct
1808 options.active = this.headers.index( this.active );
1809 }
1810
1811 this._destroyIcons();
1812
1813 this._refresh();
1814 },
1815
1816 _processPanels: function() {
1817 var prevHeaders = this.headers,
1818 prevPanels = this.panels;
1819
1820 this.headers = this.element.find( this.options.header )
1821 .addClass( "ui-accordion-header ui-state-default ui-corner-all" );
1822
1823 this.panels = this.headers.next()
1824 .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
1825 .filter( ":not(.ui-accordion-content-active)" )
1826 .hide();
1827
1828 // Avoid memory leaks (#10056)
1829 if ( prevPanels ) {
1830 this._off( prevHeaders.not( this.headers ) );
1831 this._off( prevPanels.not( this.panels ) );
1832 }
1833 },
1834
1835 _refresh: function() {
1836 var maxHeight,
1837 options = this.options,
1838 heightStyle = options.heightStyle,
1839 parent = this.element.parent();
1840
1841 this.active = this._findActive( options.active )
1842 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" )
1843 .removeClass( "ui-corner-all" );
1844 this.active.next()
1845 .addClass( "ui-accordion-content-active" )
1846 .show();
1847
1848 this.headers
1849 .attr( "role", "tab" )
1850 .each(function() {
1851 var header = $( this ),
1852 headerId = header.uniqueId().attr( "id" ),
1853 panel = header.next(),
1854 panelId = panel.uniqueId().attr( "id" );
1855 header.attr( "aria-controls", panelId );
1856 panel.attr( "aria-labelledby", headerId );
1857 })
1858 .next()
1859 .attr( "role", "tabpanel" );
1860
1861 this.headers
1862 .not( this.active )
1863 .attr({
1864 "aria-selected": "false",
1865 "aria-expanded": "false",
1866 tabIndex: -1
1867 })
1868 .next()
1869 .attr({
1870 "aria-hidden": "true"
1871 })
1872 .hide();
1873
1874 // make sure at least one header is in the tab order
1875 if ( !this.active.length ) {
1876 this.headers.eq( 0 ).attr( "tabIndex", 0 );
1877 } else {
1878 this.active.attr({
1879 "aria-selected": "true",
1880 "aria-expanded": "true",
1881 tabIndex: 0
1882 })
1883 .next()
1884 .attr({
1885 "aria-hidden": "false"
1886 });
1887 }
1888
1889 this._createIcons();
1890
1891 this._setupEvents( options.event );
1892
1893 if ( heightStyle === "fill" ) {
1894 maxHeight = parent.height();
1895 this.element.siblings( ":visible" ).each(function() {
1896 var elem = $( this ),
1897 position = elem.css( "position" );
1898
1899 if ( position === "absolute" || position === "fixed" ) {
1900 return;
1901 }
1902 maxHeight -= elem.outerHeight( true );
1903 });
1904
1905 this.headers.each(function() {
1906 maxHeight -= $( this ).outerHeight( true );
1907 });
1908
1909 this.headers.next()
1910 .each(function() {
1911 $( this ).height( Math.max( 0, maxHeight -
1912 $( this ).innerHeight() + $( this ).height() ) );
1913 })
1914 .css( "overflow", "auto" );
1915 } else if ( heightStyle === "auto" ) {
1916 maxHeight = 0;
1917 this.headers.next()
1918 .each(function() {
1919 maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
1920 })
1921 .height( maxHeight );
1922 }
1923 },
1924
1925 _activate: function( index ) {
1926 var active = this._findActive( index )[ 0 ];
1927
1928 // trying to activate the already active panel
1929 if ( active === this.active[ 0 ] ) {
1930 return;
1931 }
1932
1933 // trying to collapse, simulate a click on the currently active header
1934 active = active || this.active[ 0 ];
1935
1936 this._eventHandler({
1937 target: active,
1938 currentTarget: active,
1939 preventDefault: $.noop
1940 });
1941 },
1942
1943 _findActive: function( selector ) {
1944 return typeof selector === "number" ? this.headers.eq( selector ) : $();
1945 },
1946
1947 _setupEvents: function( event ) {
1948 var events = {
1949 keydown: "_keydown"
1950 };
1951 if ( event ) {
1952 $.each( event.split( " " ), function( index, eventName ) {
1953 events[ eventName ] = "_eventHandler";
1954 });
1955 }
1956
1957 this._off( this.headers.add( this.headers.next() ) );
1958 this._on( this.headers, events );
1959 this._on( this.headers.next(), { keydown: "_panelKeyDown" });
1960 this._hoverable( this.headers );
1961 this._focusable( this.headers );
1962 },
1963
1964 _eventHandler: function( event ) {
1965 var options = this.options,
1966 active = this.active,
1967 clicked = $( event.currentTarget ),
1968 clickedIsActive = clicked[ 0 ] === active[ 0 ],
1969 collapsing = clickedIsActive && options.collapsible,
1970 toShow = collapsing ? $() : clicked.next(),
1971 toHide = active.next(),
1972 eventData = {
1973 oldHeader: active,
1974 oldPanel: toHide,
1975 newHeader: collapsing ? $() : clicked,
1976 newPanel: toShow
1977 };
1978
1979 event.preventDefault();
1980
1981 if (
1982 // click on active header, but not collapsible
1983 ( clickedIsActive && !options.collapsible ) ||
1984 // allow canceling activation
1985 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
1986 return;
1987 }
1988
1989 options.active = collapsing ? false : this.headers.index( clicked );
1990
1991 // when the call to ._toggle() comes after the class changes
1992 // it causes a very odd bug in IE 8 (see #6720)
1993 this.active = clickedIsActive ? $() : clicked;
1994 this._toggle( eventData );
1995
1996 // switch classes
1997 // corner classes on the previously active header stay after the animation
1998 active.removeClass( "ui-accordion-header-active ui-state-active" );
1999 if ( options.icons ) {
2000 active.children( ".ui-accordion-header-icon" )
2001 .removeClass( options.icons.activeHeader )
2002 .addClass( options.icons.header );
2003 }
2004
2005 if ( !clickedIsActive ) {
2006 clicked
2007 .removeClass( "ui-corner-all" )
2008 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" );
2009 if ( options.icons ) {
2010 clicked.children( ".ui-accordion-header-icon" )
2011 .removeClass( options.icons.header )
2012 .addClass( options.icons.activeHeader );
2013 }
2014
2015 clicked
2016 .next()
2017 .addClass( "ui-accordion-content-active" );
2018 }
2019 },
2020
2021 _toggle: function( data ) {
2022 var toShow = data.newPanel,
2023 toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
2024
2025 // handle activating a panel during the animation for another activation
2026 this.prevShow.add( this.prevHide ).stop( true, true );
2027 this.prevShow = toShow;
2028 this.prevHide = toHide;
2029
2030 if ( this.options.animate ) {
2031 this._animate( toShow, toHide, data );
2032 } else {
2033 toHide.hide();
2034 toShow.show();
2035 this._toggleComplete( data );
2036 }
2037
2038 toHide.attr({
2039 "aria-hidden": "true"
2040 });
2041 toHide.prev().attr({
2042 "aria-selected": "false",
2043 "aria-expanded": "false"
2044 });
2045 // if we're switching panels, remove the old header from the tab order
2046 // if we're opening from collapsed state, remove the previous header from the tab order
2047 // if we're collapsing, then keep the collapsing header in the tab order
2048 if ( toShow.length && toHide.length ) {
2049 toHide.prev().attr({
2050 "tabIndex": -1,
2051 "aria-expanded": "false"
2052 });
2053 } else if ( toShow.length ) {
2054 this.headers.filter(function() {
2055 return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0;
2056 })
2057 .attr( "tabIndex", -1 );
2058 }
2059
2060 toShow
2061 .attr( "aria-hidden", "false" )
2062 .prev()
2063 .attr({
2064 "aria-selected": "true",
2065 "aria-expanded": "true",
2066 tabIndex: 0
2067 });
2068 },
2069
2070 _animate: function( toShow, toHide, data ) {
2071 var total, easing, duration,
2072 that = this,
2073 adjust = 0,
2074 boxSizing = toShow.css( "box-sizing" ),
2075 down = toShow.length &&
2076 ( !toHide.length || ( toShow.index() < toHide.index() ) ),
2077 animate = this.options.animate || {},
2078 options = down && animate.down || animate,
2079 complete = function() {
2080 that._toggleComplete( data );
2081 };
2082
2083 if ( typeof options === "number" ) {
2084 duration = options;
2085 }
2086 if ( typeof options === "string" ) {
2087 easing = options;
2088 }
2089 // fall back from options to animation in case of partial down settings
2090 easing = easing || options.easing || animate.easing;
2091 duration = duration || options.duration || animate.duration;
2092
2093 if ( !toHide.length ) {
2094 return toShow.animate( this.showProps, duration, easing, complete );
2095 }
2096 if ( !toShow.length ) {
2097 return toHide.animate( this.hideProps, duration, easing, complete );
2098 }
2099
2100 total = toShow.show().outerHeight();
2101 toHide.animate( this.hideProps, {
2102 duration: duration,
2103 easing: easing,
2104 step: function( now, fx ) {
2105 fx.now = Math.round( now );
2106 }
2107 });
2108 toShow
2109 .hide()
2110 .animate( this.showProps, {
2111 duration: duration,
2112 easing: easing,
2113 complete: complete,
2114 step: function( now, fx ) {
2115 fx.now = Math.round( now );
2116 if ( fx.prop !== "height" ) {
2117 if ( boxSizing === "content-box" ) {
2118 adjust += fx.now;
2119 }
2120 } else if ( that.options.heightStyle !== "content" ) {
2121 fx.now = Math.round( total - toHide.outerHeight() - adjust );
2122 adjust = 0;
2123 }
2124 }
2125 });
2126 },
2127
2128 _toggleComplete: function( data ) {
2129 var toHide = data.oldPanel;
2130
2131 toHide
2132 .removeClass( "ui-accordion-content-active" )
2133 .prev()
2134 .removeClass( "ui-corner-top" )
2135 .addClass( "ui-corner-all" );
2136
2137 // Work around for rendering bug in IE (#5421)
2138 if ( toHide.length ) {
2139 toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className;
2140 }
2141 this._trigger( "activate", null, data );
2142 }
2143 });
2144
2145
2146 /*!
2147 * jQuery UI Menu 1.11.4
2148 * http://jqueryui.com
2149 *
2150 * Copyright jQuery Foundation and other contributors
2151 * Released under the MIT license.
2152 * http://jquery.org/license
2153 *
2154 * http://api.jqueryui.com/menu/
2155 */
2156
2157
2158 var menu = $.widget( "ui.menu", {
2159 version: "1.11.4",
2160 defaultElement: "<ul>",
2161 delay: 300,
2162 options: {
2163 icons: {
2164 submenu: "ui-icon-carat-1-e"
2165 },
2166 items: "> *",
2167 menus: "ul",
2168 position: {
2169 my: "left-1 top",
2170 at: "right top"
2171 },
2172 role: "menu",
2173
2174 // callbacks
2175 blur: null,
2176 focus: null,
2177 select: null
2178 },
2179
2180 _create: function() {
2181 this.activeMenu = this.element;
2182
2183 // Flag used to prevent firing of the click handler
2184 // as the event bubbles up through nested menus
2185 this.mouseHandled = false;
2186 this.element
2187 .uniqueId()
2188 .addClass( "ui-menu ui-widget ui-widget-content" )
2189 .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
2190 .attr({
2191 role: this.options.role,
2192 tabIndex: 0
2193 });
2194
2195 if ( this.options.disabled ) {
2196 this.element
2197 .addClass( "ui-state-disabled" )
2198 .attr( "aria-disabled", "true" );
2199 }
2200
2201 this._on({
2202 // Prevent focus from sticking to links inside menu after clicking
2203 // them (focus should always stay on UL during navigation).
2204 "mousedown .ui-menu-item": function( event ) {
2205 event.preventDefault();
2206 },
2207 "click .ui-menu-item": function( event ) {
2208 var target = $( event.target );
2209 if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
2210 this.select( event );
2211
2212 // Only set the mouseHandled flag if the event will bubble, see #9469.
2213 if ( !event.isPropagationStopped() ) {
2214 this.mouseHandled = true;
2215 }
2216
2217 // Open submenu on click
2218 if ( target.has( ".ui-menu" ).length ) {
2219 this.expand( event );
2220 } else if ( !this.element.is( ":focus" ) && $( this.document[ 0 ].activeElement ).closest( ".ui-menu" ).length ) {
2221
2222 // Redirect focus to the menu
2223 this.element.trigger( "focus", [ true ] );
2224
2225 // If the active item is on the top level, let it stay active.
2226 // Otherwise, blur the active item since it is no longer visible.
2227 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
2228 clearTimeout( this.timer );
2229 }
2230 }
2231 }
2232 },
2233 "mouseenter .ui-menu-item": function( event ) {
2234 // Ignore mouse events while typeahead is active, see #10458.
2235 // Prevents focusing the wrong item when typeahead causes a scroll while the mouse
2236 // is over an item in the menu
2237 if ( this.previousFilter ) {
2238 return;
2239 }
2240 var target = $( event.currentTarget );
2241 // Remove ui-state-active class from siblings of the newly focused menu item
2242 // to avoid a jump caused by adjacent elements both having a class with a border
2243 target.siblings( ".ui-state-active" ).removeClass( "ui-state-active" );
2244 this.focus( event, target );
2245 },
2246 mouseleave: "collapseAll",
2247 "mouseleave .ui-menu": "collapseAll",
2248 focus: function( event, keepActiveItem ) {
2249 // If there's already an active item, keep it active
2250 // If not, activate the first item
2251 var item = this.active || this.element.find( this.options.items ).eq( 0 );
2252
2253 if ( !keepActiveItem ) {
2254 this.focus( event, item );
2255 }
2256 },
2257 blur: function( event ) {
2258 this._delay(function() {
2259 if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
2260 this.collapseAll( event );
2261 }
2262 });
2263 },
2264 keydown: "_keydown"
2265 });
2266
2267 this.refresh();
2268
2269 // Clicks outside of a menu collapse any open menus
2270 this._on( this.document, {
2271 click: function( event ) {
2272 if ( this._closeOnDocumentClick( event ) ) {
2273 this.collapseAll( event );
2274 }
2275
2276 // Reset the mouseHandled flag
2277 this.mouseHandled = false;
2278 }
2279 });
2280 },
2281
2282 _destroy: function() {
2283 // Destroy (sub)menus
2284 this.element
2285 .removeAttr( "aria-activedescendant" )
2286 .find( ".ui-menu" ).addBack()
2287 .removeClass( "ui-menu ui-widget ui-widget-content ui-menu-icons ui-front" )
2288 .removeAttr( "role" )
2289 .removeAttr( "tabIndex" )
2290 .removeAttr( "aria-labelledby" )
2291 .removeAttr( "aria-expanded" )
2292 .removeAttr( "aria-hidden" )
2293 .removeAttr( "aria-disabled" )
2294 .removeUniqueId()
2295 .show();
2296
2297 // Destroy menu items
2298 this.element.find( ".ui-menu-item" )
2299 .removeClass( "ui-menu-item" )
2300 .removeAttr( "role" )
2301 .removeAttr( "aria-disabled" )
2302 .removeUniqueId()
2303 .removeClass( "ui-state-hover" )
2304 .removeAttr( "tabIndex" )
2305 .removeAttr( "role" )
2306 .removeAttr( "aria-haspopup" )
2307 .children().each( function() {
2308 var elem = $( this );
2309 if ( elem.data( "ui-menu-submenu-carat" ) ) {
2310 elem.remove();
2311 }
2312 });
2313
2314 // Destroy menu dividers
2315 this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
2316 },
2317
2318 _keydown: function( event ) {
2319 var match, prev, character, skip,
2320 preventDefault = true;
2321
2322 switch ( event.keyCode ) {
2323 case $.ui.keyCode.PAGE_UP:
2324 this.previousPage( event );
2325 break;
2326 case $.ui.keyCode.PAGE_DOWN:
2327 this.nextPage( event );
2328 break;
2329 case $.ui.keyCode.HOME:
2330 this._move( "first", "first", event );
2331 break;
2332 case $.ui.keyCode.END:
2333 this._move( "last", "last", event );
2334 break;
2335 case $.ui.keyCode.UP:
2336 this.previous( event );
2337 break;
2338 case $.ui.keyCode.DOWN:
2339 this.next( event );
2340 break;
2341 case $.ui.keyCode.LEFT:
2342 this.collapse( event );
2343 break;
2344 case $.ui.keyCode.RIGHT:
2345 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
2346 this.expand( event );
2347 }
2348 break;
2349 case $.ui.keyCode.ENTER:
2350 case $.ui.keyCode.SPACE:
2351 this._activate( event );
2352 break;
2353 case $.ui.keyCode.ESCAPE:
2354 this.collapse( event );
2355 break;
2356 default:
2357 preventDefault = false;
2358 prev = this.previousFilter || "";
2359 character = String.fromCharCode( event.keyCode );
2360 skip = false;
2361
2362 clearTimeout( this.filterTimer );
2363
2364 if ( character === prev ) {
2365 skip = true;
2366 } else {
2367 character = prev + character;
2368 }
2369
2370 match = this._filterMenuItems( character );
2371 match = skip && match.index( this.active.next() ) !== -1 ?
2372 this.active.nextAll( ".ui-menu-item" ) :
2373 match;
2374
2375 // If no matches on the current filter, reset to the last character pressed
2376 // to move down the menu to the first item that starts with that character
2377 if ( !match.length ) {
2378 character = String.fromCharCode( event.keyCode );
2379 match = this._filterMenuItems( character );
2380 }
2381
2382 if ( match.length ) {
2383 this.focus( event, match );
2384 this.previousFilter = character;
2385 this.filterTimer = this._delay(function() {
2386 delete this.previousFilter;
2387 }, 1000 );
2388 } else {
2389 delete this.previousFilter;
2390 }
2391 }
2392
2393 if ( preventDefault ) {
2394 event.preventDefault();
2395 }
2396 },
2397
2398 _activate: function( event ) {
2399 if ( !this.active.is( ".ui-state-disabled" ) ) {
2400 if ( this.active.is( "[aria-haspopup='true']" ) ) {
2401 this.expand( event );
2402 } else {
2403 this.select( event );
2404 }
2405 }
2406 },
2407
2408 refresh: function() {
2409 var menus, items,
2410 that = this,
2411 icon = this.options.icons.submenu,
2412 submenus = this.element.find( this.options.menus );
2413
2414 this.element.toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length );
2415
2416 // Initialize nested menus
2417 submenus.filter( ":not(.ui-menu)" )
2418 .addClass( "ui-menu ui-widget ui-widget-content ui-front" )
2419 .hide()
2420 .attr({
2421 role: this.options.role,
2422 "aria-hidden": "true",
2423 "aria-expanded": "false"
2424 })
2425 .each(function() {
2426 var menu = $( this ),
2427 item = menu.parent(),
2428 submenuCarat = $( "<span>" )
2429 .addClass( "ui-menu-icon ui-icon " + icon )
2430 .data( "ui-menu-submenu-carat", true );
2431
2432 item
2433 .attr( "aria-haspopup", "true" )
2434 .prepend( submenuCarat );
2435 menu.attr( "aria-labelledby", item.attr( "id" ) );
2436 });
2437
2438 menus = submenus.add( this.element );
2439 items = menus.find( this.options.items );
2440
2441 // Initialize menu-items containing spaces and/or dashes only as dividers
2442 items.not( ".ui-menu-item" ).each(function() {
2443 var item = $( this );
2444 if ( that._isDivider( item ) ) {
2445 item.addClass( "ui-widget-content ui-menu-divider" );
2446 }
2447 });
2448
2449 // Don't refresh list items that are already adapted
2450 items.not( ".ui-menu-item, .ui-menu-divider" )
2451 .addClass( "ui-menu-item" )
2452 .uniqueId()
2453 .attr({
2454 tabIndex: -1,
2455 role: this._itemRole()
2456 });
2457
2458 // Add aria-disabled attribute to any disabled menu item
2459 items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
2460
2461 // If the active item has been removed, blur the menu
2462 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
2463 this.blur();
2464 }
2465 },
2466
2467 _itemRole: function() {
2468 return {
2469 menu: "menuitem",
2470 listbox: "option"
2471 }[ this.options.role ];
2472 },
2473
2474 _setOption: function( key, value ) {
2475 if ( key === "icons" ) {
2476 this.element.find( ".ui-menu-icon" )
2477 .removeClass( this.options.icons.submenu )
2478 .addClass( value.submenu );
2479 }
2480 if ( key === "disabled" ) {
2481 this.element
2482 .toggleClass( "ui-state-disabled", !!value )
2483 .attr( "aria-disabled", value );
2484 }
2485 this._super( key, value );
2486 },
2487
2488 focus: function( event, item ) {
2489 var nested, focused;
2490 this.blur( event, event && event.type === "focus" );
2491
2492 this._scrollIntoView( item );
2493
2494 this.active = item.first();
2495 focused = this.active.addClass( "ui-state-focus" ).removeClass( "ui-state-active" );
2496 // Only update aria-activedescendant if there's a role
2497 // otherwise we assume focus is managed elsewhere
2498 if ( this.options.role ) {
2499 this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
2500 }
2501
2502 // Highlight active parent menu item, if any
2503 this.active
2504 .parent()
2505 .closest( ".ui-menu-item" )
2506 .addClass( "ui-state-active" );
2507
2508 if ( event && event.type === "keydown" ) {
2509 this._close();
2510 } else {
2511 this.timer = this._delay(function() {
2512 this._close();
2513 }, this.delay );
2514 }
2515
2516 nested = item.children( ".ui-menu" );
2517 if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
2518 this._startOpening(nested);
2519 }
2520 this.activeMenu = item.parent();
2521
2522 this._trigger( "focus", event, { item: item } );
2523 },
2524
2525 _scrollIntoView: function( item ) {
2526 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
2527 if ( this._hasScroll() ) {
2528 borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
2529 paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
2530 offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
2531 scroll = this.activeMenu.scrollTop();
2532 elementHeight = this.activeMenu.height();
2533 itemHeight = item.outerHeight();
2534
2535 if ( offset < 0 ) {
2536 this.activeMenu.scrollTop( scroll + offset );
2537 } else if ( offset + itemHeight > elementHeight ) {
2538 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
2539 }
2540 }
2541 },
2542
2543 blur: function( event, fromFocus ) {
2544 if ( !fromFocus ) {
2545 clearTimeout( this.timer );
2546 }
2547
2548 if ( !this.active ) {
2549 return;
2550 }
2551
2552 this.active.removeClass( "ui-state-focus" );
2553 this.active = null;
2554
2555 this._trigger( "blur", event, { item: this.active } );
2556 },
2557
2558 _startOpening: function( submenu ) {
2559 clearTimeout( this.timer );
2560
2561 // Don't open if already open fixes a Firefox bug that caused a .5 pixel
2562 // shift in the submenu position when mousing over the carat icon
2563 if ( submenu.attr( "aria-hidden" ) !== "true" ) {
2564 return;
2565 }
2566
2567 this.timer = this._delay(function() {
2568 this._close();
2569 this._open( submenu );
2570 }, this.delay );
2571 },
2572
2573 _open: function( submenu ) {
2574 var position = $.extend({
2575 of: this.active
2576 }, this.options.position );
2577
2578 clearTimeout( this.timer );
2579 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
2580 .hide()
2581 .attr( "aria-hidden", "true" );
2582
2583 submenu
2584 .show()
2585 .removeAttr( "aria-hidden" )
2586 .attr( "aria-expanded", "true" )
2587 .position( position );
2588 },
2589
2590 collapseAll: function( event, all ) {
2591 clearTimeout( this.timer );
2592 this.timer = this._delay(function() {
2593 // If we were passed an event, look for the submenu that contains the event
2594 var currentMenu = all ? this.element :
2595 $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
2596
2597 // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
2598 if ( !currentMenu.length ) {
2599 currentMenu = this.element;
2600 }
2601
2602 this._close( currentMenu );
2603
2604 this.blur( event );
2605 this.activeMenu = currentMenu;
2606 }, this.delay );
2607 },
2608
2609 // With no arguments, closes the currently active menu - if nothing is active
2610 // it closes all menus. If passed an argument, it will search for menus BELOW
2611 _close: function( startMenu ) {
2612 if ( !startMenu ) {
2613 startMenu = this.active ? this.active.parent() : this.element;
2614 }
2615
2616 startMenu
2617 .find( ".ui-menu" )
2618 .hide()
2619 .attr( "aria-hidden", "true" )
2620 .attr( "aria-expanded", "false" )
2621 .end()
2622 .find( ".ui-state-active" ).not( ".ui-state-focus" )
2623 .removeClass( "ui-state-active" );
2624 },
2625
2626 _closeOnDocumentClick: function( event ) {
2627 return !$( event.target ).closest( ".ui-menu" ).length;
2628 },
2629
2630 _isDivider: function( item ) {
2631
2632 // Match hyphen, em dash, en dash
2633 return !/[^\-\u2014\u2013\s]/.test( item.text() );
2634 },
2635
2636 collapse: function( event ) {
2637 var newItem = this.active &&
2638 this.active.parent().closest( ".ui-menu-item", this.element );
2639 if ( newItem && newItem.length ) {
2640 this._close();
2641 this.focus( event, newItem );
2642 }
2643 },
2644
2645 expand: function( event ) {
2646 var newItem = this.active &&
2647 this.active
2648 .children( ".ui-menu " )
2649 .find( this.options.items )
2650 .first();
2651
2652 if ( newItem && newItem.length ) {
2653 this._open( newItem.parent() );
2654
2655 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
2656 this._delay(function() {
2657 this.focus( event, newItem );
2658 });
2659 }
2660 },
2661
2662 next: function( event ) {
2663 this._move( "next", "first", event );
2664 },
2665
2666 previous: function( event ) {
2667 this._move( "prev", "last", event );
2668 },
2669
2670 isFirstItem: function() {
2671 return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
2672 },
2673
2674 isLastItem: function() {
2675 return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
2676 },
2677
2678 _move: function( direction, filter, event ) {
2679 var next;
2680 if ( this.active ) {
2681 if ( direction === "first" || direction === "last" ) {
2682 next = this.active
2683 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
2684 .eq( -1 );
2685 } else {
2686 next = this.active
2687 [ direction + "All" ]( ".ui-menu-item" )
2688 .eq( 0 );
2689 }
2690 }
2691 if ( !next || !next.length || !this.active ) {
2692 next = this.activeMenu.find( this.options.items )[ filter ]();
2693 }
2694
2695 this.focus( event, next );
2696 },
2697
2698 nextPage: function( event ) {
2699 var item, base, height;
2700
2701 if ( !this.active ) {
2702 this.next( event );
2703 return;
2704 }
2705 if ( this.isLastItem() ) {
2706 return;
2707 }
2708 if ( this._hasScroll() ) {
2709 base = this.active.offset().top;
2710 height = this.element.height();
2711 this.active.nextAll( ".ui-menu-item" ).each(function() {
2712 item = $( this );
2713 return item.offset().top - base - height < 0;
2714 });
2715
2716 this.focus( event, item );
2717 } else {
2718 this.focus( event, this.activeMenu.find( this.options.items )
2719 [ !this.active ? "first" : "last" ]() );
2720 }
2721 },
2722
2723 previousPage: function( event ) {
2724 var item, base, height;
2725 if ( !this.active ) {
2726 this.next( event );
2727 return;
2728 }
2729 if ( this.isFirstItem() ) {
2730 return;
2731 }
2732 if ( this._hasScroll() ) {
2733 base = this.active.offset().top;
2734 height = this.element.height();
2735 this.active.prevAll( ".ui-menu-item" ).each(function() {
2736 item = $( this );
2737 return item.offset().top - base + height > 0;
2738 });
2739
2740 this.focus( event, item );
2741 } else {
2742 this.focus( event, this.activeMenu.find( this.options.items ).first() );
2743 }
2744 },
2745
2746 _hasScroll: function() {
2747 return this.element.outerHeight() < this.element.prop( "scrollHeight" );
2748 },
2749
2750 select: function( event ) {
2751 // TODO: It should never be possible to not have an active item at this
2752 // point, but the tests don't trigger mouseenter before click.
2753 this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
2754 var ui = { item: this.active };
2755 if ( !this.active.has( ".ui-menu" ).length ) {
2756 this.collapseAll( event, true );
2757 }
2758 this._trigger( "select", event, ui );
2759 },
2760
2761 _filterMenuItems: function(character) {
2762 var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
2763 regex = new RegExp( "^" + escapedCharacter, "i" );
2764
2765 return this.activeMenu
2766 .find( this.options.items )
2767
2768 // Only match on items, not dividers or other content (#10571)
2769 .filter( ".ui-menu-item" )
2770 .filter(function() {
2771 return regex.test( $.trim( $( this ).text() ) );
2772 });
2773 }
2774 });
2775
2776
2777 /*!
2778 * jQuery UI Autocomplete 1.11.4
2779 * http://jqueryui.com
2780 *
2781 * Copyright jQuery Foundation and other contributors
2782 * Released under the MIT license.
2783 * http://jquery.org/license
2784 *
2785 * http://api.jqueryui.com/autocomplete/
2786 */
2787
2788
2789 $.widget( "ui.autocomplete", {
2790 version: "1.11.4",
2791 defaultElement: "<input>",
2792 options: {
2793 appendTo: null,
2794 autoFocus: false,
2795 delay: 300,
2796 minLength: 1,
2797 position: {
2798 my: "left top",
2799 at: "left bottom",
2800 collision: "none"
2801 },
2802 source: null,
2803
2804 // callbacks
2805 change: null,
2806 close: null,
2807 focus: null,
2808 open: null,
2809 response: null,
2810 search: null,
2811 select: null
2812 },
2813
2814 requestIndex: 0,
2815 pending: 0,
2816
2817 _create: function() {
2818 // Some browsers only repeat keydown events, not keypress events,
2819 // so we use the suppressKeyPress flag to determine if we've already
2820 // handled the keydown event. #7269
2821 // Unfortunately the code for & in keypress is the same as the up arrow,
2822 // so we use the suppressKeyPressRepeat flag to avoid handling keypress
2823 // events when we know the keydown event was used to modify the
2824 // search term. #7799
2825 var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
2826 nodeName = this.element[ 0 ].nodeName.toLowerCase(),
2827 isTextarea = nodeName === "textarea",
2828 isInput = nodeName === "input";
2829
2830 this.isMultiLine =
2831 // Textareas are always multi-line
2832 isTextarea ? true :
2833 // Inputs are always single-line, even if inside a contentEditable element
2834 // IE also treats inputs as contentEditable
2835 isInput ? false :
2836 // All other element types are determined by whether or not they're contentEditable
2837 this.element.prop( "isContentEditable" );
2838
2839 this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
2840 this.isNewMenu = true;
2841
2842 this.element
2843 .addClass( "ui-autocomplete-input" )
2844 .attr( "autocomplete", "off" );
2845
2846 this._on( this.element, {
2847 keydown: function( event ) {
2848 if ( this.element.prop( "readOnly" ) ) {
2849 suppressKeyPress = true;
2850 suppressInput = true;
2851 suppressKeyPressRepeat = true;
2852 return;
2853 }
2854
2855 suppressKeyPress = false;
2856 suppressInput = false;
2857 suppressKeyPressRepeat = false;
2858 var keyCode = $.ui.keyCode;
2859 switch ( event.keyCode ) {
2860 case keyCode.PAGE_UP:
2861 suppressKeyPress = true;
2862 this._move( "previousPage", event );
2863 break;
2864 case keyCode.PAGE_DOWN:
2865 suppressKeyPress = true;
2866 this._move( "nextPage", event );
2867 break;
2868 case keyCode.UP:
2869 suppressKeyPress = true;
2870 this._keyEvent( "previous", event );
2871 break;
2872 case keyCode.DOWN:
2873 suppressKeyPress = true;
2874 this._keyEvent( "next", event );
2875 break;
2876 case keyCode.ENTER:
2877 // when menu is open and has focus
2878 if ( this.menu.active ) {
2879 // #6055 - Opera still allows the keypress to occur
2880 // which causes forms to submit
2881 suppressKeyPress = true;
2882 event.preventDefault();
2883 this.menu.select( event );
2884 }
2885 break;
2886 case keyCode.TAB:
2887 if ( this.menu.active ) {
2888 this.menu.select( event );
2889 }
2890 break;
2891 case keyCode.ESCAPE:
2892 if ( this.menu.element.is( ":visible" ) ) {
2893 if ( !this.isMultiLine ) {
2894 this._value( this.term );
2895 }
2896 this.close( event );
2897 // Different browsers have different default behavior for escape
2898 // Single press can mean undo or clear
2899 // Double press in IE means clear the whole form
2900 event.preventDefault();
2901 }
2902 break;
2903 default:
2904 suppressKeyPressRepeat = true;
2905 // search timeout should be triggered before the input value is changed
2906 this._searchTimeout( event );
2907 break;
2908 }
2909 },
2910 keypress: function( event ) {
2911 if ( suppressKeyPress ) {
2912 suppressKeyPress = false;
2913 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
2914 event.preventDefault();
2915 }
2916 return;
2917 }
2918 if ( suppressKeyPressRepeat ) {
2919 return;
2920 }
2921
2922 // replicate some key handlers to allow them to repeat in Firefox and Opera
2923 var keyCode = $.ui.keyCode;
2924 switch ( event.keyCode ) {
2925 case keyCode.PAGE_UP:
2926 this._move( "previousPage", event );
2927 break;
2928 case keyCode.PAGE_DOWN:
2929 this._move( "nextPage", event );
2930 break;
2931 case keyCode.UP:
2932 this._keyEvent( "previous", event );
2933 break;
2934 case keyCode.DOWN:
2935 this._keyEvent( "next", event );
2936 break;
2937 }
2938 },
2939 input: function( event ) {
2940 if ( suppressInput ) {
2941 suppressInput = false;
2942 event.preventDefault();
2943 return;
2944 }
2945 this._searchTimeout( event );
2946 },
2947 focus: function() {
2948 this.selectedItem = null;
2949 this.previous = this._value();
2950 },
2951 blur: function( event ) {
2952 if ( this.cancelBlur ) {
2953 delete this.cancelBlur;
2954 return;
2955 }
2956
2957 clearTimeout( this.searching );
2958 this.close( event );
2959 this._change( event );
2960 }
2961 });
2962
2963 this._initSource();
2964 this.menu = $( "<ul>" )
2965 .addClass( "ui-autocomplete ui-front" )
2966 .appendTo( this._appendTo() )
2967 .menu({
2968 // disable ARIA support, the live region takes care of that
2969 role: null
2970 })
2971 .hide()
2972 .menu( "instance" );
2973
2974 this._on( this.menu.element, {
2975 mousedown: function( event ) {
2976 // prevent moving focus out of the text field
2977 event.preventDefault();
2978
2979 // IE doesn't prevent moving focus even with event.preventDefault()
2980 // so we set a flag to know when we should ignore the blur event
2981 this.cancelBlur = true;
2982 this._delay(function() {
2983 delete this.cancelBlur;
2984 });
2985
2986 // clicking on the scrollbar causes focus to shift to the body
2987 // but we can't detect a mouseup or a click immediately afterward
2988 // so we have to track the next mousedown and close the menu if
2989 // the user clicks somewhere outside of the autocomplete
2990 var menuElement = this.menu.element[ 0 ];
2991 if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
2992 this._delay(function() {
2993 var that = this;
2994 this.document.one( "mousedown", function( event ) {
2995 if ( event.target !== that.element[ 0 ] &&
2996 event.target !== menuElement &&
2997 !$.contains( menuElement, event.target ) ) {
2998 that.close();
2999 }
3000 });
3001 });
3002 }
3003 },
3004 menufocus: function( event, ui ) {
3005 var label, item;
3006 // support: Firefox
3007 // Prevent accidental activation of menu items in Firefox (#7024 #9118)
3008 if ( this.isNewMenu ) {
3009 this.isNewMenu = false;
3010 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
3011 this.menu.blur();
3012
3013 this.document.one( "mousemove", function() {
3014 $( event.target ).trigger( event.originalEvent );
3015 });
3016
3017 return;
3018 }
3019 }
3020
3021 item = ui.item.data( "ui-autocomplete-item" );
3022 if ( false !== this._trigger( "focus", event, { item: item } ) ) {
3023 // use value to match what will end up in the input, if it was a key event
3024 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
3025 this._value( item.value );
3026 }
3027 }
3028
3029 // Announce the value in the liveRegion
3030 label = ui.item.attr( "aria-label" ) || item.value;
3031 if ( label && $.trim( label ).length ) {
3032 this.liveRegion.children().hide();
3033 $( "<div>" ).text( label ).appendTo( this.liveRegion );
3034 }
3035 },
3036 menuselect: function( event, ui ) {
3037 var item = ui.item.data( "ui-autocomplete-item" ),
3038 previous = this.previous;
3039
3040 // only trigger when focus was lost (click on menu)
3041 if ( this.element[ 0 ] !== this.document[ 0 ].activeElement ) {
3042 this.element.focus();
3043 this.previous = previous;
3044 // #6109 - IE triggers two focus events and the second
3045 // is asynchronous, so we need to reset the previous
3046 // term synchronously and asynchronously :-(
3047 this._delay(function() {
3048 this.previous = previous;
3049 this.selectedItem = item;
3050 });
3051 }
3052
3053 if ( false !== this._trigger( "select", event, { item: item } ) ) {
3054 this._value( item.value );
3055 }
3056 // reset the term after the select event
3057 // this allows custom select handling to work properly
3058 this.term = this._value();
3059
3060 this.close( event );
3061 this.selectedItem = item;
3062 }
3063 });
3064
3065 this.liveRegion = $( "<span>", {
3066 role: "status",
3067 "aria-live": "assertive",
3068 "aria-relevant": "additions"
3069 })
3070 .addClass( "ui-helper-hidden-accessible" )
3071 .appendTo( this.document[ 0 ].body );
3072
3073 // turning off autocomplete prevents the browser from remembering the
3074 // value when navigating through history, so we re-enable autocomplete
3075 // if the page is unloaded before the widget is destroyed. #7790
3076 this._on( this.window, {
3077 beforeunload: function() {
3078 this.element.removeAttr( "autocomplete" );
3079 }
3080 });
3081 },
3082
3083 _destroy: function() {
3084 clearTimeout( this.searching );
3085 this.element
3086 .removeClass( "ui-autocomplete-input" )
3087 .removeAttr( "autocomplete" );
3088 this.menu.element.remove();
3089 this.liveRegion.remove();
3090 },
3091
3092 _setOption: function( key, value ) {
3093 this._super( key, value );
3094 if ( key === "source" ) {
3095 this._initSource();
3096 }
3097 if ( key === "appendTo" ) {
3098 this.menu.element.appendTo( this._appendTo() );
3099 }
3100 if ( key === "disabled" && value && this.xhr ) {
3101 this.xhr.abort();
3102 }
3103 },
3104
3105 _appendTo: function() {
3106 var element = this.options.appendTo;
3107
3108 if ( element ) {
3109 element = element.jquery || element.nodeType ?
3110 $( element ) :
3111 this.document.find( element ).eq( 0 );
3112 }
3113
3114 if ( !element || !element[ 0 ] ) {
3115 element = this.element.closest( ".ui-front" );
3116 }
3117
3118 if ( !element.length ) {
3119 element = this.document[ 0 ].body;
3120 }
3121
3122 return element;
3123 },
3124
3125 _initSource: function() {
3126 var array, url,
3127 that = this;
3128 if ( $.isArray( this.options.source ) ) {
3129 array = this.options.source;
3130 this.source = function( request, response ) {
3131 response( $.ui.autocomplete.filter( array, request.term ) );
3132 };
3133 } else if ( typeof this.options.source === "string" ) {
3134 url = this.options.source;
3135 this.source = function( request, response ) {
3136 if ( that.xhr ) {
3137 that.xhr.abort();
3138 }
3139 that.xhr = $.ajax({
3140 url: url,
3141 data: request,
3142 dataType: "json",
3143 success: function( data ) {
3144 response( data );
3145 },
3146 error: function() {
3147 response([]);
3148 }
3149 });
3150 };
3151 } else {
3152 this.source = this.options.source;
3153 }
3154 },
3155
3156 _searchTimeout: function( event ) {
3157 clearTimeout( this.searching );
3158 this.searching = this._delay(function() {
3159
3160 // Search if the value has changed, or if the user retypes the same value (see #7434)
3161 var equalValues = this.term === this._value(),
3162 menuVisible = this.menu.element.is( ":visible" ),
3163 modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
3164
3165 if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
3166 this.selectedItem = null;
3167 this.search( null, event );
3168 }
3169 }, this.options.delay );
3170 },
3171
3172 search: function( value, event ) {
3173 value = value != null ? value : this._value();
3174
3175 // always save the actual value, not the one passed as an argument
3176 this.term = this._value();
3177
3178 if ( value.length < this.options.minLength ) {
3179 return this.close( event );
3180 }
3181
3182 if ( this._trigger( "search", event ) === false ) {
3183 return;
3184 }
3185
3186 return this._search( value );
3187 },
3188
3189 _search: function( value ) {
3190 this.pending++;
3191 this.element.addClass( "ui-autocomplete-loading" );
3192 this.cancelSearch = false;
3193
3194 this.source( { term: value }, this._response() );
3195 },
3196
3197 _response: function() {
3198 var index = ++this.requestIndex;
3199
3200 return $.proxy(function( content ) {
3201 if ( index === this.requestIndex ) {
3202 this.__response( content );
3203 }
3204
3205 this.pending--;
3206 if ( !this.pending ) {
3207 this.element.removeClass( "ui-autocomplete-loading" );
3208 }
3209 }, this );
3210 },
3211
3212 __response: function( content ) {
3213 if ( content ) {
3214 content = this._normalize( content );
3215 }
3216 this._trigger( "response", null, { content: content } );
3217 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
3218 this._suggest( content );
3219 this._trigger( "open" );
3220 } else {
3221 // use ._close() instead of .close() so we don't cancel future searches
3222 this._close();
3223 }
3224 },
3225
3226 close: function( event ) {
3227 this.cancelSearch = true;
3228 this._close( event );
3229 },
3230
3231 _close: function( event ) {
3232 if ( this.menu.element.is( ":visible" ) ) {
3233 this.menu.element.hide();
3234 this.menu.blur();
3235 this.isNewMenu = true;
3236 this._trigger( "close", event );
3237 }
3238 },
3239
3240 _change: function( event ) {
3241 if ( this.previous !== this._value() ) {
3242 this._trigger( "change", event, { item: this.selectedItem } );
3243 }
3244 },
3245
3246 _normalize: function( items ) {
3247 // assume all items have the right format when the first item is complete
3248 if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
3249 return items;
3250 }
3251 return $.map( items, function( item ) {
3252 if ( typeof item === "string" ) {
3253 return {
3254 label: item,
3255 value: item
3256 };
3257 }
3258 return $.extend( {}, item, {
3259 label: item.label || item.value,
3260 value: item.value || item.label
3261 });
3262 });
3263 },
3264
3265 _suggest: function( items ) {
3266 var ul = this.menu.element.empty();
3267 this._renderMenu( ul, items );
3268 this.isNewMenu = true;
3269 this.menu.refresh();
3270
3271 // size and position menu
3272 ul.show();
3273 this._resizeMenu();
3274 ul.position( $.extend({
3275 of: this.element
3276 }, this.options.position ) );
3277
3278 if ( this.options.autoFocus ) {
3279 this.menu.next();
3280 }
3281 },
3282
3283 _resizeMenu: function() {
3284 var ul = this.menu.element;
3285 ul.outerWidth( Math.max(
3286 // Firefox wraps long text (possibly a rounding bug)
3287 // so we add 1px to avoid the wrapping (#7513)
3288 ul.width( "" ).outerWidth() + 1,
3289 this.element.outerWidth()
3290 ) );
3291 },
3292
3293 _renderMenu: function( ul, items ) {
3294 var that = this;
3295 $.each( items, function( index, item ) {
3296 that._renderItemData( ul, item );
3297 });
3298 },
3299
3300 _renderItemData: function( ul, item ) {
3301 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
3302 },
3303
3304 _renderItem: function( ul, item ) {
3305 return $( "<li>" ).text( item.label ).appendTo( ul );
3306 },
3307
3308 _move: function( direction, event ) {
3309 if ( !this.menu.element.is( ":visible" ) ) {
3310 this.search( null, event );
3311 return;
3312 }
3313 if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
3314 this.menu.isLastItem() && /^next/.test( direction ) ) {
3315
3316 if ( !this.isMultiLine ) {
3317 this._value( this.term );
3318 }
3319
3320 this.menu.blur();
3321 return;
3322 }
3323 this.menu[ direction ]( event );
3324 },
3325
3326 widget: function() {
3327 return this.menu.element;
3328 },
3329
3330 _value: function() {
3331 return this.valueMethod.apply( this.element, arguments );
3332 },
3333
3334 _keyEvent: function( keyEvent, event ) {
3335 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
3336 this._move( keyEvent, event );
3337
3338 // prevents moving cursor to beginning/end of the text field in some browsers
3339 event.preventDefault();
3340 }
3341 }
3342 });
3343
3344 $.extend( $.ui.autocomplete, {
3345 escapeRegex: function( value ) {
3346 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
3347 },
3348 filter: function( array, term ) {
3349 var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
3350 return $.grep( array, function( value ) {
3351 return matcher.test( value.label || value.value || value );
3352 });
3353 }
3354 });
3355
3356 // live region extension, adding a `messages` option
3357 // NOTE: This is an experimental API. We are still investigating
3358 // a full solution for string manipulation and internationalization.
3359 $.widget( "ui.autocomplete", $.ui.autocomplete, {
3360 options: {
3361 messages: {
3362 noResults: "No search results.",
3363 results: function( amount ) {
3364 return amount + ( amount > 1 ? " results are" : " result is" ) +
3365 " available, use up and down arrow keys to navigate.";
3366 }
3367 }
3368 },
3369
3370 __response: function( content ) {
3371 var message;
3372 this._superApply( arguments );
3373 if ( this.options.disabled || this.cancelSearch ) {
3374 return;
3375 }
3376 if ( content && content.length ) {
3377 message = this.options.messages.results( content.length );
3378 } else {
3379 message = this.options.messages.noResults;
3380 }
3381 this.liveRegion.children().hide();
3382 $( "<div>" ).text( message ).appendTo( this.liveRegion );
3383 }
3384 });
3385
3386 var autocomplete = $.ui.autocomplete;
3387
3388
3389 /*!
3390 * jQuery UI Button 1.11.4
3391 * http://jqueryui.com
3392 *
3393 * Copyright jQuery Foundation and other contributors
3394 * Released under the MIT license.
3395 * http://jquery.org/license
3396 *
3397 * http://api.jqueryui.com/button/
3398 */
3399
3400
3401 var lastActive,
3402 baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
3403 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",
3404 formResetHandler = function() {
3405 var form = $( this );
3406 setTimeout(function() {
3407 form.find( ":ui-button" ).button( "refresh" );
3408 }, 1 );
3409 },
3410 radioGroup = function( radio ) {
3411 var name = radio.name,
3412 form = radio.form,
3413 radios = $( [] );
3414 if ( name ) {
3415 name = name.replace( /'/g, "\\'" );
3416 if ( form ) {
3417 radios = $( form ).find( "[name='" + name + "'][type=radio]" );
3418 } else {
3419 radios = $( "[name='" + name + "'][type=radio]", radio.ownerDocument )
3420 .filter(function() {
3421 return !this.form;
3422 });
3423 }
3424 }
3425 return radios;
3426 };
3427
3428 $.widget( "ui.button", {
3429 version: "1.11.4",
3430 defaultElement: "<button>",
3431 options: {
3432 disabled: null,
3433 text: true,
3434 label: null,
3435 icons: {
3436 primary: null,
3437 secondary: null
3438 }
3439 },
3440 _create: function() {
3441 this.element.closest( "form" )
3442 .unbind( "reset" + this.eventNamespace )
3443 .bind( "reset" + this.eventNamespace, formResetHandler );
3444
3445 if ( typeof this.options.disabled !== "boolean" ) {
3446 this.options.disabled = !!this.element.prop( "disabled" );
3447 } else {
3448 this.element.prop( "disabled", this.options.disabled );
3449 }
3450
3451 this._determineButtonType();
3452 this.hasTitle = !!this.buttonElement.attr( "title" );
3453
3454 var that = this,
3455 options = this.options,
3456 toggleButton = this.type === "checkbox" || this.type === "radio",
3457 activeClass = !toggleButton ? "ui-state-active" : "";
3458
3459 if ( options.label === null ) {
3460 options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html());
3461 }
3462
3463 this._hoverable( this.buttonElement );
3464
3465 this.buttonElement
3466 .addClass( baseClasses )
3467 .attr( "role", "button" )
3468 .bind( "mouseenter" + this.eventNamespace, function() {
3469 if ( options.disabled ) {
3470 return;
3471 }
3472 if ( this === lastActive ) {
3473 $( this ).addClass( "ui-state-active" );
3474 }
3475 })
3476 .bind( "mouseleave" + this.eventNamespace, function() {
3477 if ( options.disabled ) {
3478 return;
3479 }
3480 $( this ).removeClass( activeClass );
3481 })
3482 .bind( "click" + this.eventNamespace, function( event ) {
3483 if ( options.disabled ) {
3484 event.preventDefault();
3485 event.stopImmediatePropagation();
3486 }
3487 });
3488
3489 // Can't use _focusable() because the element that receives focus
3490 // and the element that gets the ui-state-focus class are different
3491 this._on({
3492 focus: function() {
3493 this.buttonElement.addClass( "ui-state-focus" );
3494 },
3495 blur: function() {
3496 this.buttonElement.removeClass( "ui-state-focus" );
3497 }
3498 });
3499
3500 if ( toggleButton ) {
3501 this.element.bind( "change" + this.eventNamespace, function() {
3502 that.refresh();
3503 });
3504 }
3505
3506 if ( this.type === "checkbox" ) {
3507 this.buttonElement.bind( "click" + this.eventNamespace, function() {
3508 if ( options.disabled ) {
3509 return false;
3510 }
3511 });
3512 } else if ( this.type === "radio" ) {
3513 this.buttonElement.bind( "click" + this.eventNamespace, function() {
3514 if ( options.disabled ) {
3515 return false;
3516 }
3517 $( this ).addClass( "ui-state-active" );
3518 that.buttonElement.attr( "aria-pressed", "true" );
3519
3520 var radio = that.element[ 0 ];
3521 radioGroup( radio )
3522 .not( radio )
3523 .map(function() {
3524 return $( this ).button( "widget" )[ 0 ];
3525 })
3526 .removeClass( "ui-state-active" )
3527 .attr( "aria-pressed", "false" );
3528 });
3529 } else {
3530 this.buttonElement
3531 .bind( "mousedown" + this.eventNamespace, function() {
3532 if ( options.disabled ) {
3533 return false;
3534 }
3535 $( this ).addClass( "ui-state-active" );
3536 lastActive = this;
3537 that.document.one( "mouseup", function() {
3538 lastActive = null;
3539 });
3540 })
3541 .bind( "mouseup" + this.eventNamespace, function() {
3542 if ( options.disabled ) {
3543 return false;
3544 }
3545 $( this ).removeClass( "ui-state-active" );
3546 })
3547 .bind( "keydown" + this.eventNamespace, function(event) {
3548 if ( options.disabled ) {
3549 return false;
3550 }
3551 if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) {
3552 $( this ).addClass( "ui-state-active" );
3553 }
3554 })
3555 // see #8559, we bind to blur here in case the button element loses
3556 // focus between keydown and keyup, it would be left in an "active" state
3557 .bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() {
3558 $( this ).removeClass( "ui-state-active" );
3559 });
3560
3561 if ( this.buttonElement.is("a") ) {
3562 this.buttonElement.keyup(function(event) {
3563 if ( event.keyCode === $.ui.keyCode.SPACE ) {
3564 // TODO pass through original event correctly (just as 2nd argument doesn't work)
3565 $( this ).click();
3566 }
3567 });
3568 }
3569 }
3570
3571 this._setOption( "disabled", options.disabled );
3572 this._resetButton();
3573 },
3574
3575 _determineButtonType: function() {
3576 var ancestor, labelSelector, checked;
3577
3578 if ( this.element.is("[type=checkbox]") ) {
3579 this.type = "checkbox";
3580 } else if ( this.element.is("[type=radio]") ) {
3581 this.type = "radio";
3582 } else if ( this.element.is("input") ) {
3583 this.type = "input";
3584 } else {
3585 this.type = "button";
3586 }
3587
3588 if ( this.type === "checkbox" || this.type === "radio" ) {
3589 // we don't search against the document in case the element
3590 // is disconnected from the DOM
3591 ancestor = this.element.parents().last();
3592 labelSelector = "label[for='" + this.element.attr("id") + "']";
3593 this.buttonElement = ancestor.find( labelSelector );
3594 if ( !this.buttonElement.length ) {
3595 ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
3596 this.buttonElement = ancestor.filter( labelSelector );
3597 if ( !this.buttonElement.length ) {
3598 this.buttonElement = ancestor.find( labelSelector );
3599 }
3600 }
3601 this.element.addClass( "ui-helper-hidden-accessible" );
3602
3603 checked = this.element.is( ":checked" );
3604 if ( checked ) {
3605 this.buttonElement.addClass( "ui-state-active" );
3606 }
3607 this.buttonElement.prop( "aria-pressed", checked );
3608 } else {
3609 this.buttonElement = this.element;
3610 }
3611 },
3612
3613 widget: function() {
3614 return this.buttonElement;
3615 },
3616
3617 _destroy: function() {
3618 this.element
3619 .removeClass( "ui-helper-hidden-accessible" );
3620 this.buttonElement
3621 .removeClass( baseClasses + " ui-state-active " + typeClasses )
3622 .removeAttr( "role" )
3623 .removeAttr( "aria-pressed" )
3624 .html( this.buttonElement.find(".ui-button-text").html() );
3625
3626 if ( !this.hasTitle ) {
3627 this.buttonElement.removeAttr( "title" );
3628 }
3629 },
3630
3631 _setOption: function( key, value ) {
3632 this._super( key, value );
3633 if ( key === "disabled" ) {
3634 this.widget().toggleClass( "ui-state-disabled", !!value );
3635 this.element.prop( "disabled", !!value );
3636 if ( value ) {
3637 if ( this.type === "checkbox" || this.type === "radio" ) {
3638 this.buttonElement.removeClass( "ui-state-focus" );
3639 } else {
3640 this.buttonElement.removeClass( "ui-state-focus ui-state-active" );
3641 }
3642 }
3643 return;
3644 }
3645 this._resetButton();
3646 },
3647
3648 refresh: function() {
3649 //See #8237 & #8828
3650 var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" );
3651
3652 if ( isDisabled !== this.options.disabled ) {
3653 this._setOption( "disabled", isDisabled );
3654 }
3655 if ( this.type === "radio" ) {
3656 radioGroup( this.element[0] ).each(function() {
3657 if ( $( this ).is( ":checked" ) ) {
3658 $( this ).button( "widget" )
3659 .addClass( "ui-state-active" )
3660 .attr( "aria-pressed", "true" );
3661 } else {
3662 $( this ).button( "widget" )
3663 .removeClass( "ui-state-active" )
3664 .attr( "aria-pressed", "false" );
3665 }
3666 });
3667 } else if ( this.type === "checkbox" ) {
3668 if ( this.element.is( ":checked" ) ) {
3669 this.buttonElement
3670 .addClass( "ui-state-active" )
3671 .attr( "aria-pressed", "true" );
3672 } else {
3673 this.buttonElement
3674 .removeClass( "ui-state-active" )
3675 .attr( "aria-pressed", "false" );
3676 }
3677 }
3678 },
3679
3680 _resetButton: function() {
3681 if ( this.type === "input" ) {
3682 if ( this.options.label ) {
3683 this.element.val( this.options.label );
3684 }
3685 return;
3686 }
3687 var buttonElement = this.buttonElement.removeClass( typeClasses ),
3688 buttonText = $( "<span></span>", this.document[0] )
3689 .addClass( "ui-button-text" )
3690 .html( this.options.label )
3691 .appendTo( buttonElement.empty() )
3692 .text(),
3693 icons = this.options.icons,
3694 multipleIcons = icons.primary && icons.secondary,
3695 buttonClasses = [];
3696
3697 if ( icons.primary || icons.secondary ) {
3698 if ( this.options.text ) {
3699 buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
3700 }
3701
3702 if ( icons.primary ) {
3703 buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
3704 }
3705
3706 if ( icons.secondary ) {
3707 buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
3708 }
3709
3710 if ( !this.options.text ) {
3711 buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );
3712
3713 if ( !this.hasTitle ) {
3714 buttonElement.attr( "title", $.trim( buttonText ) );
3715 }
3716 }
3717 } else {
3718 buttonClasses.push( "ui-button-text-only" );
3719 }
3720 buttonElement.addClass( buttonClasses.join( " " ) );
3721 }
3722 });
3723
3724 $.widget( "ui.buttonset", {
3725 version: "1.11.4",
3726 options: {
3727 items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"
3728 },
3729
3730 _create: function() {
3731 this.element.addClass( "ui-buttonset" );
3732 },
3733
3734 _init: function() {
3735 this.refresh();
3736 },
3737
3738 _setOption: function( key, value ) {
3739 if ( key === "disabled" ) {
3740 this.buttons.button( "option", key, value );
3741 }
3742
3743 this._super( key, value );
3744 },
3745
3746 refresh: function() {
3747 var rtl = this.element.css( "direction" ) === "rtl",
3748 allButtons = this.element.find( this.options.items ),
3749 existingButtons = allButtons.filter( ":ui-button" );
3750
3751 // Initialize new buttons
3752 allButtons.not( ":ui-button" ).button();
3753
3754 // Refresh existing buttons
3755 existingButtons.button( "refresh" );
3756
3757 this.buttons = allButtons
3758 .map(function() {
3759 return $( this ).button( "widget" )[ 0 ];
3760 })
3761 .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
3762 .filter( ":first" )
3763 .addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
3764 .end()
3765 .filter( ":last" )
3766 .addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
3767 .end()
3768 .end();
3769 },
3770
3771 _destroy: function() {
3772 this.element.removeClass( "ui-buttonset" );
3773 this.buttons
3774 .map(function() {
3775 return $( this ).button( "widget" )[ 0 ];
3776 })
3777 .removeClass( "ui-corner-left ui-corner-right" )
3778 .end()
3779 .button( "destroy" );
3780 }
3781 });
3782
3783 var button = $.ui.button;
3784
3785
3786 /*!
3787 * jQuery UI Datepicker 1.11.4
3788 * http://jqueryui.com
3789 *
3790 * Copyright jQuery Foundation and other contributors
3791 * Released under the MIT license.
3792 * http://jquery.org/license
3793 *
3794 * http://api.jqueryui.com/datepicker/
3795 */
3796
3797
3798 $.extend($.ui, { datepicker: { version: "1.11.4" } });
3799
3800 var datepicker_instActive;
3801
3802 function datepicker_getZindex( elem ) {
3803 var position, value;
3804 while ( elem.length && elem[ 0 ] !== document ) {
3805 // Ignore z-index if position is set to a value where z-index is ignored by the browser
3806 // This makes behavior of this function consistent across browsers
3807 // WebKit always returns auto if the element is positioned
3808 position = elem.css( "position" );
3809 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
3810 // IE returns 0 when zIndex is not specified
3811 // other browsers return a string
3812 // we ignore the case of nested elements with an explicit value of 0
3813 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
3814 value = parseInt( elem.css( "zIndex" ), 10 );
3815 if ( !isNaN( value ) && value !== 0 ) {
3816 return value;
3817 }
3818 }
3819 elem = elem.parent();
3820 }
3821
3822 return 0;
3823 }
3824 /* Date picker manager.
3825 Use the singleton instance of this class, $.datepicker, to interact with the date picker.
3826 Settings for (groups of) date pickers are maintained in an instance object,
3827 allowing multiple different settings on the same page. */
3828
3829 function Datepicker() {
3830 this._curInst = null; // The current instance in use
3831 this._keyEvent = false; // If the last event was a key event
3832 this._disabledInputs = []; // List of date picker inputs that have been disabled
3833 this._datepickerShowing = false; // True if the popup picker is showing , false if not
3834 this._inDialog = false; // True if showing within a "dialog", false if not
3835 this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
3836 this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
3837 this._appendClass = "ui-datepicker-append"; // The name of the append marker class
3838 this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
3839 this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
3840 this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
3841 this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
3842 this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
3843 this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
3844 this.regional = []; // Available regional settings, indexed by language code
3845 this.regional[""] = { // Default regional settings
3846 closeText: "Done", // Display text for close link
3847 prevText: "Prev", // Display text for previous month link
3848 nextText: "Next", // Display text for next month link
3849 currentText: "Today", // Display text for current month link
3850 monthNames: ["January","February","March","April","May","June",
3851 "July","August","September","October","November","December"], // Names of months for drop-down and formatting
3852 monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
3853 dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
3854 dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
3855 dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
3856 weekHeader: "Wk", // Column header for week of the year
3857 dateFormat: "mm/dd/yy", // See format options on parseDate
3858 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
3859 isRTL: false, // True if right-to-left language, false if left-to-right
3860 showMonthAfterYear: false, // True if the year select precedes month, false for month then year
3861 yearSuffix: "" // Additional text to append to the year in the month headers
3862 };
3863 this._defaults = { // Global defaults for all the date picker instances
3864 showOn: "focus", // "focus" for popup on focus,
3865 // "button" for trigger button, or "both" for either
3866 showAnim: "fadeIn", // Name of jQuery animation for popup
3867 showOptions: {}, // Options for enhanced animations
3868 defaultDate: null, // Used when field is blank: actual date,
3869 // +/-number for offset from today, null for today
3870 appendText: "", // Display text following the input box, e.g. showing the format
3871 buttonText: "...", // Text for trigger button
3872 buttonImage: "", // URL for trigger button image
3873 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
3874 hideIfNoPrevNext: false, // True to hide next/previous month links
3875 // if not applicable, false to just disable them
3876 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
3877 gotoCurrent: false, // True if today link goes back to current selection instead
3878 changeMonth: false, // True if month can be selected directly, false if only prev/next
3879 changeYear: false, // True if year can be selected directly, false if only prev/next
3880 yearRange: "c-10:c+10", // Range of years to display in drop-down,
3881 // either relative to today's year (-nn:+nn), relative to currently displayed year
3882 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
3883 showOtherMonths: false, // True to show dates in other months, false to leave blank
3884 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
3885 showWeek: false, // True to show week of the year, false to not show it
3886 calculateWeek: this.iso8601Week, // How to calculate the week of the year,
3887 // takes a Date and returns the number of the week for it
3888 shortYearCutoff: "+10", // Short year values < this are in the current century,
3889 // > this are in the previous century,
3890 // string value starting with "+" for current year + value
3891 minDate: null, // The earliest selectable date, or null for no limit
3892 maxDate: null, // The latest selectable date, or null for no limit
3893 duration: "fast", // Duration of display/closure
3894 beforeShowDay: null, // Function that takes a date and returns an array with
3895 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
3896 // [2] = cell title (optional), e.g. $.datepicker.noWeekends
3897 beforeShow: null, // Function that takes an input field and
3898 // returns a set of custom settings for the date picker
3899 onSelect: null, // Define a callback function when a date is selected
3900 onChangeMonthYear: null, // Define a callback function when the month or year is changed
3901 onClose: null, // Define a callback function when the datepicker is closed
3902 numberOfMonths: 1, // Number of months to show at a time
3903 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
3904 stepMonths: 1, // Number of months to step back/forward
3905 stepBigMonths: 12, // Number of months to step back/forward for the big links
3906 altField: "", // Selector for an alternate field to store selected dates into
3907 altFormat: "", // The date format to use for the alternate field
3908 constrainInput: true, // The input is constrained by the current date format
3909 showButtonPanel: false, // True to show button panel, false to not show it
3910 autoSize: false, // True to size the input for the date format, false to leave as is
3911 disabled: false // The initial disabled state
3912 };
3913 $.extend(this._defaults, this.regional[""]);
3914 this.regional.en = $.extend( true, {}, this.regional[ "" ]);
3915 this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
3916 this.dpDiv = datepicker_bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
3917 }
3918
3919 $.extend(Datepicker.prototype, {
3920 /* Class name added to elements to indicate already configured with a date picker. */
3921 markerClassName: "hasDatepicker",
3922
3923 //Keep track of the maximum number of rows displayed (see #7043)
3924 maxRows: 4,
3925
3926 // TODO rename to "widget" when switching to widget factory
3927 _widgetDatepicker: function() {
3928 return this.dpDiv;
3929 },
3930
3931 /* Override the default settings for all instances of the date picker.
3932 * @param settings object - the new settings to use as defaults (anonymous object)
3933 * @return the manager object
3934 */
3935 setDefaults: function(settings) {
3936 datepicker_extendRemove(this._defaults, settings || {});
3937 return this;
3938 },
3939
3940 /* Attach the date picker to a jQuery selection.
3941 * @param target element - the target input field or division or span
3942 * @param settings object - the new settings to use for this date picker instance (anonymous)
3943 */
3944 _attachDatepicker: function(target, settings) {
3945 var nodeName, inline, inst;
3946 nodeName = target.nodeName.toLowerCase();
3947 inline = (nodeName === "div" || nodeName === "span");
3948 if (!target.id) {
3949 this.uuid += 1;
3950 target.id = "dp" + this.uuid;
3951 }
3952 inst = this._newInst($(target), inline);
3953 inst.settings = $.extend({}, settings || {});
3954 if (nodeName === "input") {
3955 this._connectDatepicker(target, inst);
3956 } else if (inline) {
3957 this._inlineDatepicker(target, inst);
3958 }
3959 },
3960
3961 /* Create a new instance object. */
3962 _newInst: function(target, inline) {
3963 var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
3964 return {id: id, input: target, // associated target
3965 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
3966 drawMonth: 0, drawYear: 0, // month being drawn
3967 inline: inline, // is datepicker inline or not
3968 dpDiv: (!inline ? this.dpDiv : // presentation div
3969 datepicker_bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
3970 },
3971
3972 /* Attach the date picker to an input field. */
3973 _connectDatepicker: function(target, inst) {
3974 var input = $(target);
3975 inst.append = $([]);
3976 inst.trigger = $([]);
3977 if (input.hasClass(this.markerClassName)) {
3978 return;
3979 }
3980 this._attachments(input, inst);
3981 input.addClass(this.markerClassName).keydown(this._doKeyDown).
3982 keypress(this._doKeyPress).keyup(this._doKeyUp);
3983 this._autoSize(inst);
3984 $.data(target, "datepicker", inst);
3985 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
3986 if( inst.settings.disabled ) {
3987 this._disableDatepicker( target );
3988 }
3989 },
3990
3991 /* Make attachments based on settings. */
3992 _attachments: function(input, inst) {
3993 var showOn, buttonText, buttonImage,
3994 appendText = this._get(inst, "appendText"),
3995 isRTL = this._get(inst, "isRTL");
3996
3997 if (inst.append) {
3998 inst.append.remove();
3999 }
4000 if (appendText) {
4001 inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
4002 input[isRTL ? "before" : "after"](inst.append);
4003 }
4004
4005 input.unbind("focus", this._showDatepicker);
4006
4007 if (inst.trigger) {
4008 inst.trigger.remove();
4009 }
4010
4011 showOn = this._get(inst, "showOn");
4012 if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
4013 input.focus(this._showDatepicker);
4014 }
4015 if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
4016 buttonText = this._get(inst, "buttonText");
4017 buttonImage = this._get(inst, "buttonImage");
4018 inst.trigger = $(this._get(inst, "buttonImageOnly") ?
4019 $("<img/>").addClass(this._triggerClass).
4020 attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
4021 $("<button type='button'></button>").addClass(this._triggerClass).
4022 html(!buttonImage ? buttonText : $("<img/>").attr(
4023 { src:buttonImage, alt:buttonText, title:buttonText })));
4024 input[isRTL ? "before" : "after"](inst.trigger);
4025 inst.trigger.click(function() {
4026 if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
4027 $.datepicker._hideDatepicker();
4028 } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
4029 $.datepicker._hideDatepicker();
4030 $.datepicker._showDatepicker(input[0]);
4031 } else {
4032 $.datepicker._showDatepicker(input[0]);
4033 }
4034 return false;
4035 });
4036 }
4037 },
4038
4039 /* Apply the maximum length for the date format. */
4040 _autoSize: function(inst) {
4041 if (this._get(inst, "autoSize") && !inst.inline) {
4042 var findMax, max, maxI, i,
4043 date = new Date(2009, 12 - 1, 20), // Ensure double digits
4044 dateFormat = this._get(inst, "dateFormat");
4045
4046 if (dateFormat.match(/[DM]/)) {
4047 findMax = function(names) {
4048 max = 0;
4049 maxI = 0;
4050 for (i = 0; i < names.length; i++) {
4051 if (names[i].length > max) {
4052 max = names[i].length;
4053 maxI = i;
4054 }
4055 }
4056 return maxI;
4057 };
4058 date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
4059 "monthNames" : "monthNamesShort"))));
4060 date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
4061 "dayNames" : "dayNamesShort"))) + 20 - date.getDay());
4062 }
4063 inst.input.attr("size", this._formatDate(inst, date).length);
4064 }
4065 },
4066
4067 /* Attach an inline date picker to a div. */
4068 _inlineDatepicker: function(target, inst) {
4069 var divSpan = $(target);
4070 if (divSpan.hasClass(this.markerClassName)) {
4071 return;
4072 }
4073 divSpan.addClass(this.markerClassName).append(inst.dpDiv);
4074 $.data(target, "datepicker", inst);
4075 this._setDate(inst, this._getDefaultDate(inst), true);
4076 this._updateDatepicker(inst);
4077 this._updateAlternate(inst);
4078 //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
4079 if( inst.settings.disabled ) {
4080 this._disableDatepicker( target );
4081 }
4082 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
4083 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
4084 inst.dpDiv.css( "display", "block" );
4085 },
4086
4087 /* Pop-up the date picker in a "dialog" box.
4088 * @param input element - ignored
4089 * @param date string or Date - the initial date to display
4090 * @param onSelect function - the function to call when a date is selected
4091 * @param settings object - update the dialog date picker instance's settings (anonymous object)
4092 * @param pos int[2] - coordinates for the dialog's position within the screen or
4093 * event - with x/y coordinates or
4094 * leave empty for default (screen centre)
4095 * @return the manager object
4096 */
4097 _dialogDatepicker: function(input, date, onSelect, settings, pos) {
4098 var id, browserWidth, browserHeight, scrollX, scrollY,
4099 inst = this._dialogInst; // internal instance
4100
4101 if (!inst) {
4102 this.uuid += 1;
4103 id = "dp" + this.uuid;
4104 this._dialogInput = $("<input type='text' id='" + id +
4105 "' style='position: absolute; top: -100px; width: 0px;'/>");
4106 this._dialogInput.keydown(this._doKeyDown);
4107 $("body").append(this._dialogInput);
4108 inst = this._dialogInst = this._newInst(this._dialogInput, false);
4109 inst.settings = {};
4110 $.data(this._dialogInput[0], "datepicker", inst);
4111 }
4112 datepicker_extendRemove(inst.settings, settings || {});
4113 date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
4114 this._dialogInput.val(date);
4115
4116 this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
4117 if (!this._pos) {
4118 browserWidth = document.documentElement.clientWidth;
4119 browserHeight = document.documentElement.clientHeight;
4120 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
4121 scrollY = document.documentElement.scrollTop || document.body.scrollTop;
4122 this._pos = // should use actual width/height below
4123 [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
4124 }
4125
4126 // move input on screen for focus, but hidden behind dialog
4127 this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
4128 inst.settings.onSelect = onSelect;
4129 this._inDialog = true;
4130 this.dpDiv.addClass(this._dialogClass);
4131 this._showDatepicker(this._dialogInput[0]);
4132 if ($.blockUI) {
4133 $.blockUI(this.dpDiv);
4134 }
4135 $.data(this._dialogInput[0], "datepicker", inst);
4136 return this;
4137 },
4138
4139 /* Detach a datepicker from its control.
4140 * @param target element - the target input field or division or span
4141 */
4142 _destroyDatepicker: function(target) {
4143 var nodeName,
4144 $target = $(target),
4145 inst = $.data(target, "datepicker");
4146
4147 if (!$target.hasClass(this.markerClassName)) {
4148 return;
4149 }
4150
4151 nodeName = target.nodeName.toLowerCase();
4152 $.removeData(target, "datepicker");
4153 if (nodeName === "input") {
4154 inst.append.remove();
4155 inst.trigger.remove();
4156 $target.removeClass(this.markerClassName).
4157 unbind("focus", this._showDatepicker).
4158 unbind("keydown", this._doKeyDown).
4159 unbind("keypress", this._doKeyPress).
4160 unbind("keyup", this._doKeyUp);
4161 } else if (nodeName === "div" || nodeName === "span") {
4162 $target.removeClass(this.markerClassName).empty();
4163 }
4164
4165 if ( datepicker_instActive === inst ) {
4166 datepicker_instActive = null;
4167 }
4168 },
4169
4170 /* Enable the date picker to a jQuery selection.
4171 * @param target element - the target input field or division or span
4172 */
4173 _enableDatepicker: function(target) {
4174 var nodeName, inline,
4175 $target = $(target),
4176 inst = $.data(target, "datepicker");
4177
4178 if (!$target.hasClass(this.markerClassName)) {
4179 return;
4180 }
4181
4182 nodeName = target.nodeName.toLowerCase();
4183 if (nodeName === "input") {
4184 target.disabled = false;
4185 inst.trigger.filter("button").
4186 each(function() { this.disabled = false; }).end().
4187 filter("img").css({opacity: "1.0", cursor: ""});
4188 } else if (nodeName === "div" || nodeName === "span") {
4189 inline = $target.children("." + this._inlineClass);
4190 inline.children().removeClass("ui-state-disabled");
4191 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
4192 prop("disabled", false);
4193 }
4194 this._disabledInputs = $.map(this._disabledInputs,
4195 function(value) { return (value === target ? null : value); }); // delete entry
4196 },
4197
4198 /* Disable the date picker to a jQuery selection.
4199 * @param target element - the target input field or division or span
4200 */
4201 _disableDatepicker: function(target) {
4202 var nodeName, inline,
4203 $target = $(target),
4204 inst = $.data(target, "datepicker");
4205
4206 if (!$target.hasClass(this.markerClassName)) {
4207 return;
4208 }
4209
4210 nodeName = target.nodeName.toLowerCase();
4211 if (nodeName === "input") {
4212 target.disabled = true;
4213 inst.trigger.filter("button").
4214 each(function() { this.disabled = true; }).end().
4215 filter("img").css({opacity: "0.5", cursor: "default"});
4216 } else if (nodeName === "div" || nodeName === "span") {
4217 inline = $target.children("." + this._inlineClass);
4218 inline.children().addClass("ui-state-disabled");
4219 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
4220 prop("disabled", true);
4221 }
4222 this._disabledInputs = $.map(this._disabledInputs,
4223 function(value) { return (value === target ? null : value); }); // delete entry
4224 this._disabledInputs[this._disabledInputs.length] = target;
4225 },
4226
4227 /* Is the first field in a jQuery collection disabled as a datepicker?
4228 * @param target element - the target input field or division or span
4229 * @return boolean - true if disabled, false if enabled
4230 */
4231 _isDisabledDatepicker: function(target) {
4232 if (!target) {
4233 return false;
4234 }
4235 for (var i = 0; i < this._disabledInputs.length; i++) {
4236 if (this._disabledInputs[i] === target) {
4237 return true;
4238 }
4239 }
4240 return false;
4241 },
4242
4243 /* Retrieve the instance data for the target control.
4244 * @param target element - the target input field or division or span
4245 * @return object - the associated instance data
4246 * @throws error if a jQuery problem getting data
4247 */
4248 _getInst: function(target) {
4249 try {
4250 return $.data(target, "datepicker");
4251 }
4252 catch (err) {
4253 throw "Missing instance data for this datepicker";
4254 }
4255 },
4256
4257 /* Update or retrieve the settings for a date picker attached to an input field or division.
4258 * @param target element - the target input field or division or span
4259 * @param name object - the new settings to update or
4260 * string - the name of the setting to change or retrieve,
4261 * when retrieving also "all" for all instance settings or
4262 * "defaults" for all global defaults
4263 * @param value any - the new value for the setting
4264 * (omit if above is an object or to retrieve a value)
4265 */
4266 _optionDatepicker: function(target, name, value) {
4267 var settings, date, minDate, maxDate,
4268 inst = this._getInst(target);
4269
4270 if (arguments.length === 2 && typeof name === "string") {
4271 return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
4272 (inst ? (name === "all" ? $.extend({}, inst.settings) :
4273 this._get(inst, name)) : null));
4274 }
4275
4276 settings = name || {};
4277 if (typeof name === "string") {
4278 settings = {};
4279 settings[name] = value;
4280 }
4281
4282 if (inst) {
4283 if (this._curInst === inst) {
4284 this._hideDatepicker();
4285 }
4286
4287 date = this._getDateDatepicker(target, true);
4288 minDate = this._getMinMaxDate(inst, "min");
4289 maxDate = this._getMinMaxDate(inst, "max");
4290 datepicker_extendRemove(inst.settings, settings);
4291 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
4292 if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
4293 inst.settings.minDate = this._formatDate(inst, minDate);
4294 }
4295 if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
4296 inst.settings.maxDate = this._formatDate(inst, maxDate);
4297 }
4298 if ( "disabled" in settings ) {
4299 if ( settings.disabled ) {
4300 this._disableDatepicker(target);
4301 } else {
4302 this._enableDatepicker(target);
4303 }
4304 }
4305 this._attachments($(target), inst);
4306 this._autoSize(inst);
4307 this._setDate(inst, date);
4308 this._updateAlternate(inst);
4309 this._updateDatepicker(inst);
4310 }
4311 },
4312
4313 // change method deprecated
4314 _changeDatepicker: function(target, name, value) {
4315 this._optionDatepicker(target, name, value);
4316 },
4317
4318 /* Redraw the date picker attached to an input field or division.
4319 * @param target element - the target input field or division or span
4320 */
4321 _refreshDatepicker: function(target) {
4322 var inst = this._getInst(target);
4323 if (inst) {
4324 this._updateDatepicker(inst);
4325 }
4326 },
4327
4328 /* Set the dates for a jQuery selection.
4329 * @param target element - the target input field or division or span
4330 * @param date Date - the new date
4331 */
4332 _setDateDatepicker: function(target, date) {
4333 var inst = this._getInst(target);
4334 if (inst) {
4335 this._setDate(inst, date);
4336 this._updateDatepicker(inst);
4337 this._updateAlternate(inst);
4338 }
4339 },
4340
4341 /* Get the date(s) for the first entry in a jQuery selection.
4342 * @param target element - the target input field or division or span
4343 * @param noDefault boolean - true if no default date is to be used
4344 * @return Date - the current date
4345 */
4346 _getDateDatepicker: function(target, noDefault) {
4347 var inst = this._getInst(target);
4348 if (inst && !inst.inline) {
4349 this._setDateFromField(inst, noDefault);
4350 }
4351 return (inst ? this._getDate(inst) : null);
4352 },
4353
4354 /* Handle keystrokes. */
4355 _doKeyDown: function(event) {
4356 var onSelect, dateStr, sel,
4357 inst = $.datepicker._getInst(event.target),
4358 handled = true,
4359 isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
4360
4361 inst._keyEvent = true;
4362 if ($.datepicker._datepickerShowing) {
4363 switch (event.keyCode) {
4364 case 9: $.datepicker._hideDatepicker();
4365 handled = false;
4366 break; // hide on tab out
4367 case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
4368 $.datepicker._currentClass + ")", inst.dpDiv);
4369 if (sel[0]) {
4370 $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
4371 }
4372
4373 onSelect = $.datepicker._get(inst, "onSelect");
4374 if (onSelect) {
4375 dateStr = $.datepicker._formatDate(inst);
4376
4377 // trigger custom callback
4378 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
4379 } else {
4380 $.datepicker._hideDatepicker();
4381 }
4382
4383 return false; // don't submit the form
4384 case 27: $.datepicker._hideDatepicker();
4385 break; // hide on escape
4386 case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
4387 -$.datepicker._get(inst, "stepBigMonths") :
4388 -$.datepicker._get(inst, "stepMonths")), "M");
4389 break; // previous month/year on page up/+ ctrl
4390 case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
4391 +$.datepicker._get(inst, "stepBigMonths") :
4392 +$.datepicker._get(inst, "stepMonths")), "M");
4393 break; // next month/year on page down/+ ctrl
4394 case 35: if (event.ctrlKey || event.metaKey) {
4395 $.datepicker._clearDate(event.target);
4396 }
4397 handled = event.ctrlKey || event.metaKey;
4398 break; // clear on ctrl or command +end
4399 case 36: if (event.ctrlKey || event.metaKey) {
4400 $.datepicker._gotoToday(event.target);
4401 }
4402 handled = event.ctrlKey || event.metaKey;
4403 break; // current on ctrl or command +home
4404 case 37: if (event.ctrlKey || event.metaKey) {
4405 $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
4406 }
4407 handled = event.ctrlKey || event.metaKey;
4408 // -1 day on ctrl or command +left
4409 if (event.originalEvent.altKey) {
4410 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
4411 -$.datepicker._get(inst, "stepBigMonths") :
4412 -$.datepicker._get(inst, "stepMonths")), "M");
4413 }
4414 // next month/year on alt +left on Mac
4415 break;
4416 case 38: if (event.ctrlKey || event.metaKey) {
4417 $.datepicker._adjustDate(event.target, -7, "D");
4418 }
4419 handled = event.ctrlKey || event.metaKey;
4420 break; // -1 week on ctrl or command +up
4421 case 39: if (event.ctrlKey || event.metaKey) {
4422 $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
4423 }
4424 handled = event.ctrlKey || event.metaKey;
4425 // +1 day on ctrl or command +right
4426 if (event.originalEvent.altKey) {
4427 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
4428 +$.datepicker._get(inst, "stepBigMonths") :
4429 +$.datepicker._get(inst, "stepMonths")), "M");
4430 }
4431 // next month/year on alt +right
4432 break;
4433 case 40: if (event.ctrlKey || event.metaKey) {
4434 $.datepicker._adjustDate(event.target, +7, "D");
4435 }
4436 handled = event.ctrlKey || event.metaKey;
4437 break; // +1 week on ctrl or command +down
4438 default: handled = false;
4439 }
4440 } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
4441 $.datepicker._showDatepicker(this);
4442 } else {
4443 handled = false;
4444 }
4445
4446 if (handled) {
4447 event.preventDefault();
4448 event.stopPropagation();
4449 }
4450 },
4451
4452 /* Filter entered characters - based on date format. */
4453 _doKeyPress: function(event) {
4454 var chars, chr,
4455 inst = $.datepicker._getInst(event.target);
4456
4457 if ($.datepicker._get(inst, "constrainInput")) {
4458 chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
4459 chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
4460 return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
4461 }
4462 },
4463
4464 /* Synchronise manual entry and field/alternate field. */
4465 _doKeyUp: function(event) {
4466 var date,
4467 inst = $.datepicker._getInst(event.target);
4468
4469 if (inst.input.val() !== inst.lastVal) {
4470 try {
4471 date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
4472 (inst.input ? inst.input.val() : null),
4473 $.datepicker._getFormatConfig(inst));
4474
4475 if (date) { // only if valid
4476 $.datepicker._setDateFromField(inst);
4477 $.datepicker._updateAlternate(inst);
4478 $.datepicker._updateDatepicker(inst);
4479 }
4480 }
4481 catch (err) {
4482 }
4483 }
4484 return true;
4485 },
4486
4487 /* Pop-up the date picker for a given input field.
4488 * If false returned from beforeShow event handler do not show.
4489 * @param input element - the input field attached to the date picker or
4490 * event - if triggered by focus
4491 */
4492 _showDatepicker: function(input) {
4493 input = input.target || input;
4494 if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
4495 input = $("input", input.parentNode)[0];
4496 }
4497
4498 if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
4499 return;
4500 }
4501
4502 var inst, beforeShow, beforeShowSettings, isFixed,
4503 offset, showAnim, duration;
4504
4505 inst = $.datepicker._getInst(input);
4506 if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
4507 $.datepicker._curInst.dpDiv.stop(true, true);
4508 if ( inst && $.datepicker._datepickerShowing ) {
4509 $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
4510 }
4511 }
4512
4513 beforeShow = $.datepicker._get(inst, "beforeShow");
4514 beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
4515 if(beforeShowSettings === false){
4516 return;
4517 }
4518 datepicker_extendRemove(inst.settings, beforeShowSettings);
4519
4520 inst.lastVal = null;
4521 $.datepicker._lastInput = input;
4522 $.datepicker._setDateFromField(inst);
4523
4524 if ($.datepicker._inDialog) { // hide cursor
4525 input.value = "";
4526 }
4527 if (!$.datepicker._pos) { // position below input
4528 $.datepicker._pos = $.datepicker._findPos(input);
4529 $.datepicker._pos[1] += input.offsetHeight; // add the height
4530 }
4531
4532 isFixed = false;
4533 $(input).parents().each(function() {
4534 isFixed |= $(this).css("position") === "fixed";
4535 return !isFixed;
4536 });
4537
4538 offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
4539 $.datepicker._pos = null;
4540 //to avoid flashes on Firefox
4541 inst.dpDiv.empty();
4542 // determine sizing offscreen
4543 inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
4544 $.datepicker._updateDatepicker(inst);
4545 // fix width for dynamic number of date pickers
4546 // and adjust position before showing
4547 offset = $.datepicker._checkOffset(inst, offset, isFixed);
4548 inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
4549 "static" : (isFixed ? "fixed" : "absolute")), display: "none",
4550 left: offset.left + "px", top: offset.top + "px"});
4551
4552 if (!inst.inline) {
4553 showAnim = $.datepicker._get(inst, "showAnim");
4554 duration = $.datepicker._get(inst, "duration");
4555 inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
4556 $.datepicker._datepickerShowing = true;
4557
4558 if ( $.effects && $.effects.effect[ showAnim ] ) {
4559 inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
4560 } else {
4561 inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
4562 }
4563
4564 if ( $.datepicker._shouldFocusInput( inst ) ) {
4565 inst.input.focus();
4566 }
4567
4568 $.datepicker._curInst = inst;
4569 }
4570 },
4571
4572 /* Generate the date picker content. */
4573 _updateDatepicker: function(inst) {
4574 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
4575 datepicker_instActive = inst; // for delegate hover events
4576 inst.dpDiv.empty().append(this._generateHTML(inst));
4577 this._attachHandlers(inst);
4578
4579 var origyearshtml,
4580 numMonths = this._getNumberOfMonths(inst),
4581 cols = numMonths[1],
4582 width = 17,
4583 activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
4584
4585 if ( activeCell.length > 0 ) {
4586 datepicker_handleMouseover.apply( activeCell.get( 0 ) );
4587 }
4588
4589 inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
4590 if (cols > 1) {
4591 inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
4592 }
4593 inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
4594 "Class"]("ui-datepicker-multi");
4595 inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
4596 "Class"]("ui-datepicker-rtl");
4597
4598 if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
4599 inst.input.focus();
4600 }
4601
4602 // deffered render of the years select (to avoid flashes on Firefox)
4603 if( inst.yearshtml ){
4604 origyearshtml = inst.yearshtml;
4605 setTimeout(function(){
4606 //assure that inst.yearshtml didn't change.
4607 if( origyearshtml === inst.yearshtml && inst.yearshtml ){
4608 inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
4609 }
4610 origyearshtml = inst.yearshtml = null;
4611 }, 0);
4612 }
4613 },
4614
4615 // #6694 - don't focus the input if it's already focused
4616 // this breaks the change event in IE
4617 // Support: IE and jQuery <1.9
4618 _shouldFocusInput: function( inst ) {
4619 return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
4620 },
4621
4622 /* Check positioning to remain on screen. */
4623 _checkOffset: function(inst, offset, isFixed) {
4624 var dpWidth = inst.dpDiv.outerWidth(),
4625 dpHeight = inst.dpDiv.outerHeight(),
4626 inputWidth = inst.input ? inst.input.outerWidth() : 0,
4627 inputHeight = inst.input ? inst.input.outerHeight() : 0,
4628 viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
4629 viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
4630
4631 offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
4632 offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
4633 offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
4634
4635 // now check if datepicker is showing outside window viewport - move to a better place if so.
4636 offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
4637 Math.abs(offset.left + dpWidth - viewWidth) : 0);
4638 offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
4639 Math.abs(dpHeight + inputHeight) : 0);
4640
4641 return offset;
4642 },
4643
4644 /* Find an object's position on the screen. */
4645 _findPos: function(obj) {
4646 var position,
4647 inst = this._getInst(obj),
4648 isRTL = this._get(inst, "isRTL");
4649
4650 while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
4651 obj = obj[isRTL ? "previousSibling" : "nextSibling"];
4652 }
4653
4654 position = $(obj).offset();
4655 return [position.left, position.top];
4656 },
4657
4658 /* Hide the date picker from view.
4659 * @param input element - the input field attached to the date picker
4660 */
4661 _hideDatepicker: function(input) {
4662 var showAnim, duration, postProcess, onClose,
4663 inst = this._curInst;
4664
4665 if (!inst || (input && inst !== $.data(input, "datepicker"))) {
4666 return;
4667 }
4668
4669 if (this._datepickerShowing) {
4670 showAnim = this._get(inst, "showAnim");
4671 duration = this._get(inst, "duration");
4672 postProcess = function() {
4673 $.datepicker._tidyDialog(inst);
4674 };
4675
4676 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
4677 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
4678 inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
4679 } else {
4680 inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
4681 (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
4682 }
4683
4684 if (!showAnim) {
4685 postProcess();
4686 }
4687 this._datepickerShowing = false;
4688
4689 onClose = this._get(inst, "onClose");
4690 if (onClose) {
4691 onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
4692 }
4693
4694 this._lastInput = null;
4695 if (this._inDialog) {
4696 this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
4697 if ($.blockUI) {
4698 $.unblockUI();
4699 $("body").append(this.dpDiv);
4700 }
4701 }
4702 this._inDialog = false;
4703 }
4704 },
4705
4706 /* Tidy up after a dialog display. */
4707 _tidyDialog: function(inst) {
4708 inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");
4709 },
4710
4711 /* Close date picker if clicked elsewhere. */
4712 _checkExternalClick: function(event) {
4713 if (!$.datepicker._curInst) {
4714 return;
4715 }
4716
4717 var $target = $(event.target),
4718 inst = $.datepicker._getInst($target[0]);
4719
4720 if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
4721 $target.parents("#" + $.datepicker._mainDivId).length === 0 &&
4722 !$target.hasClass($.datepicker.markerClassName) &&
4723 !$target.closest("." + $.datepicker._triggerClass).length &&
4724 $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
4725 ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
4726 $.datepicker._hideDatepicker();
4727 }
4728 },
4729
4730 /* Adjust one of the date sub-fields. */
4731 _adjustDate: function(id, offset, period) {
4732 var target = $(id),
4733 inst = this._getInst(target[0]);
4734
4735 if (this._isDisabledDatepicker(target[0])) {
4736 return;
4737 }
4738 this._adjustInstDate(inst, offset +
4739 (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
4740 period);
4741 this._updateDatepicker(inst);
4742 },
4743
4744 /* Action for current link. */
4745 _gotoToday: function(id) {
4746 var date,
4747 target = $(id),
4748 inst = this._getInst(target[0]);
4749
4750 if (this._get(inst, "gotoCurrent") && inst.currentDay) {
4751 inst.selectedDay = inst.currentDay;
4752 inst.drawMonth = inst.selectedMonth = inst.currentMonth;
4753 inst.drawYear = inst.selectedYear = inst.currentYear;
4754 } else {
4755 date = new Date();
4756 inst.selectedDay = date.getDate();
4757 inst.drawMonth = inst.selectedMonth = date.getMonth();
4758 inst.drawYear = inst.selectedYear = date.getFullYear();
4759 }
4760 this._notifyChange(inst);
4761 this._adjustDate(target);
4762 },
4763
4764 /* Action for selecting a new month/year. */
4765 _selectMonthYear: function(id, select, period) {
4766 var target = $(id),
4767 inst = this._getInst(target[0]);
4768
4769 inst["selected" + (period === "M" ? "Month" : "Year")] =
4770 inst["draw" + (period === "M" ? "Month" : "Year")] =
4771 parseInt(select.options[select.selectedIndex].value,10);
4772
4773 this._notifyChange(inst);
4774 this._adjustDate(target);
4775 },
4776
4777 /* Action for selecting a day. */
4778 _selectDay: function(id, month, year, td) {
4779 var inst,
4780 target = $(id);
4781
4782 if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
4783 return;
4784 }
4785
4786 inst = this._getInst(target[0]);
4787 inst.selectedDay = inst.currentDay = $("a", td).html();
4788 inst.selectedMonth = inst.currentMonth = month;
4789 inst.selectedYear = inst.currentYear = year;
4790 this._selectDate(id, this._formatDate(inst,
4791 inst.currentDay, inst.currentMonth, inst.currentYear));
4792 },
4793
4794 /* Erase the input field and hide the date picker. */
4795 _clearDate: function(id) {
4796 var target = $(id);
4797 this._selectDate(target, "");
4798 },
4799
4800 /* Update the input field with the selected date. */
4801 _selectDate: function(id, dateStr) {
4802 var onSelect,
4803 target = $(id),
4804 inst = this._getInst(target[0]);
4805
4806 dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
4807 if (inst.input) {
4808 inst.input.val(dateStr);
4809 }
4810 this._updateAlternate(inst);
4811
4812 onSelect = this._get(inst, "onSelect");
4813 if (onSelect) {
4814 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
4815 } else if (inst.input) {
4816 inst.input.trigger("change"); // fire the change event
4817 }
4818
4819 if (inst.inline){
4820 this._updateDatepicker(inst);
4821 } else {
4822 this._hideDatepicker();
4823 this._lastInput = inst.input[0];
4824 if (typeof(inst.input[0]) !== "object") {
4825 inst.input.focus(); // restore focus
4826 }
4827 this._lastInput = null;
4828 }
4829 },
4830
4831 /* Update any alternate field to synchronise with the main field. */
4832 _updateAlternate: function(inst) {
4833 var altFormat, date, dateStr,
4834 altField = this._get(inst, "altField");
4835
4836 if (altField) { // update alternate field too
4837 altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
4838 date = this._getDate(inst);
4839 dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
4840 $(altField).each(function() { $(this).val(dateStr); });
4841 }
4842 },
4843
4844 /* Set as beforeShowDay function to prevent selection of weekends.
4845 * @param date Date - the date to customise
4846 * @return [boolean, string] - is this date selectable?, what is its CSS class?
4847 */
4848 noWeekends: function(date) {
4849 var day = date.getDay();
4850 return [(day > 0 && day < 6), ""];
4851 },
4852
4853 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
4854 * @param date Date - the date to get the week for
4855 * @return number - the number of the week within the year that contains this date
4856 */
4857 iso8601Week: function(date) {
4858 var time,
4859 checkDate = new Date(date.getTime());
4860
4861 // Find Thursday of this week starting on Monday
4862 checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
4863
4864 time = checkDate.getTime();
4865 checkDate.setMonth(0); // Compare with Jan 1
4866 checkDate.setDate(1);
4867 return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
4868 },
4869
4870 /* Parse a string value into a date object.
4871 * See formatDate below for the possible formats.
4872 *
4873 * @param format string - the expected format of the date
4874 * @param value string - the date in the above format
4875 * @param settings Object - attributes include:
4876 * shortYearCutoff number - the cutoff year for determining the century (optional)
4877 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
4878 * dayNames string[7] - names of the days from Sunday (optional)
4879 * monthNamesShort string[12] - abbreviated names of the months (optional)
4880 * monthNames string[12] - names of the months (optional)
4881 * @return Date - the extracted date value or null if value is blank
4882 */
4883 parseDate: function (format, value, settings) {
4884 if (format == null || value == null) {
4885 throw "Invalid arguments";
4886 }
4887
4888 value = (typeof value === "object" ? value.toString() : value + "");
4889 if (value === "") {
4890 return null;
4891 }
4892
4893 var iFormat, dim, extra,
4894 iValue = 0,
4895 shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
4896 shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
4897 new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
4898 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
4899 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
4900 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
4901 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
4902 year = -1,
4903 month = -1,
4904 day = -1,
4905 doy = -1,
4906 literal = false,
4907 date,
4908 // Check whether a format character is doubled
4909 lookAhead = function(match) {
4910 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
4911 if (matches) {
4912 iFormat++;
4913 }
4914 return matches;
4915 },
4916 // Extract a number from the string value
4917 getNumber = function(match) {
4918 var isDoubled = lookAhead(match),
4919 size = (match === "@" ? 14 : (match === "!" ? 20 :
4920 (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
4921 minSize = (match === "y" ? size : 1),
4922 digits = new RegExp("^\\d{" + minSize + "," + size + "}"),
4923 num = value.substring(iValue).match(digits);
4924 if (!num) {
4925 throw "Missing number at position " + iValue;
4926 }
4927 iValue += num[0].length;
4928 return parseInt(num[0], 10);
4929 },
4930 // Extract a name from the string value and convert to an index
4931 getName = function(match, shortNames, longNames) {
4932 var index = -1,
4933 names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
4934 return [ [k, v] ];
4935 }).sort(function (a, b) {
4936 return -(a[1].length - b[1].length);
4937 });
4938
4939 $.each(names, function (i, pair) {
4940 var name = pair[1];
4941 if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
4942 index = pair[0];
4943 iValue += name.length;
4944 return false;
4945 }
4946 });
4947 if (index !== -1) {
4948 return index + 1;
4949 } else {
4950 throw "Unknown name at position " + iValue;
4951 }
4952 },
4953 // Confirm that a literal character matches the string value
4954 checkLiteral = function() {
4955 if (value.charAt(iValue) !== format.charAt(iFormat)) {
4956 throw "Unexpected literal at position " + iValue;
4957 }
4958 iValue++;
4959 };
4960
4961 for (iFormat = 0; iFormat < format.length; iFormat++) {
4962 if (literal) {
4963 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
4964 literal = false;
4965 } else {
4966 checkLiteral();
4967 }
4968 } else {
4969 switch (format.charAt(iFormat)) {
4970 case "d":
4971 day = getNumber("d");
4972 break;
4973 case "D":
4974 getName("D", dayNamesShort, dayNames);
4975 break;
4976 case "o":
4977 doy = getNumber("o");
4978 break;
4979 case "m":
4980 month = getNumber("m");
4981 break;
4982 case "M":
4983 month = getName("M", monthNamesShort, monthNames);
4984 break;
4985 case "y":
4986 year = getNumber("y");
4987 break;
4988 case "@":
4989 date = new Date(getNumber("@"));
4990 year = date.getFullYear();
4991 month = date.getMonth() + 1;
4992 day = date.getDate();
4993 break;
4994 case "!":
4995 date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
4996 year = date.getFullYear();
4997 month = date.getMonth() + 1;
4998 day = date.getDate();
4999 break;
5000 case "'":
5001 if (lookAhead("'")){
5002 checkLiteral();
5003 } else {
5004 literal = true;
5005 }
5006 break;
5007 default:
5008 checkLiteral();
5009 }
5010 }
5011 }
5012
5013 if (iValue < value.length){
5014 extra = value.substr(iValue);
5015 if (!/^\s+/.test(extra)) {
5016 throw "Extra/unparsed characters found in date: " + extra;
5017 }
5018 }
5019
5020 if (year === -1) {
5021 year = new Date().getFullYear();
5022 } else if (year < 100) {
5023 year += new Date().getFullYear() - new Date().getFullYear() % 100 +
5024 (year <= shortYearCutoff ? 0 : -100);
5025 }
5026
5027 if (doy > -1) {
5028 month = 1;
5029 day = doy;
5030 do {
5031 dim = this._getDaysInMonth(year, month - 1);
5032 if (day <= dim) {
5033 break;
5034 }
5035 month++;
5036 day -= dim;
5037 } while (true);
5038 }
5039
5040 date = this._daylightSavingAdjust(new Date(year, month - 1, day));
5041 if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
5042 throw "Invalid date"; // E.g. 31/02/00
5043 }
5044 return date;
5045 },
5046
5047 /* Standard date formats. */
5048 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
5049 COOKIE: "D, dd M yy",
5050 ISO_8601: "yy-mm-dd",
5051 RFC_822: "D, d M y",
5052 RFC_850: "DD, dd-M-y",
5053 RFC_1036: "D, d M y",
5054 RFC_1123: "D, d M yy",
5055 RFC_2822: "D, d M yy",
5056 RSS: "D, d M y", // RFC 822
5057 TICKS: "!",
5058 TIMESTAMP: "@",
5059 W3C: "yy-mm-dd", // ISO 8601
5060
5061 _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
5062 Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
5063
5064 /* Format a date object into a string value.
5065 * The format can be combinations of the following:
5066 * d - day of month (no leading zero)
5067 * dd - day of month (two digit)
5068 * o - day of year (no leading zeros)
5069 * oo - day of year (three digit)
5070 * D - day name short
5071 * DD - day name long
5072 * m - month of year (no leading zero)
5073 * mm - month of year (two digit)
5074 * M - month name short
5075 * MM - month name long
5076 * y - year (two digit)
5077 * yy - year (four digit)
5078 * @ - Unix timestamp (ms since 01/01/1970)
5079 * ! - Windows ticks (100ns since 01/01/0001)
5080 * "..." - literal text
5081 * '' - single quote
5082 *
5083 * @param format string - the desired format of the date
5084 * @param date Date - the date value to format
5085 * @param settings Object - attributes include:
5086 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
5087 * dayNames string[7] - names of the days from Sunday (optional)
5088 * monthNamesShort string[12] - abbreviated names of the months (optional)
5089 * monthNames string[12] - names of the months (optional)
5090 * @return string - the date in the above format
5091 */
5092 formatDate: function (format, date, settings) {
5093 if (!date) {
5094 return "";
5095 }
5096
5097 var iFormat,
5098 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
5099 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
5100 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
5101 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
5102 // Check whether a format character is doubled
5103 lookAhead = function(match) {
5104 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
5105 if (matches) {
5106 iFormat++;
5107 }
5108 return matches;
5109 },
5110 // Format a number, with leading zero if necessary
5111 formatNumber = function(match, value, len) {
5112 var num = "" + value;
5113 if (lookAhead(match)) {
5114 while (num.length < len) {
5115 num = "0" + num;
5116 }
5117 }
5118 return num;
5119 },
5120 // Format a name, short or long as requested
5121 formatName = function(match, value, shortNames, longNames) {
5122 return (lookAhead(match) ? longNames[value] : shortNames[value]);
5123 },
5124 output = "",
5125 literal = false;
5126
5127 if (date) {
5128 for (iFormat = 0; iFormat < format.length; iFormat++) {
5129 if (literal) {
5130 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
5131 literal = false;
5132 } else {
5133 output += format.charAt(iFormat);
5134 }
5135 } else {
5136 switch (format.charAt(iFormat)) {
5137 case "d":
5138 output += formatNumber("d", date.getDate(), 2);
5139 break;
5140 case "D":
5141 output += formatName("D", date.getDay(), dayNamesShort, dayNames);
5142 break;
5143 case "o":
5144 output += formatNumber("o",
5145 Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
5146 break;
5147 case "m":
5148 output += formatNumber("m", date.getMonth() + 1, 2);
5149 break;
5150 case "M":
5151 output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
5152 break;
5153 case "y":
5154 output += (lookAhead("y") ? date.getFullYear() :
5155 (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
5156 break;
5157 case "@":
5158 output += date.getTime();
5159 break;
5160 case "!":
5161 output += date.getTime() * 10000 + this._ticksTo1970;
5162 break;
5163 case "'":
5164 if (lookAhead("'")) {
5165 output += "'";
5166 } else {
5167 literal = true;
5168 }
5169 break;
5170 default:
5171 output += format.charAt(iFormat);
5172 }
5173 }
5174 }
5175 }
5176 return output;
5177 },
5178
5179 /* Extract all possible characters from the date format. */
5180 _possibleChars: function (format) {
5181 var iFormat,
5182 chars = "",
5183 literal = false,
5184 // Check whether a format character is doubled
5185 lookAhead = function(match) {
5186 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
5187 if (matches) {
5188 iFormat++;
5189 }
5190 return matches;
5191 };
5192
5193 for (iFormat = 0; iFormat < format.length; iFormat++) {
5194 if (literal) {
5195 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
5196 literal = false;
5197 } else {
5198 chars += format.charAt(iFormat);
5199 }
5200 } else {
5201 switch (format.charAt(iFormat)) {
5202 case "d": case "m": case "y": case "@":
5203 chars += "0123456789";
5204 break;
5205 case "D": case "M":
5206 return null; // Accept anything
5207 case "'":
5208 if (lookAhead("'")) {
5209 chars += "'";
5210 } else {
5211 literal = true;
5212 }
5213 break;
5214 default:
5215 chars += format.charAt(iFormat);
5216 }
5217 }
5218 }
5219 return chars;
5220 },
5221
5222 /* Get a setting value, defaulting if necessary. */
5223 _get: function(inst, name) {
5224 return inst.settings[name] !== undefined ?
5225 inst.settings[name] : this._defaults[name];
5226 },
5227
5228 /* Parse existing date and initialise date picker. */
5229 _setDateFromField: function(inst, noDefault) {
5230 if (inst.input.val() === inst.lastVal) {
5231 return;
5232 }
5233
5234 var dateFormat = this._get(inst, "dateFormat"),
5235 dates = inst.lastVal = inst.input ? inst.input.val() : null,
5236 defaultDate = this._getDefaultDate(inst),
5237 date = defaultDate,
5238 settings = this._getFormatConfig(inst);
5239
5240 try {
5241 date = this.parseDate(dateFormat, dates, settings) || defaultDate;
5242 } catch (event) {
5243 dates = (noDefault ? "" : dates);
5244 }
5245 inst.selectedDay = date.getDate();
5246 inst.drawMonth = inst.selectedMonth = date.getMonth();
5247 inst.drawYear = inst.selectedYear = date.getFullYear();
5248 inst.currentDay = (dates ? date.getDate() : 0);
5249 inst.currentMonth = (dates ? date.getMonth() : 0);
5250 inst.currentYear = (dates ? date.getFullYear() : 0);
5251 this._adjustInstDate(inst);
5252 },
5253
5254 /* Retrieve the default date shown on opening. */
5255 _getDefaultDate: function(inst) {
5256 return this._restrictMinMax(inst,
5257 this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
5258 },
5259
5260 /* A date may be specified as an exact value or a relative one. */
5261 _determineDate: function(inst, date, defaultDate) {
5262 var offsetNumeric = function(offset) {
5263 var date = new Date();
5264 date.setDate(date.getDate() + offset);
5265 return date;
5266 },
5267 offsetString = function(offset) {
5268 try {
5269 return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
5270 offset, $.datepicker._getFormatConfig(inst));
5271 }
5272 catch (e) {
5273 // Ignore
5274 }
5275
5276 var date = (offset.toLowerCase().match(/^c/) ?
5277 $.datepicker._getDate(inst) : null) || new Date(),
5278 year = date.getFullYear(),
5279 month = date.getMonth(),
5280 day = date.getDate(),
5281 pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
5282 matches = pattern.exec(offset);
5283
5284 while (matches) {
5285 switch (matches[2] || "d") {
5286 case "d" : case "D" :
5287 day += parseInt(matches[1],10); break;
5288 case "w" : case "W" :
5289 day += parseInt(matches[1],10) * 7; break;
5290 case "m" : case "M" :
5291 month += parseInt(matches[1],10);
5292 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
5293 break;
5294 case "y": case "Y" :
5295 year += parseInt(matches[1],10);
5296 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
5297 break;
5298 }
5299 matches = pattern.exec(offset);
5300 }
5301 return new Date(year, month, day);
5302 },
5303 newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
5304 (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
5305
5306 newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
5307 if (newDate) {
5308 newDate.setHours(0);
5309 newDate.setMinutes(0);
5310 newDate.setSeconds(0);
5311 newDate.setMilliseconds(0);
5312 }
5313 return this._daylightSavingAdjust(newDate);
5314 },
5315
5316 /* Handle switch to/from daylight saving.
5317 * Hours may be non-zero on daylight saving cut-over:
5318 * > 12 when midnight changeover, but then cannot generate
5319 * midnight datetime, so jump to 1AM, otherwise reset.
5320 * @param date (Date) the date to check
5321 * @return (Date) the corrected date
5322 */
5323 _daylightSavingAdjust: function(date) {
5324 if (!date) {
5325 return null;
5326 }
5327 date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
5328 return date;
5329 },
5330
5331 /* Set the date(s) directly. */
5332 _setDate: function(inst, date, noChange) {
5333 var clear = !date,
5334 origMonth = inst.selectedMonth,
5335 origYear = inst.selectedYear,
5336 newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
5337
5338 inst.selectedDay = inst.currentDay = newDate.getDate();
5339 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
5340 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
5341 if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
5342 this._notifyChange(inst);
5343 }
5344 this._adjustInstDate(inst);
5345 if (inst.input) {
5346 inst.input.val(clear ? "" : this._formatDate(inst));
5347 }
5348 },
5349
5350 /* Retrieve the date(s) directly. */
5351 _getDate: function(inst) {
5352 var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
5353 this._daylightSavingAdjust(new Date(
5354 inst.currentYear, inst.currentMonth, inst.currentDay)));
5355 return startDate;
5356 },
5357
5358 /* Attach the onxxx handlers. These are declared statically so
5359 * they work with static code transformers like Caja.
5360 */
5361 _attachHandlers: function(inst) {
5362 var stepMonths = this._get(inst, "stepMonths"),
5363 id = "#" + inst.id.replace( /\\\\/g, "\\" );
5364 inst.dpDiv.find("[data-handler]").map(function () {
5365 var handler = {
5366 prev: function () {
5367 $.datepicker._adjustDate(id, -stepMonths, "M");
5368 },
5369 next: function () {
5370 $.datepicker._adjustDate(id, +stepMonths, "M");
5371 },
5372 hide: function () {
5373 $.datepicker._hideDatepicker();
5374 },
5375 today: function () {
5376 $.datepicker._gotoToday(id);
5377 },
5378 selectDay: function () {
5379 $.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
5380 return false;
5381 },
5382 selectMonth: function () {
5383 $.datepicker._selectMonthYear(id, this, "M");
5384 return false;
5385 },
5386 selectYear: function () {
5387 $.datepicker._selectMonthYear(id, this, "Y");
5388 return false;
5389 }
5390 };
5391 $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
5392 });
5393 },
5394
5395 /* Generate the HTML for the current state of the date picker. */
5396 _generateHTML: function(inst) {
5397 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
5398 controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
5399 monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
5400 selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
5401 cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
5402 printDate, dRow, tbody, daySettings, otherMonth, unselectable,
5403 tempDate = new Date(),
5404 today = this._daylightSavingAdjust(
5405 new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
5406 isRTL = this._get(inst, "isRTL"),
5407 showButtonPanel = this._get(inst, "showButtonPanel"),
5408 hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
5409 navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
5410 numMonths = this._getNumberOfMonths(inst),
5411 showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
5412 stepMonths = this._get(inst, "stepMonths"),
5413 isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
5414 currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
5415 new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
5416 minDate = this._getMinMaxDate(inst, "min"),
5417 maxDate = this._getMinMaxDate(inst, "max"),
5418 drawMonth = inst.drawMonth - showCurrentAtPos,
5419 drawYear = inst.drawYear;
5420
5421 if (drawMonth < 0) {
5422 drawMonth += 12;
5423 drawYear--;
5424 }
5425 if (maxDate) {
5426 maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
5427 maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
5428 maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
5429 while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
5430 drawMonth--;
5431 if (drawMonth < 0) {
5432 drawMonth = 11;
5433 drawYear--;
5434 }
5435 }
5436 }
5437 inst.drawMonth = drawMonth;
5438 inst.drawYear = drawYear;
5439
5440 prevText = this._get(inst, "prevText");
5441 prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
5442 this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
5443 this._getFormatConfig(inst)));
5444
5445 prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
5446 "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
5447 " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
5448 (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>"));
5449
5450 nextText = this._get(inst, "nextText");
5451 nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
5452 this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
5453 this._getFormatConfig(inst)));
5454
5455 next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
5456 "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
5457 " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
5458 (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>"));
5459
5460 currentText = this._get(inst, "currentText");
5461 gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
5462 currentText = (!navigationAsDateFormat ? currentText :
5463 this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
5464
5465 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'>" +
5466 this._get(inst, "closeText") + "</button>" : "");
5467
5468 buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
5469 (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'" +
5470 ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";
5471
5472 firstDay = parseInt(this._get(inst, "firstDay"),10);
5473 firstDay = (isNaN(firstDay) ? 0 : firstDay);
5474
5475 showWeek = this._get(inst, "showWeek");
5476 dayNames = this._get(inst, "dayNames");
5477 dayNamesMin = this._get(inst, "dayNamesMin");
5478 monthNames = this._get(inst, "monthNames");
5479 monthNamesShort = this._get(inst, "monthNamesShort");
5480 beforeShowDay = this._get(inst, "beforeShowDay");
5481 showOtherMonths = this._get(inst, "showOtherMonths");
5482 selectOtherMonths = this._get(inst, "selectOtherMonths");
5483 defaultDate = this._getDefaultDate(inst);
5484 html = "";
5485 dow;
5486 for (row = 0; row < numMonths[0]; row++) {
5487 group = "";
5488 this.maxRows = 4;
5489 for (col = 0; col < numMonths[1]; col++) {
5490 selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
5491 cornerClass = " ui-corner-all";
5492 calender = "";
5493 if (isMultiMonth) {
5494 calender += "<div class='ui-datepicker-group";
5495 if (numMonths[1] > 1) {
5496 switch (col) {
5497 case 0: calender += " ui-datepicker-group-first";
5498 cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
5499 case numMonths[1]-1: calender += " ui-datepicker-group-last";
5500 cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
5501 default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
5502 }
5503 }
5504 calender += "'>";
5505 }
5506 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
5507 (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
5508 (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
5509 this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
5510 row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
5511 "</div><table class='ui-datepicker-calendar'><thead>" +
5512 "<tr>";
5513 thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
5514 for (dow = 0; dow < 7; dow++) { // days of the week
5515 day = (dow + firstDay) % 7;
5516 thead += "<th scope='col'" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
5517 "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
5518 }
5519 calender += thead + "</tr></thead><tbody>";
5520 daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
5521 if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
5522 inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
5523 }
5524 leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
5525 curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
5526 numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
5527 this.maxRows = numRows;
5528 printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
5529 for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
5530 calender += "<tr>";
5531 tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
5532 this._get(inst, "calculateWeek")(printDate) + "</td>");
5533 for (dow = 0; dow < 7; dow++) { // create date picker days
5534 daySettings = (beforeShowDay ?
5535 beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
5536 otherMonth = (printDate.getMonth() !== drawMonth);
5537 unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
5538 (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
5539 tbody += "<td class='" +
5540 ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
5541 (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
5542 ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
5543 (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
5544 // or defaultDate is current printedDate and defaultDate is selectedDate
5545 " " + this._dayOverClass : "") + // highlight selected day
5546 (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days
5547 (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
5548 (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
5549 (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
5550 ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "&#39;") + "'" : "") + // cell title
5551 (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
5552 (otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
5553 (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
5554 (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
5555 (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
5556 (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
5557 "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
5558 printDate.setDate(printDate.getDate() + 1);
5559 printDate = this._daylightSavingAdjust(printDate);
5560 }
5561 calender += tbody + "</tr>";
5562 }
5563 drawMonth++;
5564 if (drawMonth > 11) {
5565 drawMonth = 0;
5566 drawYear++;
5567 }
5568 calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
5569 ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
5570 group += calender;
5571 }
5572 html += group;
5573 }
5574 html += buttonPanel;
5575 inst._keyEvent = false;
5576 return html;
5577 },
5578
5579 /* Generate the month and year header. */
5580 _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
5581 secondary, monthNames, monthNamesShort) {
5582
5583 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
5584 changeMonth = this._get(inst, "changeMonth"),
5585 changeYear = this._get(inst, "changeYear"),
5586 showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
5587 html = "<div class='ui-datepicker-title'>",
5588 monthHtml = "";
5589
5590 // month selection
5591 if (secondary || !changeMonth) {
5592 monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
5593 } else {
5594 inMinYear = (minDate && minDate.getFullYear() === drawYear);
5595 inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
5596 monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
5597 for ( month = 0; month < 12; month++) {
5598 if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
5599 monthHtml += "<option value='" + month + "'" +
5600 (month === drawMonth ? " selected='selected'" : "") +
5601 ">" + monthNamesShort[month] + "</option>";
5602 }
5603 }
5604 monthHtml += "</select>";
5605 }
5606
5607 if (!showMonthAfterYear) {
5608 html += monthHtml + (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "");
5609 }
5610
5611 // year selection
5612 if ( !inst.yearshtml ) {
5613 inst.yearshtml = "";
5614 if (secondary || !changeYear) {
5615 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
5616 } else {
5617 // determine range of years to display
5618 years = this._get(inst, "yearRange").split(":");
5619 thisYear = new Date().getFullYear();
5620 determineYear = function(value) {
5621 var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
5622 (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
5623 parseInt(value, 10)));
5624 return (isNaN(year) ? thisYear : year);
5625 };
5626 year = determineYear(years[0]);
5627 endYear = Math.max(year, determineYear(years[1] || ""));
5628 year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
5629 endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
5630 inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
5631 for (; year <= endYear; year++) {
5632 inst.yearshtml += "<option value='" + year + "'" +
5633 (year === drawYear ? " selected='selected'" : "") +
5634 ">" + year + "</option>";
5635 }
5636 inst.yearshtml += "</select>";
5637
5638 html += inst.yearshtml;
5639 inst.yearshtml = null;
5640 }
5641 }
5642
5643 html += this._get(inst, "yearSuffix");
5644 if (showMonthAfterYear) {
5645 html += (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "") + monthHtml;
5646 }
5647 html += "</div>"; // Close datepicker_header
5648 return html;
5649 },
5650
5651 /* Adjust one of the date sub-fields. */
5652 _adjustInstDate: function(inst, offset, period) {
5653 var year = inst.drawYear + (period === "Y" ? offset : 0),
5654 month = inst.drawMonth + (period === "M" ? offset : 0),
5655 day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
5656 date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));
5657
5658 inst.selectedDay = date.getDate();
5659 inst.drawMonth = inst.selectedMonth = date.getMonth();
5660 inst.drawYear = inst.selectedYear = date.getFullYear();
5661 if (period === "M" || period === "Y") {
5662 this._notifyChange(inst);
5663 }
5664 },
5665
5666 /* Ensure a date is within any min/max bounds. */
5667 _restrictMinMax: function(inst, date) {
5668 var minDate = this._getMinMaxDate(inst, "min"),
5669 maxDate = this._getMinMaxDate(inst, "max"),
5670 newDate = (minDate && date < minDate ? minDate : date);
5671 return (maxDate && newDate > maxDate ? maxDate : newDate);
5672 },
5673
5674 /* Notify change of month/year. */
5675 _notifyChange: function(inst) {
5676 var onChange = this._get(inst, "onChangeMonthYear");
5677 if (onChange) {
5678 onChange.apply((inst.input ? inst.input[0] : null),
5679 [inst.selectedYear, inst.selectedMonth + 1, inst]);
5680 }
5681 },
5682
5683 /* Determine the number of months to show. */
5684 _getNumberOfMonths: function(inst) {
5685 var numMonths = this._get(inst, "numberOfMonths");
5686 return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
5687 },
5688
5689 /* Determine the current maximum date - ensure no time components are set. */
5690 _getMinMaxDate: function(inst, minMax) {
5691 return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
5692 },
5693
5694 /* Find the number of days in a given month. */
5695 _getDaysInMonth: function(year, month) {
5696 return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
5697 },
5698
5699 /* Find the day of the week of the first of a month. */
5700 _getFirstDayOfMonth: function(year, month) {
5701 return new Date(year, month, 1).getDay();
5702 },
5703
5704 /* Determines if we should allow a "next/prev" month display change. */
5705 _canAdjustMonth: function(inst, offset, curYear, curMonth) {
5706 var numMonths = this._getNumberOfMonths(inst),
5707 date = this._daylightSavingAdjust(new Date(curYear,
5708 curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
5709
5710 if (offset < 0) {
5711 date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
5712 }
5713 return this._isInRange(inst, date);
5714 },
5715
5716 /* Is the given date in the accepted range? */
5717 _isInRange: function(inst, date) {
5718 var yearSplit, currentYear,
5719 minDate = this._getMinMaxDate(inst, "min"),
5720 maxDate = this._getMinMaxDate(inst, "max"),
5721 minYear = null,
5722 maxYear = null,
5723 years = this._get(inst, "yearRange");
5724 if (years){
5725 yearSplit = years.split(":");
5726 currentYear = new Date().getFullYear();
5727 minYear = parseInt(yearSplit[0], 10);
5728 maxYear = parseInt(yearSplit[1], 10);
5729 if ( yearSplit[0].match(/[+\-].*/) ) {
5730 minYear += currentYear;
5731 }
5732 if ( yearSplit[1].match(/[+\-].*/) ) {
5733 maxYear += currentYear;
5734 }
5735 }
5736
5737 return ((!minDate || date.getTime() >= minDate.getTime()) &&
5738 (!maxDate || date.getTime() <= maxDate.getTime()) &&
5739 (!minYear || date.getFullYear() >= minYear) &&
5740 (!maxYear || date.getFullYear() <= maxYear));
5741 },
5742
5743 /* Provide the configuration settings for formatting/parsing. */
5744 _getFormatConfig: function(inst) {
5745 var shortYearCutoff = this._get(inst, "shortYearCutoff");
5746 shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
5747 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
5748 return {shortYearCutoff: shortYearCutoff,
5749 dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
5750 monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
5751 },
5752
5753 /* Format the given date for display. */
5754 _formatDate: function(inst, day, month, year) {
5755 if (!day) {
5756 inst.currentDay = inst.selectedDay;
5757 inst.currentMonth = inst.selectedMonth;
5758 inst.currentYear = inst.selectedYear;
5759 }
5760 var date = (day ? (typeof day === "object" ? day :
5761 this._daylightSavingAdjust(new Date(year, month, day))) :
5762 this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
5763 return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
5764 }
5765 });
5766
5767 /*
5768 * Bind hover events for datepicker elements.
5769 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
5770 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
5771 */
5772 function datepicker_bindHover(dpDiv) {
5773 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
5774 return dpDiv.delegate(selector, "mouseout", function() {
5775 $(this).removeClass("ui-state-hover");
5776 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
5777 $(this).removeClass("ui-datepicker-prev-hover");
5778 }
5779 if (this.className.indexOf("ui-datepicker-next") !== -1) {
5780 $(this).removeClass("ui-datepicker-next-hover");
5781 }
5782 })
5783 .delegate( selector, "mouseover", datepicker_handleMouseover );
5784 }
5785
5786 function datepicker_handleMouseover() {
5787 if (!$.datepicker._isDisabledDatepicker( datepicker_instActive.inline? datepicker_instActive.dpDiv.parent()[0] : datepicker_instActive.input[0])) {
5788 $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
5789 $(this).addClass("ui-state-hover");
5790 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
5791 $(this).addClass("ui-datepicker-prev-hover");
5792 }
5793 if (this.className.indexOf("ui-datepicker-next") !== -1) {
5794 $(this).addClass("ui-datepicker-next-hover");
5795 }
5796 }
5797 }
5798
5799 /* jQuery extend now ignores nulls! */
5800 function datepicker_extendRemove(target, props) {
5801 $.extend(target, props);
5802 for (var name in props) {
5803 if (props[name] == null) {
5804 target[name] = props[name];
5805 }
5806 }
5807 return target;
5808 }
5809
5810 /* Invoke the datepicker functionality.
5811 @param options string - a command, optionally followed by additional parameters or
5812 Object - settings for attaching new datepicker functionality
5813 @return jQuery object */
5814 $.fn.datepicker = function(options){
5815
5816 /* Verify an empty collection wasn't passed - Fixes #6976 */
5817 if ( !this.length ) {
5818 return this;
5819 }
5820
5821 /* Initialise the date picker. */
5822 if (!$.datepicker.initialized) {
5823 $(document).mousedown($.datepicker._checkExternalClick);
5824 $.datepicker.initialized = true;
5825 }
5826
5827 /* Append datepicker main container to body if not exist. */
5828 if ($("#"+$.datepicker._mainDivId).length === 0) {
5829 $("body").append($.datepicker.dpDiv);
5830 }
5831
5832 var otherArgs = Array.prototype.slice.call(arguments, 1);
5833 if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
5834 return $.datepicker["_" + options + "Datepicker"].
5835 apply($.datepicker, [this[0]].concat(otherArgs));
5836 }
5837 if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
5838 return $.datepicker["_" + options + "Datepicker"].
5839 apply($.datepicker, [this[0]].concat(otherArgs));
5840 }
5841 return this.each(function() {
5842 typeof options === "string" ?
5843 $.datepicker["_" + options + "Datepicker"].
5844 apply($.datepicker, [this].concat(otherArgs)) :
5845 $.datepicker._attachDatepicker(this, options);
5846 });
5847 };
5848
5849 $.datepicker = new Datepicker(); // singleton instance
5850 $.datepicker.initialized = false;
5851 $.datepicker.uuid = new Date().getTime();
5852 $.datepicker.version = "1.11.4";
5853
5854 var datepicker = $.datepicker;
5855
5856
5857 /*!
5858 * jQuery UI Draggable 1.11.4
5859 * http://jqueryui.com
5860 *
5861 * Copyright jQuery Foundation and other contributors
5862 * Released under the MIT license.
5863 * http://jquery.org/license
5864 *
5865 * http://api.jqueryui.com/draggable/
5866 */
5867
5868
5869 $.widget("ui.draggable", $.ui.mouse, {
5870 version: "1.11.4",
5871 widgetEventPrefix: "drag",
5872 options: {
5873 addClasses: true,
5874 appendTo: "parent",
5875 axis: false,
5876 connectToSortable: false,
5877 containment: false,
5878 cursor: "auto",
5879 cursorAt: false,
5880 grid: false,
5881 handle: false,
5882 helper: "original",
5883 iframeFix: false,
5884 opacity: false,
5885 refreshPositions: false,
5886 revert: false,
5887 revertDuration: 500,
5888 scope: "default",
5889 scroll: true,
5890 scrollSensitivity: 20,
5891 scrollSpeed: 20,
5892 snap: false,
5893 snapMode: "both",
5894 snapTolerance: 20,
5895 stack: false,
5896 zIndex: false,
5897
5898 // callbacks
5899 drag: null,
5900 start: null,
5901 stop: null
5902 },
5903 _create: function() {
5904
5905 if ( this.options.helper === "original" ) {
5906 this._setPositionRelative();
5907 }
5908 if (this.options.addClasses){
5909 this.element.addClass("ui-draggable");
5910 }
5911 if (this.options.disabled){
5912 this.element.addClass("ui-draggable-disabled");
5913 }
5914 this._setHandleClassName();
5915
5916 this._mouseInit();
5917 },
5918
5919 _setOption: function( key, value ) {
5920 this._super( key, value );
5921 if ( key === "handle" ) {
5922 this._removeHandleClassName();
5923 this._setHandleClassName();
5924 }
5925 },
5926
5927 _destroy: function() {
5928 if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
5929 this.destroyOnClear = true;
5930 return;
5931 }
5932 this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
5933 this._removeHandleClassName();
5934 this._mouseDestroy();
5935 },
5936
5937 _mouseCapture: function(event) {
5938 var o = this.options;
5939
5940 this._blurActiveElement( event );
5941
5942 // among others, prevent a drag on a resizable-handle
5943 if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) {
5944 return false;
5945 }
5946
5947 //Quit if we're not on a valid handle
5948 this.handle = this._getHandle(event);
5949 if (!this.handle) {
5950 return false;
5951 }
5952
5953 this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix );
5954
5955 return true;
5956
5957 },
5958
5959 _blockFrames: function( selector ) {
5960 this.iframeBlocks = this.document.find( selector ).map(function() {
5961 var iframe = $( this );
5962
5963 return $( "<div>" )
5964 .css( "position", "absolute" )
5965 .appendTo( iframe.parent() )
5966 .outerWidth( iframe.outerWidth() )
5967 .outerHeight( iframe.outerHeight() )
5968 .offset( iframe.offset() )[ 0 ];
5969 });
5970 },
5971
5972 _unblockFrames: function() {
5973 if ( this.iframeBlocks ) {
5974 this.iframeBlocks.remove();
5975 delete this.iframeBlocks;
5976 }
5977 },
5978
5979 _blurActiveElement: function( event ) {
5980 var document = this.document[ 0 ];
5981
5982 // Only need to blur if the event occurred on the draggable itself, see #10527
5983 if ( !this.handleElement.is( event.target ) ) {
5984 return;
5985 }
5986
5987 // support: IE9
5988 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
5989 try {
5990
5991 // Support: IE9, IE10
5992 // If the <body> is blurred, IE will switch windows, see #9520
5993 if ( document.activeElement && document.activeElement.nodeName.toLowerCase() !== "body" ) {
5994
5995 // Blur any element that currently has focus, see #4261
5996 $( document.activeElement ).blur();
5997 }
5998 } catch ( error ) {}
5999 },
6000
6001 _mouseStart: function(event) {
6002
6003 var o = this.options;
6004
6005 //Create and append the visible helper
6006 this.helper = this._createHelper(event);
6007
6008 this.helper.addClass("ui-draggable-dragging");
6009
6010 //Cache the helper size
6011 this._cacheHelperProportions();
6012
6013 //If ddmanager is used for droppables, set the global draggable
6014 if ($.ui.ddmanager) {
6015 $.ui.ddmanager.current = this;
6016 }
6017
6018 /*
6019 * - Position generation -
6020 * This block generates everything position related - it's the core of draggables.
6021 */
6022
6023 //Cache the margins of the original element
6024 this._cacheMargins();
6025
6026 //Store the helper's css position
6027 this.cssPosition = this.helper.css( "position" );
6028 this.scrollParent = this.helper.scrollParent( true );
6029 this.offsetParent = this.helper.offsetParent();
6030 this.hasFixedAncestor = this.helper.parents().filter(function() {
6031 return $( this ).css( "position" ) === "fixed";
6032 }).length > 0;
6033
6034 //The element's absolute position on the page minus margins
6035 this.positionAbs = this.element.offset();
6036 this._refreshOffsets( event );
6037
6038 //Generate the original position
6039 this.originalPosition = this.position = this._generatePosition( event, false );
6040 this.originalPageX = event.pageX;
6041 this.originalPageY = event.pageY;
6042
6043 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
6044 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
6045
6046 //Set a containment if given in the options
6047 this._setContainment();
6048
6049 //Trigger event + callbacks
6050 if (this._trigger("start", event) === false) {
6051 this._clear();
6052 return false;
6053 }
6054
6055 //Recache the helper size
6056 this._cacheHelperProportions();
6057
6058 //Prepare the droppable offsets
6059 if ($.ui.ddmanager && !o.dropBehaviour) {
6060 $.ui.ddmanager.prepareOffsets(this, event);
6061 }
6062
6063 // Reset helper's right/bottom css if they're set and set explicit width/height instead
6064 // as this prevents resizing of elements with right/bottom set (see #7772)
6065 this._normalizeRightBottom();
6066
6067 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
6068
6069 //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
6070 if ( $.ui.ddmanager ) {
6071 $.ui.ddmanager.dragStart(this, event);
6072 }
6073
6074 return true;
6075 },
6076
6077 _refreshOffsets: function( event ) {
6078 this.offset = {
6079 top: this.positionAbs.top - this.margins.top,
6080 left: this.positionAbs.left - this.margins.left,
6081 scroll: false,
6082 parent: this._getParentOffset(),
6083 relative: this._getRelativeOffset()
6084 };
6085
6086 this.offset.click = {
6087 left: event.pageX - this.offset.left,
6088 top: event.pageY - this.offset.top
6089 };
6090 },
6091
6092 _mouseDrag: function(event, noPropagation) {
6093 // reset any necessary cached properties (see #5009)
6094 if ( this.hasFixedAncestor ) {
6095 this.offset.parent = this._getParentOffset();
6096 }
6097
6098 //Compute the helpers position
6099 this.position = this._generatePosition( event, true );
6100 this.positionAbs = this._convertPositionTo("absolute");
6101
6102 //Call plugins and callbacks and use the resulting position if something is returned
6103 if (!noPropagation) {
6104 var ui = this._uiHash();
6105 if (this._trigger("drag", event, ui) === false) {
6106 this._mouseUp({});
6107 return false;
6108 }
6109 this.position = ui.position;
6110 }
6111
6112 this.helper[ 0 ].style.left = this.position.left + "px";
6113 this.helper[ 0 ].style.top = this.position.top + "px";
6114
6115 if ($.ui.ddmanager) {
6116 $.ui.ddmanager.drag(this, event);
6117 }
6118
6119 return false;
6120 },
6121
6122 _mouseStop: function(event) {
6123
6124 //If we are using droppables, inform the manager about the drop
6125 var that = this,
6126 dropped = false;
6127 if ($.ui.ddmanager && !this.options.dropBehaviour) {
6128 dropped = $.ui.ddmanager.drop(this, event);
6129 }
6130
6131 //if a drop comes from outside (a sortable)
6132 if (this.dropped) {
6133 dropped = this.dropped;
6134 this.dropped = false;
6135 }
6136
6137 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))) {
6138 $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
6139 if (that._trigger("stop", event) !== false) {
6140 that._clear();
6141 }
6142 });
6143 } else {
6144 if (this._trigger("stop", event) !== false) {
6145 this._clear();
6146 }
6147 }
6148
6149 return false;
6150 },
6151
6152 _mouseUp: function( event ) {
6153 this._unblockFrames();
6154
6155 //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
6156 if ( $.ui.ddmanager ) {
6157 $.ui.ddmanager.dragStop(this, event);
6158 }
6159
6160 // Only need to focus if the event occurred on the draggable itself, see #10527
6161 if ( this.handleElement.is( event.target ) ) {
6162 // The interaction is over; whether or not the click resulted in a drag, focus the element
6163 this.element.focus();
6164 }
6165
6166 return $.ui.mouse.prototype._mouseUp.call(this, event);
6167 },
6168
6169 cancel: function() {
6170
6171 if (this.helper.is(".ui-draggable-dragging")) {
6172 this._mouseUp({});
6173 } else {
6174 this._clear();
6175 }
6176
6177 return this;
6178
6179 },
6180
6181 _getHandle: function(event) {
6182 return this.options.handle ?
6183 !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
6184 true;
6185 },
6186
6187 _setHandleClassName: function() {
6188 this.handleElement = this.options.handle ?
6189 this.element.find( this.options.handle ) : this.element;
6190 this.handleElement.addClass( "ui-draggable-handle" );
6191 },
6192
6193 _removeHandleClassName: function() {
6194 this.handleElement.removeClass( "ui-draggable-handle" );
6195 },
6196
6197 _createHelper: function(event) {
6198
6199 var o = this.options,
6200 helperIsFunction = $.isFunction( o.helper ),
6201 helper = helperIsFunction ?
6202 $( o.helper.apply( this.element[ 0 ], [ event ] ) ) :
6203 ( o.helper === "clone" ?
6204 this.element.clone().removeAttr( "id" ) :
6205 this.element );
6206
6207 if (!helper.parents("body").length) {
6208 helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo));
6209 }
6210
6211 // http://bugs.jqueryui.com/ticket/9446
6212 // a helper function can return the original element
6213 // which wouldn't have been set to relative in _create
6214 if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) {
6215 this._setPositionRelative();
6216 }
6217
6218 if (helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) {
6219 helper.css("position", "absolute");
6220 }
6221
6222 return helper;
6223
6224 },
6225
6226 _setPositionRelative: function() {
6227 if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) {
6228 this.element[ 0 ].style.position = "relative";
6229 }
6230 },
6231
6232 _adjustOffsetFromHelper: function(obj) {
6233 if (typeof obj === "string") {
6234 obj = obj.split(" ");
6235 }
6236 if ($.isArray(obj)) {
6237 obj = { left: +obj[0], top: +obj[1] || 0 };
6238 }
6239 if ("left" in obj) {
6240 this.offset.click.left = obj.left + this.margins.left;
6241 }
6242 if ("right" in obj) {
6243 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
6244 }
6245 if ("top" in obj) {
6246 this.offset.click.top = obj.top + this.margins.top;
6247 }
6248 if ("bottom" in obj) {
6249 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
6250 }
6251 },
6252
6253 _isRootNode: function( element ) {
6254 return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
6255 },
6256
6257 _getParentOffset: function() {
6258
6259 //Get the offsetParent and cache its position
6260 var po = this.offsetParent.offset(),
6261 document = this.document[ 0 ];
6262
6263 // This is a special case where we need to modify a offset calculated on start, since the following happened:
6264 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
6265 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
6266 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
6267 if (this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
6268 po.left += this.scrollParent.scrollLeft();
6269 po.top += this.scrollParent.scrollTop();
6270 }
6271
6272 if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
6273 po = { top: 0, left: 0 };
6274 }
6275
6276 return {
6277 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"), 10) || 0),
6278 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"), 10) || 0)
6279 };
6280
6281 },
6282
6283 _getRelativeOffset: function() {
6284 if ( this.cssPosition !== "relative" ) {
6285 return { top: 0, left: 0 };
6286 }
6287
6288 var p = this.element.position(),
6289 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
6290
6291 return {
6292 top: p.top - ( parseInt(this.helper.css( "top" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
6293 left: p.left - ( parseInt(this.helper.css( "left" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
6294 };
6295
6296 },
6297
6298 _cacheMargins: function() {
6299 this.margins = {
6300 left: (parseInt(this.element.css("marginLeft"), 10) || 0),
6301 top: (parseInt(this.element.css("marginTop"), 10) || 0),
6302 right: (parseInt(this.element.css("marginRight"), 10) || 0),
6303 bottom: (parseInt(this.element.css("marginBottom"), 10) || 0)
6304 };
6305 },
6306
6307 _cacheHelperProportions: function() {
6308 this.helperProportions = {
6309 width: this.helper.outerWidth(),
6310 height: this.helper.outerHeight()
6311 };
6312 },
6313
6314 _setContainment: function() {
6315
6316 var isUserScrollable, c, ce,
6317 o = this.options,
6318 document = this.document[ 0 ];
6319
6320 this.relativeContainer = null;
6321
6322 if ( !o.containment ) {
6323 this.containment = null;
6324 return;
6325 }
6326
6327 if ( o.containment === "window" ) {
6328 this.containment = [
6329 $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
6330 $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
6331 $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left,
6332 $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
6333 ];
6334 return;
6335 }
6336
6337 if ( o.containment === "document") {
6338 this.containment = [
6339 0,
6340 0,
6341 $( document ).width() - this.helperProportions.width - this.margins.left,
6342 ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
6343 ];
6344 return;
6345 }
6346
6347 if ( o.containment.constructor === Array ) {
6348 this.containment = o.containment;
6349 return;
6350 }
6351
6352 if ( o.containment === "parent" ) {
6353 o.containment = this.helper[ 0 ].parentNode;
6354 }
6355
6356 c = $( o.containment );
6357 ce = c[ 0 ];
6358
6359 if ( !ce ) {
6360 return;
6361 }
6362
6363 isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) );
6364
6365 this.containment = [
6366 ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
6367 ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ),
6368 ( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
6369 ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) -
6370 ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) -
6371 this.helperProportions.width -
6372 this.margins.left -
6373 this.margins.right,
6374 ( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
6375 ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) -
6376 ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) -
6377 this.helperProportions.height -
6378 this.margins.top -
6379 this.margins.bottom
6380 ];
6381 this.relativeContainer = c;
6382 },
6383
6384 _convertPositionTo: function(d, pos) {
6385
6386 if (!pos) {
6387 pos = this.position;
6388 }
6389
6390 var mod = d === "absolute" ? 1 : -1,
6391 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
6392
6393 return {
6394 top: (
6395 pos.top + // The absolute mouse position
6396 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
6397 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
6398 ( ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod)
6399 ),
6400 left: (
6401 pos.left + // The absolute mouse position
6402 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
6403 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
6404 ( ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod)
6405 )
6406 };
6407
6408 },
6409
6410 _generatePosition: function( event, constrainPosition ) {
6411
6412 var containment, co, top, left,
6413 o = this.options,
6414 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
6415 pageX = event.pageX,
6416 pageY = event.pageY;
6417
6418 // Cache the scroll
6419 if ( !scrollIsRootNode || !this.offset.scroll ) {
6420 this.offset.scroll = {
6421 top: this.scrollParent.scrollTop(),
6422 left: this.scrollParent.scrollLeft()
6423 };
6424 }
6425
6426 /*
6427 * - Position constraining -
6428 * Constrain the position to a mix of grid, containment.
6429 */
6430
6431 // If we are not dragging yet, we won't check for options
6432 if ( constrainPosition ) {
6433 if ( this.containment ) {
6434 if ( this.relativeContainer ){
6435 co = this.relativeContainer.offset();
6436 containment = [
6437 this.containment[ 0 ] + co.left,
6438 this.containment[ 1 ] + co.top,
6439 this.containment[ 2 ] + co.left,
6440 this.containment[ 3 ] + co.top
6441 ];
6442 } else {
6443 containment = this.containment;
6444 }
6445
6446 if (event.pageX - this.offset.click.left < containment[0]) {
6447 pageX = containment[0] + this.offset.click.left;
6448 }
6449 if (event.pageY - this.offset.click.top < containment[1]) {
6450 pageY = containment[1] + this.offset.click.top;
6451 }
6452 if (event.pageX - this.offset.click.left > containment[2]) {
6453 pageX = containment[2] + this.offset.click.left;
6454 }
6455 if (event.pageY - this.offset.click.top > containment[3]) {
6456 pageY = containment[3] + this.offset.click.top;
6457 }
6458 }
6459
6460 if (o.grid) {
6461 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
6462 top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
6463 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;
6464
6465 left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
6466 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;
6467 }
6468
6469 if ( o.axis === "y" ) {
6470 pageX = this.originalPageX;
6471 }
6472
6473 if ( o.axis === "x" ) {
6474 pageY = this.originalPageY;
6475 }
6476 }
6477
6478 return {
6479 top: (
6480 pageY - // The absolute mouse position
6481 this.offset.click.top - // Click offset (relative to the element)
6482 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
6483 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
6484 ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
6485 ),
6486 left: (
6487 pageX - // The absolute mouse position
6488 this.offset.click.left - // Click offset (relative to the element)
6489 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
6490 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
6491 ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
6492 )
6493 };
6494
6495 },
6496
6497 _clear: function() {
6498 this.helper.removeClass("ui-draggable-dragging");
6499 if (this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) {
6500 this.helper.remove();
6501 }
6502 this.helper = null;
6503 this.cancelHelperRemoval = false;
6504 if ( this.destroyOnClear ) {
6505 this.destroy();
6506 }
6507 },
6508
6509 _normalizeRightBottom: function() {
6510 if ( this.options.axis !== "y" && this.helper.css( "right" ) !== "auto" ) {
6511 this.helper.width( this.helper.width() );
6512 this.helper.css( "right", "auto" );
6513 }
6514 if ( this.options.axis !== "x" && this.helper.css( "bottom" ) !== "auto" ) {
6515 this.helper.height( this.helper.height() );
6516 this.helper.css( "bottom", "auto" );
6517 }
6518 },
6519
6520 // From now on bulk stuff - mainly helpers
6521
6522 _trigger: function( type, event, ui ) {
6523 ui = ui || this._uiHash();
6524 $.ui.plugin.call( this, type, [ event, ui, this ], true );
6525
6526 // Absolute position and offset (see #6884 ) have to be recalculated after plugins
6527 if ( /^(drag|start|stop)/.test( type ) ) {
6528 this.positionAbs = this._convertPositionTo( "absolute" );
6529 ui.offset = this.positionAbs;
6530 }
6531 return $.Widget.prototype._trigger.call( this, type, event, ui );
6532 },
6533
6534 plugins: {},
6535
6536 _uiHash: function() {
6537 return {
6538 helper: this.helper,
6539 position: this.position,
6540 originalPosition: this.originalPosition,
6541 offset: this.positionAbs
6542 };
6543 }
6544
6545 });
6546
6547 $.ui.plugin.add( "draggable", "connectToSortable", {
6548 start: function( event, ui, draggable ) {
6549 var uiSortable = $.extend( {}, ui, {
6550 item: draggable.element
6551 });
6552
6553 draggable.sortables = [];
6554 $( draggable.options.connectToSortable ).each(function() {
6555 var sortable = $( this ).sortable( "instance" );
6556
6557 if ( sortable && !sortable.options.disabled ) {
6558 draggable.sortables.push( sortable );
6559
6560 // refreshPositions is called at drag start to refresh the containerCache
6561 // which is used in drag. This ensures it's initialized and synchronized
6562 // with any changes that might have happened on the page since initialization.
6563 sortable.refreshPositions();
6564 sortable._trigger("activate", event, uiSortable);
6565 }
6566 });
6567 },
6568 stop: function( event, ui, draggable ) {
6569 var uiSortable = $.extend( {}, ui, {
6570 item: draggable.element
6571 });
6572
6573 draggable.cancelHelperRemoval = false;
6574
6575 $.each( draggable.sortables, function() {
6576 var sortable = this;
6577
6578 if ( sortable.isOver ) {
6579 sortable.isOver = 0;
6580
6581 // Allow this sortable to handle removing the helper
6582 draggable.cancelHelperRemoval = true;
6583 sortable.cancelHelperRemoval = false;
6584
6585 // Use _storedCSS To restore properties in the sortable,
6586 // as this also handles revert (#9675) since the draggable
6587 // may have modified them in unexpected ways (#8809)
6588 sortable._storedCSS = {
6589 position: sortable.placeholder.css( "position" ),
6590 top: sortable.placeholder.css( "top" ),
6591 left: sortable.placeholder.css( "left" )
6592 };
6593
6594 sortable._mouseStop(event);
6595
6596 // Once drag has ended, the sortable should return to using
6597 // its original helper, not the shared helper from draggable
6598 sortable.options.helper = sortable.options._helper;
6599 } else {
6600 // Prevent this Sortable from removing the helper.
6601 // However, don't set the draggable to remove the helper
6602 // either as another connected Sortable may yet handle the removal.
6603 sortable.cancelHelperRemoval = true;
6604
6605 sortable._trigger( "deactivate", event, uiSortable );
6606 }
6607 });
6608 },
6609 drag: function( event, ui, draggable ) {
6610 $.each( draggable.sortables, function() {
6611 var innermostIntersecting = false,
6612 sortable = this;
6613
6614 // Copy over variables that sortable's _intersectsWith uses
6615 sortable.positionAbs = draggable.positionAbs;
6616 sortable.helperProportions = draggable.helperProportions;
6617 sortable.offset.click = draggable.offset.click;
6618
6619 if ( sortable._intersectsWith( sortable.containerCache ) ) {
6620 innermostIntersecting = true;
6621
6622 $.each( draggable.sortables, function() {
6623 // Copy over variables that sortable's _intersectsWith uses
6624 this.positionAbs = draggable.positionAbs;
6625 this.helperProportions = draggable.helperProportions;
6626 this.offset.click = draggable.offset.click;
6627
6628 if ( this !== sortable &&
6629 this._intersectsWith( this.containerCache ) &&
6630 $.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) {
6631 innermostIntersecting = false;
6632 }
6633
6634 return innermostIntersecting;
6635 });
6636 }
6637
6638 if ( innermostIntersecting ) {
6639 // If it intersects, we use a little isOver variable and set it once,
6640 // so that the move-in stuff gets fired only once.
6641 if ( !sortable.isOver ) {
6642 sortable.isOver = 1;
6643
6644 // Store draggable's parent in case we need to reappend to it later.
6645 draggable._parent = ui.helper.parent();
6646
6647 sortable.currentItem = ui.helper
6648 .appendTo( sortable.element )
6649 .data( "ui-sortable-item", true );
6650
6651 // Store helper option to later restore it
6652 sortable.options._helper = sortable.options.helper;
6653
6654 sortable.options.helper = function() {
6655 return ui.helper[ 0 ];
6656 };
6657
6658 // Fire the start events of the sortable with our passed browser event,
6659 // and our own helper (so it doesn't create a new one)
6660 event.target = sortable.currentItem[ 0 ];
6661 sortable._mouseCapture( event, true );
6662 sortable._mouseStart( event, true, true );
6663
6664 // Because the browser event is way off the new appended portlet,
6665 // modify necessary variables to reflect the changes
6666 sortable.offset.click.top = draggable.offset.click.top;
6667 sortable.offset.click.left = draggable.offset.click.left;
6668 sortable.offset.parent.left -= draggable.offset.parent.left -
6669 sortable.offset.parent.left;
6670 sortable.offset.parent.top -= draggable.offset.parent.top -
6671 sortable.offset.parent.top;
6672
6673 draggable._trigger( "toSortable", event );
6674
6675 // Inform draggable that the helper is in a valid drop zone,
6676 // used solely in the revert option to handle "valid/invalid".
6677 draggable.dropped = sortable.element;
6678
6679 // Need to refreshPositions of all sortables in the case that
6680 // adding to one sortable changes the location of the other sortables (#9675)
6681 $.each( draggable.sortables, function() {
6682 this.refreshPositions();
6683 });
6684
6685 // hack so receive/update callbacks work (mostly)
6686 draggable.currentItem = draggable.element;
6687 sortable.fromOutside = draggable;
6688 }
6689
6690 if ( sortable.currentItem ) {
6691 sortable._mouseDrag( event );
6692 // Copy the sortable's position because the draggable's can potentially reflect
6693 // a relative position, while sortable is always absolute, which the dragged
6694 // element has now become. (#8809)
6695 ui.position = sortable.position;
6696 }
6697 } else {
6698 // If it doesn't intersect with the sortable, and it intersected before,
6699 // we fake the drag stop of the sortable, but make sure it doesn't remove
6700 // the helper by using cancelHelperRemoval.
6701 if ( sortable.isOver ) {
6702
6703 sortable.isOver = 0;
6704 sortable.cancelHelperRemoval = true;
6705
6706 // Calling sortable's mouseStop would trigger a revert,
6707 // so revert must be temporarily false until after mouseStop is called.
6708 sortable.options._revert = sortable.options.revert;
6709 sortable.options.revert = false;
6710
6711 sortable._trigger( "out", event, sortable._uiHash( sortable ) );
6712 sortable._mouseStop( event, true );
6713
6714 // restore sortable behaviors that were modfied
6715 // when the draggable entered the sortable area (#9481)
6716 sortable.options.revert = sortable.options._revert;
6717 sortable.options.helper = sortable.options._helper;
6718
6719 if ( sortable.placeholder ) {
6720 sortable.placeholder.remove();
6721 }
6722
6723 // Restore and recalculate the draggable's offset considering the sortable
6724 // may have modified them in unexpected ways. (#8809, #10669)
6725 ui.helper.appendTo( draggable._parent );
6726 draggable._refreshOffsets( event );
6727 ui.position = draggable._generatePosition( event, true );
6728
6729 draggable._trigger( "fromSortable", event );
6730
6731 // Inform draggable that the helper is no longer in a valid drop zone
6732 draggable.dropped = false;
6733
6734 // Need to refreshPositions of all sortables just in case removing
6735 // from one sortable changes the location of other sortables (#9675)
6736 $.each( draggable.sortables, function() {
6737 this.refreshPositions();
6738 });
6739 }
6740 }
6741 });
6742 }
6743 });
6744
6745 $.ui.plugin.add("draggable", "cursor", {
6746 start: function( event, ui, instance ) {
6747 var t = $( "body" ),
6748 o = instance.options;
6749
6750 if (t.css("cursor")) {
6751 o._cursor = t.css("cursor");
6752 }
6753 t.css("cursor", o.cursor);
6754 },
6755 stop: function( event, ui, instance ) {
6756 var o = instance.options;
6757 if (o._cursor) {
6758 $("body").css("cursor", o._cursor);
6759 }
6760 }
6761 });
6762
6763 $.ui.plugin.add("draggable", "opacity", {
6764 start: function( event, ui, instance ) {
6765 var t = $( ui.helper ),
6766 o = instance.options;
6767 if (t.css("opacity")) {
6768 o._opacity = t.css("opacity");
6769 }
6770 t.css("opacity", o.opacity);
6771 },
6772 stop: function( event, ui, instance ) {
6773 var o = instance.options;
6774 if (o._opacity) {
6775 $(ui.helper).css("opacity", o._opacity);
6776 }
6777 }
6778 });
6779
6780 $.ui.plugin.add("draggable", "scroll", {
6781 start: function( event, ui, i ) {
6782 if ( !i.scrollParentNotHidden ) {
6783 i.scrollParentNotHidden = i.helper.scrollParent( false );
6784 }
6785
6786 if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] && i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) {
6787 i.overflowOffset = i.scrollParentNotHidden.offset();
6788 }
6789 },
6790 drag: function( event, ui, i ) {
6791
6792 var o = i.options,
6793 scrolled = false,
6794 scrollParent = i.scrollParentNotHidden[ 0 ],
6795 document = i.document[ 0 ];
6796
6797 if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) {
6798 if ( !o.axis || o.axis !== "x" ) {
6799 if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY < o.scrollSensitivity ) {
6800 scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed;
6801 } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) {
6802 scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed;
6803 }
6804 }
6805
6806 if ( !o.axis || o.axis !== "y" ) {
6807 if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX < o.scrollSensitivity ) {
6808 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed;
6809 } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) {
6810 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed;
6811 }
6812 }
6813
6814 } else {
6815
6816 if (!o.axis || o.axis !== "x") {
6817 if (event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
6818 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
6819 } else if ($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
6820 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
6821 }
6822 }
6823
6824 if (!o.axis || o.axis !== "y") {
6825 if (event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
6826 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
6827 } else if ($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
6828 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
6829 }
6830 }
6831
6832 }
6833
6834 if (scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
6835 $.ui.ddmanager.prepareOffsets(i, event);
6836 }
6837
6838 }
6839 });
6840
6841 $.ui.plugin.add("draggable", "snap", {
6842 start: function( event, ui, i ) {
6843
6844 var o = i.options;
6845
6846 i.snapElements = [];
6847
6848 $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() {
6849 var $t = $(this),
6850 $o = $t.offset();
6851 if (this !== i.element[0]) {
6852 i.snapElements.push({
6853 item: this,
6854 width: $t.outerWidth(), height: $t.outerHeight(),
6855 top: $o.top, left: $o.left
6856 });
6857 }
6858 });
6859
6860 },
6861 drag: function( event, ui, inst ) {
6862
6863 var ts, bs, ls, rs, l, r, t, b, i, first,
6864 o = inst.options,
6865 d = o.snapTolerance,
6866 x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
6867 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
6868
6869 for (i = inst.snapElements.length - 1; i >= 0; i--){
6870
6871 l = inst.snapElements[i].left - inst.margins.left;
6872 r = l + inst.snapElements[i].width;
6873 t = inst.snapElements[i].top - inst.margins.top;
6874 b = t + inst.snapElements[i].height;
6875
6876 if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) {
6877 if (inst.snapElements[i].snapping) {
6878 (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
6879 }
6880 inst.snapElements[i].snapping = false;
6881 continue;
6882 }
6883
6884 if (o.snapMode !== "inner") {
6885 ts = Math.abs(t - y2) <= d;
6886 bs = Math.abs(b - y1) <= d;
6887 ls = Math.abs(l - x2) <= d;
6888 rs = Math.abs(r - x1) <= d;
6889 if (ts) {
6890 ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top;
6891 }
6892 if (bs) {
6893 ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top;
6894 }
6895 if (ls) {
6896 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left;
6897 }
6898 if (rs) {
6899 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left;
6900 }
6901 }
6902
6903 first = (ts || bs || ls || rs);
6904
6905 if (o.snapMode !== "outer") {
6906 ts = Math.abs(t - y1) <= d;
6907 bs = Math.abs(b - y2) <= d;
6908 ls = Math.abs(l - x1) <= d;
6909 rs = Math.abs(r - x2) <= d;
6910 if (ts) {
6911 ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top;
6912 }
6913 if (bs) {
6914 ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top;
6915 }
6916 if (ls) {
6917 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left;
6918 }
6919 if (rs) {
6920 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left;
6921 }
6922 }
6923
6924 if (!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) {
6925 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
6926 }
6927 inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
6928
6929 }
6930
6931 }
6932 });
6933
6934 $.ui.plugin.add("draggable", "stack", {
6935 start: function( event, ui, instance ) {
6936 var min,
6937 o = instance.options,
6938 group = $.makeArray($(o.stack)).sort(function(a, b) {
6939 return (parseInt($(a).css("zIndex"), 10) || 0) - (parseInt($(b).css("zIndex"), 10) || 0);
6940 });
6941
6942 if (!group.length) { return; }
6943
6944 min = parseInt($(group[0]).css("zIndex"), 10) || 0;
6945 $(group).each(function(i) {
6946 $(this).css("zIndex", min + i);
6947 });
6948 this.css("zIndex", (min + group.length));
6949 }
6950 });
6951
6952 $.ui.plugin.add("draggable", "zIndex", {
6953 start: function( event, ui, instance ) {
6954 var t = $( ui.helper ),
6955 o = instance.options;
6956
6957 if (t.css("zIndex")) {
6958 o._zIndex = t.css("zIndex");
6959 }
6960 t.css("zIndex", o.zIndex);
6961 },
6962 stop: function( event, ui, instance ) {
6963 var o = instance.options;
6964
6965 if (o._zIndex) {
6966 $(ui.helper).css("zIndex", o._zIndex);
6967 }
6968 }
6969 });
6970
6971 var draggable = $.ui.draggable;
6972
6973
6974 /*!
6975 * jQuery UI Resizable 1.11.4
6976 * http://jqueryui.com
6977 *
6978 * Copyright jQuery Foundation and other contributors
6979 * Released under the MIT license.
6980 * http://jquery.org/license
6981 *
6982 * http://api.jqueryui.com/resizable/
6983 */
6984
6985
6986 $.widget("ui.resizable", $.ui.mouse, {
6987 version: "1.11.4",
6988 widgetEventPrefix: "resize",
6989 options: {
6990 alsoResize: false,
6991 animate: false,
6992 animateDuration: "slow",
6993 animateEasing: "swing",
6994 aspectRatio: false,
6995 autoHide: false,
6996 containment: false,
6997 ghost: false,
6998 grid: false,
6999 handles: "e,s,se",
7000 helper: false,
7001 maxHeight: null,
7002 maxWidth: null,
7003 minHeight: 10,
7004 minWidth: 10,
7005 // See #7960
7006 zIndex: 90,
7007
7008 // callbacks
7009 resize: null,
7010 start: null,
7011 stop: null
7012 },
7013
7014 _num: function( value ) {
7015 return parseInt( value, 10 ) || 0;
7016 },
7017
7018 _isNumber: function( value ) {
7019 return !isNaN( parseInt( value, 10 ) );
7020 },
7021
7022 _hasScroll: function( el, a ) {
7023
7024 if ( $( el ).css( "overflow" ) === "hidden") {
7025 return false;
7026 }
7027
7028 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
7029 has = false;
7030
7031 if ( el[ scroll ] > 0 ) {
7032 return true;
7033 }
7034
7035 // TODO: determine which cases actually cause this to happen
7036 // if the element doesn't have the scroll set, see if it's possible to
7037 // set the scroll
7038 el[ scroll ] = 1;
7039 has = ( el[ scroll ] > 0 );
7040 el[ scroll ] = 0;
7041 return has;
7042 },
7043
7044 _create: function() {
7045
7046 var n, i, handle, axis, hname,
7047 that = this,
7048 o = this.options;
7049 this.element.addClass("ui-resizable");
7050
7051 $.extend(this, {
7052 _aspectRatio: !!(o.aspectRatio),
7053 aspectRatio: o.aspectRatio,
7054 originalElement: this.element,
7055 _proportionallyResizeElements: [],
7056 _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
7057 });
7058
7059 // Wrap the element if it cannot hold child nodes
7060 if (this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)) {
7061
7062 this.element.wrap(
7063 $("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({
7064 position: this.element.css("position"),
7065 width: this.element.outerWidth(),
7066 height: this.element.outerHeight(),
7067 top: this.element.css("top"),
7068 left: this.element.css("left")
7069 })
7070 );
7071
7072 this.element = this.element.parent().data(
7073 "ui-resizable", this.element.resizable( "instance" )
7074 );
7075
7076 this.elementIsWrapper = true;
7077
7078 this.element.css({
7079 marginLeft: this.originalElement.css("marginLeft"),
7080 marginTop: this.originalElement.css("marginTop"),
7081 marginRight: this.originalElement.css("marginRight"),
7082 marginBottom: this.originalElement.css("marginBottom")
7083 });
7084 this.originalElement.css({
7085 marginLeft: 0,
7086 marginTop: 0,
7087 marginRight: 0,
7088 marginBottom: 0
7089 });
7090 // support: Safari
7091 // Prevent Safari textarea resize
7092 this.originalResizeStyle = this.originalElement.css("resize");
7093 this.originalElement.css("resize", "none");
7094
7095 this._proportionallyResizeElements.push( this.originalElement.css({
7096 position: "static",
7097 zoom: 1,
7098 display: "block"
7099 }) );
7100
7101 // support: IE9
7102 // avoid IE jump (hard set the margin)
7103 this.originalElement.css({ margin: this.originalElement.css("margin") });
7104
7105 this._proportionallyResize();
7106 }
7107
7108 this.handles = o.handles ||
7109 ( !$(".ui-resizable-handle", this.element).length ?
7110 "e,s,se" : {
7111 n: ".ui-resizable-n",
7112 e: ".ui-resizable-e",
7113 s: ".ui-resizable-s",
7114 w: ".ui-resizable-w",
7115 se: ".ui-resizable-se",
7116 sw: ".ui-resizable-sw",
7117 ne: ".ui-resizable-ne",
7118 nw: ".ui-resizable-nw"
7119 } );
7120
7121 this._handles = $();
7122 if ( this.handles.constructor === String ) {
7123
7124 if ( this.handles === "all") {
7125 this.handles = "n,e,s,w,se,sw,ne,nw";
7126 }
7127
7128 n = this.handles.split(",");
7129 this.handles = {};
7130
7131 for (i = 0; i < n.length; i++) {
7132
7133 handle = $.trim(n[i]);
7134 hname = "ui-resizable-" + handle;
7135 axis = $("<div class='ui-resizable-handle " + hname + "'></div>");
7136
7137 axis.css({ zIndex: o.zIndex });
7138
7139 // TODO : What's going on here?
7140 if ("se" === handle) {
7141 axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se");
7142 }
7143
7144 this.handles[handle] = ".ui-resizable-" + handle;
7145 this.element.append(axis);
7146 }
7147
7148 }
7149
7150 this._renderAxis = function(target) {
7151
7152 var i, axis, padPos, padWrapper;
7153
7154 target = target || this.element;
7155
7156 for (i in this.handles) {
7157
7158 if (this.handles[i].constructor === String) {
7159 this.handles[i] = this.element.children( this.handles[ i ] ).first().show();
7160 } else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) {
7161 this.handles[ i ] = $( this.handles[ i ] );
7162 this._on( this.handles[ i ], { "mousedown": that._mouseDown });
7163 }
7164
7165 if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)) {
7166
7167 axis = $(this.handles[i], this.element);
7168
7169 padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
7170
7171 padPos = [ "padding",
7172 /ne|nw|n/.test(i) ? "Top" :
7173 /se|sw|s/.test(i) ? "Bottom" :
7174 /^e$/.test(i) ? "Right" : "Left" ].join("");
7175
7176 target.css(padPos, padWrapper);
7177
7178 this._proportionallyResize();
7179 }
7180
7181 this._handles = this._handles.add( this.handles[ i ] );
7182 }
7183 };
7184
7185 // TODO: make renderAxis a prototype function
7186 this._renderAxis(this.element);
7187
7188 this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) );
7189 this._handles.disableSelection();
7190
7191 this._handles.mouseover(function() {
7192 if (!that.resizing) {
7193 if (this.className) {
7194 axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
7195 }
7196 that.axis = axis && axis[1] ? axis[1] : "se";
7197 }
7198 });
7199
7200 if (o.autoHide) {
7201 this._handles.hide();
7202 $(this.element)
7203 .addClass("ui-resizable-autohide")
7204 .mouseenter(function() {
7205 if (o.disabled) {
7206 return;
7207 }
7208 $(this).removeClass("ui-resizable-autohide");
7209 that._handles.show();
7210 })
7211 .mouseleave(function() {
7212 if (o.disabled) {
7213 return;
7214 }
7215 if (!that.resizing) {
7216 $(this).addClass("ui-resizable-autohide");
7217 that._handles.hide();
7218 }
7219 });
7220 }
7221
7222 this._mouseInit();
7223 },
7224
7225 _destroy: function() {
7226
7227 this._mouseDestroy();
7228
7229 var wrapper,
7230 _destroy = function(exp) {
7231 $(exp)
7232 .removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
7233 .removeData("resizable")
7234 .removeData("ui-resizable")
7235 .unbind(".resizable")
7236 .find(".ui-resizable-handle")
7237 .remove();
7238 };
7239
7240 // TODO: Unwrap at same DOM position
7241 if (this.elementIsWrapper) {
7242 _destroy(this.element);
7243 wrapper = this.element;
7244 this.originalElement.css({
7245 position: wrapper.css("position"),
7246 width: wrapper.outerWidth(),
7247 height: wrapper.outerHeight(),
7248 top: wrapper.css("top"),
7249 left: wrapper.css("left")
7250 }).insertAfter( wrapper );
7251 wrapper.remove();
7252 }
7253
7254 this.originalElement.css("resize", this.originalResizeStyle);
7255 _destroy(this.originalElement);
7256
7257 return this;
7258 },
7259
7260 _mouseCapture: function(event) {
7261 var i, handle,
7262 capture = false;
7263
7264 for (i in this.handles) {
7265 handle = $(this.handles[i])[0];
7266 if (handle === event.target || $.contains(handle, event.target)) {
7267 capture = true;
7268 }
7269 }
7270
7271 return !this.options.disabled && capture;
7272 },
7273
7274 _mouseStart: function(event) {
7275
7276 var curleft, curtop, cursor,
7277 o = this.options,
7278 el = this.element;
7279
7280 this.resizing = true;
7281
7282 this._renderProxy();
7283
7284 curleft = this._num(this.helper.css("left"));
7285 curtop = this._num(this.helper.css("top"));
7286
7287 if (o.containment) {
7288 curleft += $(o.containment).scrollLeft() || 0;
7289 curtop += $(o.containment).scrollTop() || 0;
7290 }
7291
7292 this.offset = this.helper.offset();
7293 this.position = { left: curleft, top: curtop };
7294
7295 this.size = this._helper ? {
7296 width: this.helper.width(),
7297 height: this.helper.height()
7298 } : {
7299 width: el.width(),
7300 height: el.height()
7301 };
7302
7303 this.originalSize = this._helper ? {
7304 width: el.outerWidth(),
7305 height: el.outerHeight()
7306 } : {
7307 width: el.width(),
7308 height: el.height()
7309 };
7310
7311 this.sizeDiff = {
7312 width: el.outerWidth() - el.width(),
7313 height: el.outerHeight() - el.height()
7314 };
7315
7316 this.originalPosition = { left: curleft, top: curtop };
7317 this.originalMousePosition = { left: event.pageX, top: event.pageY };
7318
7319 this.aspectRatio = (typeof o.aspectRatio === "number") ?
7320 o.aspectRatio :
7321 ((this.originalSize.width / this.originalSize.height) || 1);
7322
7323 cursor = $(".ui-resizable-" + this.axis).css("cursor");
7324 $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor);
7325
7326 el.addClass("ui-resizable-resizing");
7327 this._propagate("start", event);
7328 return true;
7329 },
7330
7331 _mouseDrag: function(event) {
7332
7333 var data, props,
7334 smp = this.originalMousePosition,
7335 a = this.axis,
7336 dx = (event.pageX - smp.left) || 0,
7337 dy = (event.pageY - smp.top) || 0,
7338 trigger = this._change[a];
7339
7340 this._updatePrevProperties();
7341
7342 if (!trigger) {
7343 return false;
7344 }
7345
7346 data = trigger.apply(this, [ event, dx, dy ]);
7347
7348 this._updateVirtualBoundaries(event.shiftKey);
7349 if (this._aspectRatio || event.shiftKey) {
7350 data = this._updateRatio(data, event);
7351 }
7352
7353 data = this._respectSize(data, event);
7354
7355 this._updateCache(data);
7356
7357 this._propagate("resize", event);
7358
7359 props = this._applyChanges();
7360
7361 if ( !this._helper && this._proportionallyResizeElements.length ) {
7362 this._proportionallyResize();
7363 }
7364
7365 if ( !$.isEmptyObject( props ) ) {
7366 this._updatePrevProperties();
7367 this._trigger( "resize", event, this.ui() );
7368 this._applyChanges();
7369 }
7370
7371 return false;
7372 },
7373
7374 _mouseStop: function(event) {
7375
7376 this.resizing = false;
7377 var pr, ista, soffseth, soffsetw, s, left, top,
7378 o = this.options, that = this;
7379
7380 if (this._helper) {
7381
7382 pr = this._proportionallyResizeElements;
7383 ista = pr.length && (/textarea/i).test(pr[0].nodeName);
7384 soffseth = ista && this._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height;
7385 soffsetw = ista ? 0 : that.sizeDiff.width;
7386
7387 s = {
7388 width: (that.helper.width() - soffsetw),
7389 height: (that.helper.height() - soffseth)
7390 };
7391 left = (parseInt(that.element.css("left"), 10) +
7392 (that.position.left - that.originalPosition.left)) || null;
7393 top = (parseInt(that.element.css("top"), 10) +
7394 (that.position.top - that.originalPosition.top)) || null;
7395
7396 if (!o.animate) {
7397 this.element.css($.extend(s, { top: top, left: left }));
7398 }
7399
7400 that.helper.height(that.size.height);
7401 that.helper.width(that.size.width);
7402
7403 if (this._helper && !o.animate) {
7404 this._proportionallyResize();
7405 }
7406 }
7407
7408 $("body").css("cursor", "auto");
7409
7410 this.element.removeClass("ui-resizable-resizing");
7411
7412 this._propagate("stop", event);
7413
7414 if (this._helper) {
7415 this.helper.remove();
7416 }
7417
7418 return false;
7419
7420 },
7421
7422 _updatePrevProperties: function() {
7423 this.prevPosition = {
7424 top: this.position.top,
7425 left: this.position.left
7426 };
7427 this.prevSize = {
7428 width: this.size.width,
7429 height: this.size.height
7430 };
7431 },
7432
7433 _applyChanges: function() {
7434 var props = {};
7435
7436 if ( this.position.top !== this.prevPosition.top ) {
7437 props.top = this.position.top + "px";
7438 }
7439 if ( this.position.left !== this.prevPosition.left ) {
7440 props.left = this.position.left + "px";
7441 }
7442 if ( this.size.width !== this.prevSize.width ) {
7443 props.width = this.size.width + "px";
7444 }
7445 if ( this.size.height !== this.prevSize.height ) {
7446 props.height = this.size.height + "px";
7447 }
7448
7449 this.helper.css( props );
7450
7451 return props;
7452 },
7453
7454 _updateVirtualBoundaries: function(forceAspectRatio) {
7455 var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
7456 o = this.options;
7457
7458 b = {
7459 minWidth: this._isNumber(o.minWidth) ? o.minWidth : 0,
7460 maxWidth: this._isNumber(o.maxWidth) ? o.maxWidth : Infinity,
7461 minHeight: this._isNumber(o.minHeight) ? o.minHeight : 0,
7462 maxHeight: this._isNumber(o.maxHeight) ? o.maxHeight : Infinity
7463 };
7464
7465 if (this._aspectRatio || forceAspectRatio) {
7466 pMinWidth = b.minHeight * this.aspectRatio;
7467 pMinHeight = b.minWidth / this.aspectRatio;
7468 pMaxWidth = b.maxHeight * this.aspectRatio;
7469 pMaxHeight = b.maxWidth / this.aspectRatio;
7470
7471 if (pMinWidth > b.minWidth) {
7472 b.minWidth = pMinWidth;
7473 }
7474 if (pMinHeight > b.minHeight) {
7475 b.minHeight = pMinHeight;
7476 }
7477 if (pMaxWidth < b.maxWidth) {
7478 b.maxWidth = pMaxWidth;
7479 }
7480 if (pMaxHeight < b.maxHeight) {
7481 b.maxHeight = pMaxHeight;
7482 }
7483 }
7484 this._vBoundaries = b;
7485 },
7486
7487 _updateCache: function(data) {
7488 this.offset = this.helper.offset();
7489 if (this._isNumber(data.left)) {
7490 this.position.left = data.left;
7491 }
7492 if (this._isNumber(data.top)) {
7493 this.position.top = data.top;
7494 }
7495 if (this._isNumber(data.height)) {
7496 this.size.height = data.height;
7497 }
7498 if (this._isNumber(data.width)) {
7499 this.size.width = data.width;
7500 }
7501 },
7502
7503 _updateRatio: function( data ) {
7504
7505 var cpos = this.position,
7506 csize = this.size,
7507 a = this.axis;
7508
7509 if (this._isNumber(data.height)) {
7510 data.width = (data.height * this.aspectRatio);
7511 } else if (this._isNumber(data.width)) {
7512 data.height = (data.width / this.aspectRatio);
7513 }
7514
7515 if (a === "sw") {
7516 data.left = cpos.left + (csize.width - data.width);
7517 data.top = null;
7518 }
7519 if (a === "nw") {
7520 data.top = cpos.top + (csize.height - data.height);
7521 data.left = cpos.left + (csize.width - data.width);
7522 }
7523
7524 return data;
7525 },
7526
7527 _respectSize: function( data ) {
7528
7529 var o = this._vBoundaries,
7530 a = this.axis,
7531 ismaxw = this._isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width),
7532 ismaxh = this._isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
7533 isminw = this._isNumber(data.width) && o.minWidth && (o.minWidth > data.width),
7534 isminh = this._isNumber(data.height) && o.minHeight && (o.minHeight > data.height),
7535 dw = this.originalPosition.left + this.originalSize.width,
7536 dh = this.position.top + this.size.height,
7537 cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
7538 if (isminw) {
7539 data.width = o.minWidth;
7540 }
7541 if (isminh) {
7542 data.height = o.minHeight;
7543 }
7544 if (ismaxw) {
7545 data.width = o.maxWidth;
7546 }
7547 if (ismaxh) {
7548 data.height = o.maxHeight;
7549 }
7550
7551 if (isminw && cw) {
7552 data.left = dw - o.minWidth;
7553 }
7554 if (ismaxw && cw) {
7555 data.left = dw - o.maxWidth;
7556 }
7557 if (isminh && ch) {
7558 data.top = dh - o.minHeight;
7559 }
7560 if (ismaxh && ch) {
7561 data.top = dh - o.maxHeight;
7562 }
7563
7564 // Fixing jump error on top/left - bug #2330
7565 if (!data.width && !data.height && !data.left && data.top) {
7566 data.top = null;
7567 } else if (!data.width && !data.height && !data.top && data.left) {
7568 data.left = null;
7569 }
7570
7571 return data;
7572 },
7573
7574 _getPaddingPlusBorderDimensions: function( element ) {
7575 var i = 0,
7576 widths = [],
7577 borders = [
7578 element.css( "borderTopWidth" ),
7579 element.css( "borderRightWidth" ),
7580 element.css( "borderBottomWidth" ),
7581 element.css( "borderLeftWidth" )
7582 ],
7583 paddings = [
7584 element.css( "paddingTop" ),
7585 element.css( "paddingRight" ),
7586 element.css( "paddingBottom" ),
7587 element.css( "paddingLeft" )
7588 ];
7589
7590 for ( ; i < 4; i++ ) {
7591 widths[ i ] = ( parseInt( borders[ i ], 10 ) || 0 );
7592 widths[ i ] += ( parseInt( paddings[ i ], 10 ) || 0 );
7593 }
7594
7595 return {
7596 height: widths[ 0 ] + widths[ 2 ],
7597 width: widths[ 1 ] + widths[ 3 ]
7598 };
7599 },
7600
7601 _proportionallyResize: function() {
7602
7603 if (!this._proportionallyResizeElements.length) {
7604 return;
7605 }
7606
7607 var prel,
7608 i = 0,
7609 element = this.helper || this.element;
7610
7611 for ( ; i < this._proportionallyResizeElements.length; i++) {
7612
7613 prel = this._proportionallyResizeElements[i];
7614
7615 // TODO: Seems like a bug to cache this.outerDimensions
7616 // considering that we are in a loop.
7617 if (!this.outerDimensions) {
7618 this.outerDimensions = this._getPaddingPlusBorderDimensions( prel );
7619 }
7620
7621 prel.css({
7622 height: (element.height() - this.outerDimensions.height) || 0,
7623 width: (element.width() - this.outerDimensions.width) || 0
7624 });
7625
7626 }
7627
7628 },
7629
7630 _renderProxy: function() {
7631
7632 var el = this.element, o = this.options;
7633 this.elementOffset = el.offset();
7634
7635 if (this._helper) {
7636
7637 this.helper = this.helper || $("<div style='overflow:hidden;'></div>");
7638
7639 this.helper.addClass(this._helper).css({
7640 width: this.element.outerWidth() - 1,
7641 height: this.element.outerHeight() - 1,
7642 position: "absolute",
7643 left: this.elementOffset.left + "px",
7644 top: this.elementOffset.top + "px",
7645 zIndex: ++o.zIndex //TODO: Don't modify option
7646 });
7647
7648 this.helper
7649 .appendTo("body")
7650 .disableSelection();
7651
7652 } else {
7653 this.helper = this.element;
7654 }
7655
7656 },
7657
7658 _change: {
7659 e: function(event, dx) {
7660 return { width: this.originalSize.width + dx };
7661 },
7662 w: function(event, dx) {
7663 var cs = this.originalSize, sp = this.originalPosition;
7664 return { left: sp.left + dx, width: cs.width - dx };
7665 },
7666 n: function(event, dx, dy) {
7667 var cs = this.originalSize, sp = this.originalPosition;
7668 return { top: sp.top + dy, height: cs.height - dy };
7669 },
7670 s: function(event, dx, dy) {
7671 return { height: this.originalSize.height + dy };
7672 },
7673 se: function(event, dx, dy) {
7674 return $.extend(this._change.s.apply(this, arguments),
7675 this._change.e.apply(this, [ event, dx, dy ]));
7676 },
7677 sw: function(event, dx, dy) {
7678 return $.extend(this._change.s.apply(this, arguments),
7679 this._change.w.apply(this, [ event, dx, dy ]));
7680 },
7681 ne: function(event, dx, dy) {
7682 return $.extend(this._change.n.apply(this, arguments),
7683 this._change.e.apply(this, [ event, dx, dy ]));
7684 },
7685 nw: function(event, dx, dy) {
7686 return $.extend(this._change.n.apply(this, arguments),
7687 this._change.w.apply(this, [ event, dx, dy ]));
7688 }
7689 },
7690
7691 _propagate: function(n, event) {
7692 $.ui.plugin.call(this, n, [ event, this.ui() ]);
7693 (n !== "resize" && this._trigger(n, event, this.ui()));
7694 },
7695
7696 plugins: {},
7697
7698 ui: function() {
7699 return {
7700 originalElement: this.originalElement,
7701 element: this.element,
7702 helper: this.helper,
7703 position: this.position,
7704 size: this.size,
7705 originalSize: this.originalSize,
7706 originalPosition: this.originalPosition
7707 };
7708 }
7709
7710 });
7711
7712 /*
7713 * Resizable Extensions
7714 */
7715
7716 $.ui.plugin.add("resizable", "animate", {
7717
7718 stop: function( event ) {
7719 var that = $(this).resizable( "instance" ),
7720 o = that.options,
7721 pr = that._proportionallyResizeElements,
7722 ista = pr.length && (/textarea/i).test(pr[0].nodeName),
7723 soffseth = ista && that._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height,
7724 soffsetw = ista ? 0 : that.sizeDiff.width,
7725 style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) },
7726 left = (parseInt(that.element.css("left"), 10) +
7727 (that.position.left - that.originalPosition.left)) || null,
7728 top = (parseInt(that.element.css("top"), 10) +
7729 (that.position.top - that.originalPosition.top)) || null;
7730
7731 that.element.animate(
7732 $.extend(style, top && left ? { top: top, left: left } : {}), {
7733 duration: o.animateDuration,
7734 easing: o.animateEasing,
7735 step: function() {
7736
7737 var data = {
7738 width: parseInt(that.element.css("width"), 10),
7739 height: parseInt(that.element.css("height"), 10),
7740 top: parseInt(that.element.css("top"), 10),
7741 left: parseInt(that.element.css("left"), 10)
7742 };
7743
7744 if (pr && pr.length) {
7745 $(pr[0]).css({ width: data.width, height: data.height });
7746 }
7747
7748 // propagating resize, and updating values for each animation step
7749 that._updateCache(data);
7750 that._propagate("resize", event);
7751
7752 }
7753 }
7754 );
7755 }
7756
7757 });
7758
7759 $.ui.plugin.add( "resizable", "containment", {
7760
7761 start: function() {
7762 var element, p, co, ch, cw, width, height,
7763 that = $( this ).resizable( "instance" ),
7764 o = that.options,
7765 el = that.element,
7766 oc = o.containment,
7767 ce = ( oc instanceof $ ) ? oc.get( 0 ) : ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc;
7768
7769 if ( !ce ) {
7770 return;
7771 }
7772
7773 that.containerElement = $( ce );
7774
7775 if ( /document/.test( oc ) || oc === document ) {
7776 that.containerOffset = {
7777 left: 0,
7778 top: 0
7779 };
7780 that.containerPosition = {
7781 left: 0,
7782 top: 0
7783 };
7784
7785 that.parentData = {
7786 element: $( document ),
7787 left: 0,
7788 top: 0,
7789 width: $( document ).width(),
7790 height: $( document ).height() || document.body.parentNode.scrollHeight
7791 };
7792 } else {
7793 element = $( ce );
7794 p = [];
7795 $([ "Top", "Right", "Left", "Bottom" ]).each(function( i, name ) {
7796 p[ i ] = that._num( element.css( "padding" + name ) );
7797 });
7798
7799 that.containerOffset = element.offset();
7800 that.containerPosition = element.position();
7801 that.containerSize = {
7802 height: ( element.innerHeight() - p[ 3 ] ),
7803 width: ( element.innerWidth() - p[ 1 ] )
7804 };
7805
7806 co = that.containerOffset;
7807 ch = that.containerSize.height;
7808 cw = that.containerSize.width;
7809 width = ( that._hasScroll ( ce, "left" ) ? ce.scrollWidth : cw );
7810 height = ( that._hasScroll ( ce ) ? ce.scrollHeight : ch ) ;
7811
7812 that.parentData = {
7813 element: ce,
7814 left: co.left,
7815 top: co.top,
7816 width: width,
7817 height: height
7818 };
7819 }
7820 },
7821
7822 resize: function( event ) {
7823 var woset, hoset, isParent, isOffsetRelative,
7824 that = $( this ).resizable( "instance" ),
7825 o = that.options,
7826 co = that.containerOffset,
7827 cp = that.position,
7828 pRatio = that._aspectRatio || event.shiftKey,
7829 cop = {
7830 top: 0,
7831 left: 0
7832 },
7833 ce = that.containerElement,
7834 continueResize = true;
7835
7836 if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) {
7837 cop = co;
7838 }
7839
7840 if ( cp.left < ( that._helper ? co.left : 0 ) ) {
7841 that.size.width = that.size.width +
7842 ( that._helper ?
7843 ( that.position.left - co.left ) :
7844 ( that.position.left - cop.left ) );
7845
7846 if ( pRatio ) {
7847 that.size.height = that.size.width / that.aspectRatio;
7848 continueResize = false;
7849 }
7850 that.position.left = o.helper ? co.left : 0;
7851 }
7852
7853 if ( cp.top < ( that._helper ? co.top : 0 ) ) {
7854 that.size.height = that.size.height +
7855 ( that._helper ?
7856 ( that.position.top - co.top ) :
7857 that.position.top );
7858
7859 if ( pRatio ) {
7860 that.size.width = that.size.height * that.aspectRatio;
7861 continueResize = false;
7862 }
7863 that.position.top = that._helper ? co.top : 0;
7864 }
7865
7866 isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 );
7867 isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) );
7868
7869 if ( isParent && isOffsetRelative ) {
7870 that.offset.left = that.parentData.left + that.position.left;
7871 that.offset.top = that.parentData.top + that.position.top;
7872 } else {
7873 that.offset.left = that.element.offset().left;
7874 that.offset.top = that.element.offset().top;
7875 }
7876
7877 woset = Math.abs( that.sizeDiff.width +
7878 (that._helper ?
7879 that.offset.left - cop.left :
7880 (that.offset.left - co.left)) );
7881
7882 hoset = Math.abs( that.sizeDiff.height +
7883 (that._helper ?
7884 that.offset.top - cop.top :
7885 (that.offset.top - co.top)) );
7886
7887 if ( woset + that.size.width >= that.parentData.width ) {
7888 that.size.width = that.parentData.width - woset;
7889 if ( pRatio ) {
7890 that.size.height = that.size.width / that.aspectRatio;
7891 continueResize = false;
7892 }
7893 }
7894
7895 if ( hoset + that.size.height >= that.parentData.height ) {
7896 that.size.height = that.parentData.height - hoset;
7897 if ( pRatio ) {
7898 that.size.width = that.size.height * that.aspectRatio;
7899 continueResize = false;
7900 }
7901 }
7902
7903 if ( !continueResize ) {
7904 that.position.left = that.prevPosition.left;
7905 that.position.top = that.prevPosition.top;
7906 that.size.width = that.prevSize.width;
7907 that.size.height = that.prevSize.height;
7908 }
7909 },
7910
7911 stop: function() {
7912 var that = $( this ).resizable( "instance" ),
7913 o = that.options,
7914 co = that.containerOffset,
7915 cop = that.containerPosition,
7916 ce = that.containerElement,
7917 helper = $( that.helper ),
7918 ho = helper.offset(),
7919 w = helper.outerWidth() - that.sizeDiff.width,
7920 h = helper.outerHeight() - that.sizeDiff.height;
7921
7922 if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) {
7923 $( this ).css({
7924 left: ho.left - cop.left - co.left,
7925 width: w,
7926 height: h
7927 });
7928 }
7929
7930 if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) {
7931 $( this ).css({
7932 left: ho.left - cop.left - co.left,
7933 width: w,
7934 height: h
7935 });
7936 }
7937 }
7938 });
7939
7940 $.ui.plugin.add("resizable", "alsoResize", {
7941
7942 start: function() {
7943 var that = $(this).resizable( "instance" ),
7944 o = that.options;
7945
7946 $(o.alsoResize).each(function() {
7947 var el = $(this);
7948 el.data("ui-resizable-alsoresize", {
7949 width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
7950 left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10)
7951 });
7952 });
7953 },
7954
7955 resize: function(event, ui) {
7956 var that = $(this).resizable( "instance" ),
7957 o = that.options,
7958 os = that.originalSize,
7959 op = that.originalPosition,
7960 delta = {
7961 height: (that.size.height - os.height) || 0,
7962 width: (that.size.width - os.width) || 0,
7963 top: (that.position.top - op.top) || 0,
7964 left: (that.position.left - op.left) || 0
7965 };
7966
7967 $(o.alsoResize).each(function() {
7968 var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {},
7969 css = el.parents(ui.originalElement[0]).length ?
7970 [ "width", "height" ] :
7971 [ "width", "height", "top", "left" ];
7972
7973 $.each(css, function(i, prop) {
7974 var sum = (start[prop] || 0) + (delta[prop] || 0);
7975 if (sum && sum >= 0) {
7976 style[prop] = sum || null;
7977 }
7978 });
7979
7980 el.css(style);
7981 });
7982 },
7983
7984 stop: function() {
7985 $(this).removeData("resizable-alsoresize");
7986 }
7987 });
7988
7989 $.ui.plugin.add("resizable", "ghost", {
7990
7991 start: function() {
7992
7993 var that = $(this).resizable( "instance" ), o = that.options, cs = that.size;
7994
7995 that.ghost = that.originalElement.clone();
7996 that.ghost
7997 .css({
7998 opacity: 0.25,
7999 display: "block",
8000 position: "relative",
8001 height: cs.height,
8002 width: cs.width,
8003 margin: 0,
8004 left: 0,
8005 top: 0
8006 })
8007 .addClass("ui-resizable-ghost")
8008 .addClass(typeof o.ghost === "string" ? o.ghost : "");
8009
8010 that.ghost.appendTo(that.helper);
8011
8012 },
8013
8014 resize: function() {
8015 var that = $(this).resizable( "instance" );
8016 if (that.ghost) {
8017 that.ghost.css({
8018 position: "relative",
8019 height: that.size.height,
8020 width: that.size.width
8021 });
8022 }
8023 },
8024
8025 stop: function() {
8026 var that = $(this).resizable( "instance" );
8027 if (that.ghost && that.helper) {
8028 that.helper.get(0).removeChild(that.ghost.get(0));
8029 }
8030 }
8031
8032 });
8033
8034 $.ui.plugin.add("resizable", "grid", {
8035
8036 resize: function() {
8037 var outerDimensions,
8038 that = $(this).resizable( "instance" ),
8039 o = that.options,
8040 cs = that.size,
8041 os = that.originalSize,
8042 op = that.originalPosition,
8043 a = that.axis,
8044 grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid,
8045 gridX = (grid[0] || 1),
8046 gridY = (grid[1] || 1),
8047 ox = Math.round((cs.width - os.width) / gridX) * gridX,
8048 oy = Math.round((cs.height - os.height) / gridY) * gridY,
8049 newWidth = os.width + ox,
8050 newHeight = os.height + oy,
8051 isMaxWidth = o.maxWidth && (o.maxWidth < newWidth),
8052 isMaxHeight = o.maxHeight && (o.maxHeight < newHeight),
8053 isMinWidth = o.minWidth && (o.minWidth > newWidth),
8054 isMinHeight = o.minHeight && (o.minHeight > newHeight);
8055
8056 o.grid = grid;
8057
8058 if (isMinWidth) {
8059 newWidth += gridX;
8060 }
8061 if (isMinHeight) {
8062 newHeight += gridY;
8063 }
8064 if (isMaxWidth) {
8065 newWidth -= gridX;
8066 }
8067 if (isMaxHeight) {
8068 newHeight -= gridY;
8069 }
8070
8071 if (/^(se|s|e)$/.test(a)) {
8072 that.size.width = newWidth;
8073 that.size.height = newHeight;
8074 } else if (/^(ne)$/.test(a)) {
8075 that.size.width = newWidth;
8076 that.size.height = newHeight;
8077 that.position.top = op.top - oy;
8078 } else if (/^(sw)$/.test(a)) {
8079 that.size.width = newWidth;
8080 that.size.height = newHeight;
8081 that.position.left = op.left - ox;
8082 } else {
8083 if ( newHeight - gridY <= 0 || newWidth - gridX <= 0) {
8084 outerDimensions = that._getPaddingPlusBorderDimensions( this );
8085 }
8086
8087 if ( newHeight - gridY > 0 ) {
8088 that.size.height = newHeight;
8089 that.position.top = op.top - oy;
8090 } else {
8091 newHeight = gridY - outerDimensions.height;
8092 that.size.height = newHeight;
8093 that.position.top = op.top + os.height - newHeight;
8094 }
8095 if ( newWidth - gridX > 0 ) {
8096 that.size.width = newWidth;
8097 that.position.left = op.left - ox;
8098 } else {
8099 newWidth = gridX - outerDimensions.width;
8100 that.size.width = newWidth;
8101 that.position.left = op.left + os.width - newWidth;
8102 }
8103 }
8104 }
8105
8106 });
8107
8108 var resizable = $.ui.resizable;
8109
8110
8111 /*!
8112 * jQuery UI Dialog 1.11.4
8113 * http://jqueryui.com
8114 *
8115 * Copyright jQuery Foundation and other contributors
8116 * Released under the MIT license.
8117 * http://jquery.org/license
8118 *
8119 * http://api.jqueryui.com/dialog/
8120 */
8121
8122
8123 var dialog = $.widget( "ui.dialog", {
8124 version: "1.11.4",
8125 options: {
8126 appendTo: "body",
8127 autoOpen: true,
8128 buttons: [],
8129 closeOnEscape: true,
8130 closeText: "Close",
8131 dialogClass: "",
8132 draggable: true,
8133 hide: null,
8134 height: "auto",
8135 maxHeight: null,
8136 maxWidth: null,
8137 minHeight: 150,
8138 minWidth: 150,
8139 modal: false,
8140 position: {
8141 my: "center",
8142 at: "center",
8143 of: window,
8144 collision: "fit",
8145 // Ensure the titlebar is always visible
8146 using: function( pos ) {
8147 var topOffset = $( this ).css( pos ).offset().top;
8148 if ( topOffset < 0 ) {
8149 $( this ).css( "top", pos.top - topOffset );
8150 }
8151 }
8152 },
8153 resizable: true,
8154 show: null,
8155 title: null,
8156 width: 300,
8157
8158 // callbacks
8159 beforeClose: null,
8160 close: null,
8161 drag: null,
8162 dragStart: null,
8163 dragStop: null,
8164 focus: null,
8165 open: null,
8166 resize: null,
8167 resizeStart: null,
8168 resizeStop: null
8169 },
8170
8171 sizeRelatedOptions: {
8172 buttons: true,
8173 height: true,
8174 maxHeight: true,
8175 maxWidth: true,
8176 minHeight: true,
8177 minWidth: true,
8178 width: true
8179 },
8180
8181 resizableRelatedOptions: {
8182 maxHeight: true,
8183 maxWidth: true,
8184 minHeight: true,
8185 minWidth: true
8186 },
8187
8188 _create: function() {
8189 this.originalCss = {
8190 display: this.element[ 0 ].style.display,
8191 width: this.element[ 0 ].style.width,
8192 minHeight: this.element[ 0 ].style.minHeight,
8193 maxHeight: this.element[ 0 ].style.maxHeight,
8194 height: this.element[ 0 ].style.height
8195 };
8196 this.originalPosition = {
8197 parent: this.element.parent(),
8198 index: this.element.parent().children().index( this.element )
8199 };
8200 this.originalTitle = this.element.attr( "title" );
8201 this.options.title = this.options.title || this.originalTitle;
8202
8203 this._createWrapper();
8204
8205 this.element
8206 .show()
8207 .removeAttr( "title" )
8208 .addClass( "ui-dialog-content ui-widget-content" )
8209 .appendTo( this.uiDialog );
8210
8211 this._createTitlebar();
8212 this._createButtonPane();
8213
8214 if ( this.options.draggable && $.fn.draggable ) {
8215 this._makeDraggable();
8216 }
8217 if ( this.options.resizable && $.fn.resizable ) {
8218 this._makeResizable();
8219 }
8220
8221 this._isOpen = false;
8222
8223 this._trackFocus();
8224 },
8225
8226 _init: function() {
8227 if ( this.options.autoOpen ) {
8228 this.open();
8229 }
8230 },
8231
8232 _appendTo: function() {
8233 var element = this.options.appendTo;
8234 if ( element && (element.jquery || element.nodeType) ) {
8235 return $( element );
8236 }
8237 return this.document.find( element || "body" ).eq( 0 );
8238 },
8239
8240 _destroy: function() {
8241 var next,
8242 originalPosition = this.originalPosition;
8243
8244 this._untrackInstance();
8245 this._destroyOverlay();
8246
8247 this.element
8248 .removeUniqueId()
8249 .removeClass( "ui-dialog-content ui-widget-content" )
8250 .css( this.originalCss )
8251 // Without detaching first, the following becomes really slow
8252 .detach();
8253
8254 this.uiDialog.stop( true, true ).remove();
8255
8256 if ( this.originalTitle ) {
8257 this.element.attr( "title", this.originalTitle );
8258 }
8259
8260 next = originalPosition.parent.children().eq( originalPosition.index );
8261 // Don't try to place the dialog next to itself (#8613)
8262 if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
8263 next.before( this.element );
8264 } else {
8265 originalPosition.parent.append( this.element );
8266 }
8267 },
8268
8269 widget: function() {
8270 return this.uiDialog;
8271 },
8272
8273 disable: $.noop,
8274 enable: $.noop,
8275
8276 close: function( event ) {
8277 var activeElement,
8278 that = this;
8279
8280 if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
8281 return;
8282 }
8283
8284 this._isOpen = false;
8285 this._focusedElement = null;
8286 this._destroyOverlay();
8287 this._untrackInstance();
8288
8289 if ( !this.opener.filter( ":focusable" ).focus().length ) {
8290
8291 // support: IE9
8292 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
8293 try {
8294 activeElement = this.document[ 0 ].activeElement;
8295
8296 // Support: IE9, IE10
8297 // If the <body> is blurred, IE will switch windows, see #4520
8298 if ( activeElement && activeElement.nodeName.toLowerCase() !== "body" ) {
8299
8300 // Hiding a focused element doesn't trigger blur in WebKit
8301 // so in case we have nothing to focus on, explicitly blur the active element
8302 // https://bugs.webkit.org/show_bug.cgi?id=47182
8303 $( activeElement ).blur();
8304 }
8305 } catch ( error ) {}
8306 }
8307
8308 this._hide( this.uiDialog, this.options.hide, function() {
8309 that._trigger( "close", event );
8310 });
8311 },
8312
8313 isOpen: function() {
8314 return this._isOpen;
8315 },
8316
8317 moveToTop: function() {
8318 this._moveToTop();
8319 },
8320
8321 _moveToTop: function( event, silent ) {
8322 var moved = false,
8323 zIndices = this.uiDialog.siblings( ".ui-front:visible" ).map(function() {
8324 return +$( this ).css( "z-index" );
8325 }).get(),
8326 zIndexMax = Math.max.apply( null, zIndices );
8327
8328 if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) {
8329 this.uiDialog.css( "z-index", zIndexMax + 1 );
8330 moved = true;
8331 }
8332
8333 if ( moved && !silent ) {
8334 this._trigger( "focus", event );
8335 }
8336 return moved;
8337 },
8338
8339 open: function() {
8340 var that = this;
8341 if ( this._isOpen ) {
8342 if ( this._moveToTop() ) {
8343 this._focusTabbable();
8344 }
8345 return;
8346 }
8347
8348 this._isOpen = true;
8349 this.opener = $( this.document[ 0 ].activeElement );
8350
8351 this._size();
8352 this._position();
8353 this._createOverlay();
8354 this._moveToTop( null, true );
8355
8356 // Ensure the overlay is moved to the top with the dialog, but only when
8357 // opening. The overlay shouldn't move after the dialog is open so that
8358 // modeless dialogs opened after the modal dialog stack properly.
8359 if ( this.overlay ) {
8360 this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 );
8361 }
8362
8363 this._show( this.uiDialog, this.options.show, function() {
8364 that._focusTabbable();
8365 that._trigger( "focus" );
8366 });
8367
8368 // Track the dialog immediately upon openening in case a focus event
8369 // somehow occurs outside of the dialog before an element inside the
8370 // dialog is focused (#10152)
8371 this._makeFocusTarget();
8372
8373 this._trigger( "open" );
8374 },
8375
8376 _focusTabbable: function() {
8377 // Set focus to the first match:
8378 // 1. An element that was focused previously
8379 // 2. First element inside the dialog matching [autofocus]
8380 // 3. Tabbable element inside the content element
8381 // 4. Tabbable element inside the buttonpane
8382 // 5. The close button
8383 // 6. The dialog itself
8384 var hasFocus = this._focusedElement;
8385 if ( !hasFocus ) {
8386 hasFocus = this.element.find( "[autofocus]" );
8387 }
8388 if ( !hasFocus.length ) {
8389 hasFocus = this.element.find( ":tabbable" );
8390 }
8391 if ( !hasFocus.length ) {
8392 hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
8393 }
8394 if ( !hasFocus.length ) {
8395 hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" );
8396 }
8397 if ( !hasFocus.length ) {
8398 hasFocus = this.uiDialog;
8399 }
8400 hasFocus.eq( 0 ).focus();
8401 },
8402
8403 _keepFocus: function( event ) {
8404 function checkFocus() {
8405 var activeElement = this.document[0].activeElement,
8406 isActive = this.uiDialog[0] === activeElement ||
8407 $.contains( this.uiDialog[0], activeElement );
8408 if ( !isActive ) {
8409 this._focusTabbable();
8410 }
8411 }
8412 event.preventDefault();
8413 checkFocus.call( this );
8414 // support: IE
8415 // IE <= 8 doesn't prevent moving focus even with event.preventDefault()
8416 // so we check again later
8417 this._delay( checkFocus );
8418 },
8419
8420 _createWrapper: function() {
8421 this.uiDialog = $("<div>")
8422 .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " +
8423 this.options.dialogClass )
8424 .hide()
8425 .attr({
8426 // Setting tabIndex makes the div focusable
8427 tabIndex: -1,
8428 role: "dialog"
8429 })
8430 .appendTo( this._appendTo() );
8431
8432 this._on( this.uiDialog, {
8433 keydown: function( event ) {
8434 if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
8435 event.keyCode === $.ui.keyCode.ESCAPE ) {
8436 event.preventDefault();
8437 this.close( event );
8438 return;
8439 }
8440
8441 // prevent tabbing out of dialogs
8442 if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) {
8443 return;
8444 }
8445 var tabbables = this.uiDialog.find( ":tabbable" ),
8446 first = tabbables.filter( ":first" ),
8447 last = tabbables.filter( ":last" );
8448
8449 if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) {
8450 this._delay(function() {
8451 first.focus();
8452 });
8453 event.preventDefault();
8454 } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) {
8455 this._delay(function() {
8456 last.focus();
8457 });
8458 event.preventDefault();
8459 }
8460 },
8461 mousedown: function( event ) {
8462 if ( this._moveToTop( event ) ) {
8463 this._focusTabbable();
8464 }
8465 }
8466 });
8467
8468 // We assume that any existing aria-describedby attribute means
8469 // that the dialog content is marked up properly
8470 // otherwise we brute force the content as the description
8471 if ( !this.element.find( "[aria-describedby]" ).length ) {
8472 this.uiDialog.attr({
8473 "aria-describedby": this.element.uniqueId().attr( "id" )
8474 });
8475 }
8476 },
8477
8478 _createTitlebar: function() {
8479 var uiDialogTitle;
8480
8481 this.uiDialogTitlebar = $( "<div>" )
8482 .addClass( "ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix" )
8483 .prependTo( this.uiDialog );
8484 this._on( this.uiDialogTitlebar, {
8485 mousedown: function( event ) {
8486 // Don't prevent click on close button (#8838)
8487 // Focusing a dialog that is partially scrolled out of view
8488 // causes the browser to scroll it into view, preventing the click event
8489 if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) {
8490 // Dialog isn't getting focus when dragging (#8063)
8491 this.uiDialog.focus();
8492 }
8493 }
8494 });
8495
8496 // support: IE
8497 // Use type="button" to prevent enter keypresses in textboxes from closing the
8498 // dialog in IE (#9312)
8499 this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
8500 .button({
8501 label: this.options.closeText,
8502 icons: {
8503 primary: "ui-icon-closethick"
8504 },
8505 text: false
8506 })
8507 .addClass( "ui-dialog-titlebar-close" )
8508 .appendTo( this.uiDialogTitlebar );
8509 this._on( this.uiDialogTitlebarClose, {
8510 click: function( event ) {
8511 event.preventDefault();
8512 this.close( event );
8513 }
8514 });
8515
8516 uiDialogTitle = $( "<span>" )
8517 .uniqueId()
8518 .addClass( "ui-dialog-title" )
8519 .prependTo( this.uiDialogTitlebar );
8520 this._title( uiDialogTitle );
8521
8522 this.uiDialog.attr({
8523 "aria-labelledby": uiDialogTitle.attr( "id" )
8524 });
8525 },
8526
8527 _title: function( title ) {
8528 if ( !this.options.title ) {
8529 title.html( "&#160;" );
8530 }
8531 title.text( this.options.title );
8532 },
8533
8534 _createButtonPane: function() {
8535 this.uiDialogButtonPane = $( "<div>" )
8536 .addClass( "ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" );
8537
8538 this.uiButtonSet = $( "<div>" )
8539 .addClass( "ui-dialog-buttonset" )
8540 .appendTo( this.uiDialogButtonPane );
8541
8542 this._createButtons();
8543 },
8544
8545 _createButtons: function() {
8546 var that = this,
8547 buttons = this.options.buttons;
8548
8549 // if we already have a button pane, remove it
8550 this.uiDialogButtonPane.remove();
8551 this.uiButtonSet.empty();
8552
8553 if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) {
8554 this.uiDialog.removeClass( "ui-dialog-buttons" );
8555 return;
8556 }
8557
8558 $.each( buttons, function( name, props ) {
8559 var click, buttonOptions;
8560 props = $.isFunction( props ) ?
8561 { click: props, text: name } :
8562 props;
8563 // Default to a non-submitting button
8564 props = $.extend( { type: "button" }, props );
8565 // Change the context for the click callback to be the main element
8566 click = props.click;
8567 props.click = function() {
8568 click.apply( that.element[ 0 ], arguments );
8569 };
8570 buttonOptions = {
8571 icons: props.icons,
8572 text: props.showText
8573 };
8574 delete props.icons;
8575 delete props.showText;
8576 $( "<button></button>", props )
8577 .button( buttonOptions )
8578 .appendTo( that.uiButtonSet );
8579 });
8580 this.uiDialog.addClass( "ui-dialog-buttons" );
8581 this.uiDialogButtonPane.appendTo( this.uiDialog );
8582 },
8583
8584 _makeDraggable: function() {
8585 var that = this,
8586 options = this.options;
8587
8588 function filteredUi( ui ) {
8589 return {
8590 position: ui.position,
8591 offset: ui.offset
8592 };
8593 }
8594
8595 this.uiDialog.draggable({
8596 cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
8597 handle: ".ui-dialog-titlebar",
8598 containment: "document",
8599 start: function( event, ui ) {
8600 $( this ).addClass( "ui-dialog-dragging" );
8601 that._blockFrames();
8602 that._trigger( "dragStart", event, filteredUi( ui ) );
8603 },
8604 drag: function( event, ui ) {
8605 that._trigger( "drag", event, filteredUi( ui ) );
8606 },
8607 stop: function( event, ui ) {
8608 var left = ui.offset.left - that.document.scrollLeft(),
8609 top = ui.offset.top - that.document.scrollTop();
8610
8611 options.position = {
8612 my: "left top",
8613 at: "left" + (left >= 0 ? "+" : "") + left + " " +
8614 "top" + (top >= 0 ? "+" : "") + top,
8615 of: that.window
8616 };
8617 $( this ).removeClass( "ui-dialog-dragging" );
8618 that._unblockFrames();
8619 that._trigger( "dragStop", event, filteredUi( ui ) );
8620 }
8621 });
8622 },
8623
8624 _makeResizable: function() {
8625 var that = this,
8626 options = this.options,
8627 handles = options.resizable,
8628 // .ui-resizable has position: relative defined in the stylesheet
8629 // but dialogs have to use absolute or fixed positioning
8630 position = this.uiDialog.css("position"),
8631 resizeHandles = typeof handles === "string" ?
8632 handles :
8633 "n,e,s,w,se,sw,ne,nw";
8634
8635 function filteredUi( ui ) {
8636 return {
8637 originalPosition: ui.originalPosition,
8638 originalSize: ui.originalSize,
8639 position: ui.position,
8640 size: ui.size
8641 };
8642 }
8643
8644 this.uiDialog.resizable({
8645 cancel: ".ui-dialog-content",
8646 containment: "document",
8647 alsoResize: this.element,
8648 maxWidth: options.maxWidth,
8649 maxHeight: options.maxHeight,
8650 minWidth: options.minWidth,
8651 minHeight: this._minHeight(),
8652 handles: resizeHandles,
8653 start: function( event, ui ) {
8654 $( this ).addClass( "ui-dialog-resizing" );
8655 that._blockFrames();
8656 that._trigger( "resizeStart", event, filteredUi( ui ) );
8657 },
8658 resize: function( event, ui ) {
8659 that._trigger( "resize", event, filteredUi( ui ) );
8660 },
8661 stop: function( event, ui ) {
8662 var offset = that.uiDialog.offset(),
8663 left = offset.left - that.document.scrollLeft(),
8664 top = offset.top - that.document.scrollTop();
8665
8666 options.height = that.uiDialog.height();
8667 options.width = that.uiDialog.width();
8668 options.position = {
8669 my: "left top",
8670 at: "left" + (left >= 0 ? "+" : "") + left + " " +
8671 "top" + (top >= 0 ? "+" : "") + top,
8672 of: that.window
8673 };
8674 $( this ).removeClass( "ui-dialog-resizing" );
8675 that._unblockFrames();
8676 that._trigger( "resizeStop", event, filteredUi( ui ) );
8677 }
8678 })
8679 .css( "position", position );
8680 },
8681
8682 _trackFocus: function() {
8683 this._on( this.widget(), {
8684 focusin: function( event ) {
8685 this._makeFocusTarget();
8686 this._focusedElement = $( event.target );
8687 }
8688 });
8689 },
8690
8691 _makeFocusTarget: function() {
8692 this._untrackInstance();
8693 this._trackingInstances().unshift( this );
8694 },
8695
8696 _untrackInstance: function() {
8697 var instances = this._trackingInstances(),
8698 exists = $.inArray( this, instances );
8699 if ( exists !== -1 ) {
8700 instances.splice( exists, 1 );
8701 }
8702 },
8703
8704 _trackingInstances: function() {
8705 var instances = this.document.data( "ui-dialog-instances" );
8706 if ( !instances ) {
8707 instances = [];
8708 this.document.data( "ui-dialog-instances", instances );
8709 }
8710 return instances;
8711 },
8712
8713 _minHeight: function() {
8714 var options = this.options;
8715
8716 return options.height === "auto" ?
8717 options.minHeight :
8718 Math.min( options.minHeight, options.height );
8719 },
8720
8721 _position: function() {
8722 // Need to show the dialog to get the actual offset in the position plugin
8723 var isVisible = this.uiDialog.is( ":visible" );
8724 if ( !isVisible ) {
8725 this.uiDialog.show();
8726 }
8727 this.uiDialog.position( this.options.position );
8728 if ( !isVisible ) {
8729 this.uiDialog.hide();
8730 }
8731 },
8732
8733 _setOptions: function( options ) {
8734 var that = this,
8735 resize = false,
8736 resizableOptions = {};
8737
8738 $.each( options, function( key, value ) {
8739 that._setOption( key, value );
8740
8741 if ( key in that.sizeRelatedOptions ) {
8742 resize = true;
8743 }
8744 if ( key in that.resizableRelatedOptions ) {
8745 resizableOptions[ key ] = value;
8746 }
8747 });
8748
8749 if ( resize ) {
8750 this._size();
8751 this._position();
8752 }
8753 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
8754 this.uiDialog.resizable( "option", resizableOptions );
8755 }
8756 },
8757
8758 _setOption: function( key, value ) {
8759 var isDraggable, isResizable,
8760 uiDialog = this.uiDialog;
8761
8762 if ( key === "dialogClass" ) {
8763 uiDialog
8764 .removeClass( this.options.dialogClass )
8765 .addClass( value );
8766 }
8767
8768 if ( key === "disabled" ) {
8769 return;
8770 }
8771
8772 this._super( key, value );
8773
8774 if ( key === "appendTo" ) {
8775 this.uiDialog.appendTo( this._appendTo() );
8776 }
8777
8778 if ( key === "buttons" ) {
8779 this._createButtons();
8780 }
8781
8782 if ( key === "closeText" ) {
8783 this.uiDialogTitlebarClose.button({
8784 // Ensure that we always pass a string
8785 label: "" + value
8786 });
8787 }
8788
8789 if ( key === "draggable" ) {
8790 isDraggable = uiDialog.is( ":data(ui-draggable)" );
8791 if ( isDraggable && !value ) {
8792 uiDialog.draggable( "destroy" );
8793 }
8794
8795 if ( !isDraggable && value ) {
8796 this._makeDraggable();
8797 }
8798 }
8799
8800 if ( key === "position" ) {
8801 this._position();
8802 }
8803
8804 if ( key === "resizable" ) {
8805 // currently resizable, becoming non-resizable
8806 isResizable = uiDialog.is( ":data(ui-resizable)" );
8807 if ( isResizable && !value ) {
8808 uiDialog.resizable( "destroy" );
8809 }
8810
8811 // currently resizable, changing handles
8812 if ( isResizable && typeof value === "string" ) {
8813 uiDialog.resizable( "option", "handles", value );
8814 }
8815
8816 // currently non-resizable, becoming resizable
8817 if ( !isResizable && value !== false ) {
8818 this._makeResizable();
8819 }
8820 }
8821
8822 if ( key === "title" ) {
8823 this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) );
8824 }
8825 },
8826
8827 _size: function() {
8828 // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
8829 // divs will both have width and height set, so we need to reset them
8830 var nonContentHeight, minContentHeight, maxContentHeight,
8831 options = this.options;
8832
8833 // Reset content sizing
8834 this.element.show().css({
8835 width: "auto",
8836 minHeight: 0,
8837 maxHeight: "none",
8838 height: 0
8839 });
8840
8841 if ( options.minWidth > options.width ) {
8842 options.width = options.minWidth;
8843 }
8844
8845 // reset wrapper sizing
8846 // determine the height of all the non-content elements
8847 nonContentHeight = this.uiDialog.css({
8848 height: "auto",
8849 width: options.width
8850 })
8851 .outerHeight();
8852 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
8853 maxContentHeight = typeof options.maxHeight === "number" ?
8854 Math.max( 0, options.maxHeight - nonContentHeight ) :
8855 "none";
8856
8857 if ( options.height === "auto" ) {
8858 this.element.css({
8859 minHeight: minContentHeight,
8860 maxHeight: maxContentHeight,
8861 height: "auto"
8862 });
8863 } else {
8864 this.element.height( Math.max( 0, options.height - nonContentHeight ) );
8865 }
8866
8867 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
8868 this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
8869 }
8870 },
8871
8872 _blockFrames: function() {
8873 this.iframeBlocks = this.document.find( "iframe" ).map(function() {
8874 var iframe = $( this );
8875
8876 return $( "<div>" )
8877 .css({
8878 position: "absolute",
8879 width: iframe.outerWidth(),
8880 height: iframe.outerHeight()
8881 })
8882 .appendTo( iframe.parent() )
8883 .offset( iframe.offset() )[0];
8884 });
8885 },
8886
8887 _unblockFrames: function() {
8888 if ( this.iframeBlocks ) {
8889 this.iframeBlocks.remove();
8890 delete this.iframeBlocks;
8891 }
8892 },
8893
8894 _allowInteraction: function( event ) {
8895 if ( $( event.target ).closest( ".ui-dialog" ).length ) {
8896 return true;
8897 }
8898
8899 // TODO: Remove hack when datepicker implements
8900 // the .ui-front logic (#8989)
8901 return !!$( event.target ).closest( ".ui-datepicker" ).length;
8902 },
8903
8904 _createOverlay: function() {
8905 if ( !this.options.modal ) {
8906 return;
8907 }
8908
8909 // We use a delay in case the overlay is created from an
8910 // event that we're going to be cancelling (#2804)
8911 var isOpening = true;
8912 this._delay(function() {
8913 isOpening = false;
8914 });
8915
8916 if ( !this.document.data( "ui-dialog-overlays" ) ) {
8917
8918 // Prevent use of anchors and inputs
8919 // Using _on() for an event handler shared across many instances is
8920 // safe because the dialogs stack and must be closed in reverse order
8921 this._on( this.document, {
8922 focusin: function( event ) {
8923 if ( isOpening ) {
8924 return;
8925 }
8926
8927 if ( !this._allowInteraction( event ) ) {
8928 event.preventDefault();
8929 this._trackingInstances()[ 0 ]._focusTabbable();
8930 }
8931 }
8932 });
8933 }
8934
8935 this.overlay = $( "<div>" )
8936 .addClass( "ui-widget-overlay ui-front" )
8937 .appendTo( this._appendTo() );
8938 this._on( this.overlay, {
8939 mousedown: "_keepFocus"
8940 });
8941 this.document.data( "ui-dialog-overlays",
8942 (this.document.data( "ui-dialog-overlays" ) || 0) + 1 );
8943 },
8944
8945 _destroyOverlay: function() {
8946 if ( !this.options.modal ) {
8947 return;
8948 }
8949
8950 if ( this.overlay ) {
8951 var overlays = this.document.data( "ui-dialog-overlays" ) - 1;
8952
8953 if ( !overlays ) {
8954 this.document
8955 .unbind( "focusin" )
8956 .removeData( "ui-dialog-overlays" );
8957 } else {
8958 this.document.data( "ui-dialog-overlays", overlays );
8959 }
8960
8961 this.overlay.remove();
8962 this.overlay = null;
8963 }
8964 }
8965 });
8966
8967
8968 /*!
8969 * jQuery UI Droppable 1.11.4
8970 * http://jqueryui.com
8971 *
8972 * Copyright jQuery Foundation and other contributors
8973 * Released under the MIT license.
8974 * http://jquery.org/license
8975 *
8976 * http://api.jqueryui.com/droppable/
8977 */
8978
8979
8980 $.widget( "ui.droppable", {
8981 version: "1.11.4",
8982 widgetEventPrefix: "drop",
8983 options: {
8984 accept: "*",
8985 activeClass: false,
8986 addClasses: true,
8987 greedy: false,
8988 hoverClass: false,
8989 scope: "default",
8990 tolerance: "intersect",
8991
8992 // callbacks
8993 activate: null,
8994 deactivate: null,
8995 drop: null,
8996 out: null,
8997 over: null
8998 },
8999 _create: function() {
9000
9001 var proportions,
9002 o = this.options,
9003 accept = o.accept;
9004
9005 this.isover = false;
9006 this.isout = true;
9007
9008 this.accept = $.isFunction( accept ) ? accept : function( d ) {
9009 return d.is( accept );
9010 };
9011
9012 this.proportions = function( /* valueToWrite */ ) {
9013 if ( arguments.length ) {
9014 // Store the droppable's proportions
9015 proportions = arguments[ 0 ];
9016 } else {
9017 // Retrieve or derive the droppable's proportions
9018 return proportions ?
9019 proportions :
9020 proportions = {
9021 width: this.element[ 0 ].offsetWidth,
9022 height: this.element[ 0 ].offsetHeight
9023 };
9024 }
9025 };
9026
9027 this._addToManager( o.scope );
9028
9029 o.addClasses && this.element.addClass( "ui-droppable" );
9030
9031 },
9032
9033 _addToManager: function( scope ) {
9034 // Add the reference and positions to the manager
9035 $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || [];
9036 $.ui.ddmanager.droppables[ scope ].push( this );
9037 },
9038
9039 _splice: function( drop ) {
9040 var i = 0;
9041 for ( ; i < drop.length; i++ ) {
9042 if ( drop[ i ] === this ) {
9043 drop.splice( i, 1 );
9044 }
9045 }
9046 },
9047
9048 _destroy: function() {
9049 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
9050
9051 this._splice( drop );
9052
9053 this.element.removeClass( "ui-droppable ui-droppable-disabled" );
9054 },
9055
9056 _setOption: function( key, value ) {
9057
9058 if ( key === "accept" ) {
9059 this.accept = $.isFunction( value ) ? value : function( d ) {
9060 return d.is( value );
9061 };
9062 } else if ( key === "scope" ) {
9063 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
9064
9065 this._splice( drop );
9066 this._addToManager( value );
9067 }
9068
9069 this._super( key, value );
9070 },
9071
9072 _activate: function( event ) {
9073 var draggable = $.ui.ddmanager.current;
9074 if ( this.options.activeClass ) {
9075 this.element.addClass( this.options.activeClass );
9076 }
9077 if ( draggable ){
9078 this._trigger( "activate", event, this.ui( draggable ) );
9079 }
9080 },
9081
9082 _deactivate: function( event ) {
9083 var draggable = $.ui.ddmanager.current;
9084 if ( this.options.activeClass ) {
9085 this.element.removeClass( this.options.activeClass );
9086 }
9087 if ( draggable ){
9088 this._trigger( "deactivate", event, this.ui( draggable ) );
9089 }
9090 },
9091
9092 _over: function( event ) {
9093
9094 var draggable = $.ui.ddmanager.current;
9095
9096 // Bail if draggable and droppable are same element
9097 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
9098 return;
9099 }
9100
9101 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
9102 if ( this.options.hoverClass ) {
9103 this.element.addClass( this.options.hoverClass );
9104 }
9105 this._trigger( "over", event, this.ui( draggable ) );
9106 }
9107
9108 },
9109
9110 _out: function( event ) {
9111
9112 var draggable = $.ui.ddmanager.current;
9113
9114 // Bail if draggable and droppable are same element
9115 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
9116 return;
9117 }
9118
9119 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
9120 if ( this.options.hoverClass ) {
9121 this.element.removeClass( this.options.hoverClass );
9122 }
9123 this._trigger( "out", event, this.ui( draggable ) );
9124 }
9125
9126 },
9127
9128 _drop: function( event, custom ) {
9129
9130 var draggable = custom || $.ui.ddmanager.current,
9131 childrenIntersection = false;
9132
9133 // Bail if draggable and droppable are same element
9134 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
9135 return false;
9136 }
9137
9138 this.element.find( ":data(ui-droppable)" ).not( ".ui-draggable-dragging" ).each(function() {
9139 var inst = $( this ).droppable( "instance" );
9140 if (
9141 inst.options.greedy &&
9142 !inst.options.disabled &&
9143 inst.options.scope === draggable.options.scope &&
9144 inst.accept.call( inst.element[ 0 ], ( draggable.currentItem || draggable.element ) ) &&
9145 $.ui.intersect( draggable, $.extend( inst, { offset: inst.element.offset() } ), inst.options.tolerance, event )
9146 ) { childrenIntersection = true; return false; }
9147 });
9148 if ( childrenIntersection ) {
9149 return false;
9150 }
9151
9152 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
9153 if ( this.options.activeClass ) {
9154 this.element.removeClass( this.options.activeClass );
9155 }
9156 if ( this.options.hoverClass ) {
9157 this.element.removeClass( this.options.hoverClass );
9158 }
9159 this._trigger( "drop", event, this.ui( draggable ) );
9160 return this.element;
9161 }
9162
9163 return false;
9164
9165 },
9166
9167 ui: function( c ) {
9168 return {
9169 draggable: ( c.currentItem || c.element ),
9170 helper: c.helper,
9171 position: c.position,
9172 offset: c.positionAbs
9173 };
9174 }
9175
9176 });
9177
9178 $.ui.intersect = (function() {
9179 function isOverAxis( x, reference, size ) {
9180 return ( x >= reference ) && ( x < ( reference + size ) );
9181 }
9182
9183 return function( draggable, droppable, toleranceMode, event ) {
9184
9185 if ( !droppable.offset ) {
9186 return false;
9187 }
9188
9189 var x1 = ( draggable.positionAbs || draggable.position.absolute ).left + draggable.margins.left,
9190 y1 = ( draggable.positionAbs || draggable.position.absolute ).top + draggable.margins.top,
9191 x2 = x1 + draggable.helperProportions.width,
9192 y2 = y1 + draggable.helperProportions.height,
9193 l = droppable.offset.left,
9194 t = droppable.offset.top,
9195 r = l + droppable.proportions().width,
9196 b = t + droppable.proportions().height;
9197
9198 switch ( toleranceMode ) {
9199 case "fit":
9200 return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
9201 case "intersect":
9202 return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
9203 x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
9204 t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
9205 y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
9206 case "pointer":
9207 return isOverAxis( event.pageY, t, droppable.proportions().height ) && isOverAxis( event.pageX, l, droppable.proportions().width );
9208 case "touch":
9209 return (
9210 ( y1 >= t && y1 <= b ) || // Top edge touching
9211 ( y2 >= t && y2 <= b ) || // Bottom edge touching
9212 ( y1 < t && y2 > b ) // Surrounded vertically
9213 ) && (
9214 ( x1 >= l && x1 <= r ) || // Left edge touching
9215 ( x2 >= l && x2 <= r ) || // Right edge touching
9216 ( x1 < l && x2 > r ) // Surrounded horizontally
9217 );
9218 default:
9219 return false;
9220 }
9221 };
9222 })();
9223
9224 /*
9225 This manager tracks offsets of draggables and droppables
9226 */
9227 $.ui.ddmanager = {
9228 current: null,
9229 droppables: { "default": [] },
9230 prepareOffsets: function( t, event ) {
9231
9232 var i, j,
9233 m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
9234 type = event ? event.type : null, // workaround for #2317
9235 list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack();
9236
9237 droppablesLoop: for ( i = 0; i < m.length; i++ ) {
9238
9239 // No disabled and non-accepted
9240 if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ], ( t.currentItem || t.element ) ) ) ) {
9241 continue;
9242 }
9243
9244 // Filter out elements in the current dragged item
9245 for ( j = 0; j < list.length; j++ ) {
9246 if ( list[ j ] === m[ i ].element[ 0 ] ) {
9247 m[ i ].proportions().height = 0;
9248 continue droppablesLoop;
9249 }
9250 }
9251
9252 m[ i ].visible = m[ i ].element.css( "display" ) !== "none";
9253 if ( !m[ i ].visible ) {
9254 continue;
9255 }
9256
9257 // Activate the droppable if used directly from draggables
9258 if ( type === "mousedown" ) {
9259 m[ i ]._activate.call( m[ i ], event );
9260 }
9261
9262 m[ i ].offset = m[ i ].element.offset();
9263 m[ i ].proportions({ width: m[ i ].element[ 0 ].offsetWidth, height: m[ i ].element[ 0 ].offsetHeight });
9264
9265 }
9266
9267 },
9268 drop: function( draggable, event ) {
9269
9270 var dropped = false;
9271 // Create a copy of the droppables in case the list changes during the drop (#9116)
9272 $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {
9273
9274 if ( !this.options ) {
9275 return;
9276 }
9277 if ( !this.options.disabled && this.visible && $.ui.intersect( draggable, this, this.options.tolerance, event ) ) {
9278 dropped = this._drop.call( this, event ) || dropped;
9279 }
9280
9281 if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
9282 this.isout = true;
9283 this.isover = false;
9284 this._deactivate.call( this, event );
9285 }
9286
9287 });
9288 return dropped;
9289
9290 },
9291 dragStart: function( draggable, event ) {
9292 // Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
9293 draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
9294 if ( !draggable.options.refreshPositions ) {
9295 $.ui.ddmanager.prepareOffsets( draggable, event );
9296 }
9297 });
9298 },
9299 drag: function( draggable, event ) {
9300
9301 // If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
9302 if ( draggable.options.refreshPositions ) {
9303 $.ui.ddmanager.prepareOffsets( draggable, event );
9304 }
9305
9306 // Run through all droppables and check their positions based on specific tolerance options
9307 $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {
9308
9309 if ( this.options.disabled || this.greedyChild || !this.visible ) {
9310 return;
9311 }
9312
9313 var parentInstance, scope, parent,
9314 intersects = $.ui.intersect( draggable, this, this.options.tolerance, event ),
9315 c = !intersects && this.isover ? "isout" : ( intersects && !this.isover ? "isover" : null );
9316 if ( !c ) {
9317 return;
9318 }
9319
9320 if ( this.options.greedy ) {
9321 // find droppable parents with same scope
9322 scope = this.options.scope;
9323 parent = this.element.parents( ":data(ui-droppable)" ).filter(function() {
9324 return $( this ).droppable( "instance" ).options.scope === scope;
9325 });
9326
9327 if ( parent.length ) {
9328 parentInstance = $( parent[ 0 ] ).droppable( "instance" );
9329 parentInstance.greedyChild = ( c === "isover" );
9330 }
9331 }
9332
9333 // we just moved into a greedy child
9334 if ( parentInstance && c === "isover" ) {
9335 parentInstance.isover = false;
9336 parentInstance.isout = true;
9337 parentInstance._out.call( parentInstance, event );
9338 }
9339
9340 this[ c ] = true;
9341 this[c === "isout" ? "isover" : "isout"] = false;
9342 this[c === "isover" ? "_over" : "_out"].call( this, event );
9343
9344 // we just moved out of a greedy child
9345 if ( parentInstance && c === "isout" ) {
9346 parentInstance.isout = false;
9347 parentInstance.isover = true;
9348 parentInstance._over.call( parentInstance, event );
9349 }
9350 });
9351
9352 },
9353 dragStop: function( draggable, event ) {
9354 draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
9355 // Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
9356 if ( !draggable.options.refreshPositions ) {
9357 $.ui.ddmanager.prepareOffsets( draggable, event );
9358 }
9359 }
9360 };
9361
9362 var droppable = $.ui.droppable;
9363
9364
9365 /*!
9366 * jQuery UI Effects 1.11.4
9367 * http://jqueryui.com
9368 *
9369 * Copyright jQuery Foundation and other contributors
9370 * Released under the MIT license.
9371 * http://jquery.org/license
9372 *
9373 * http://api.jqueryui.com/category/effects-core/
9374 */
9375
9376
9377 var dataSpace = "ui-effects-",
9378
9379 // Create a local jQuery because jQuery Color relies on it and the
9380 // global may not exist with AMD and a custom build (#10199)
9381 jQuery = $;
9382
9383 $.effects = {
9384 effect: {}
9385 };
9386
9387 /*!
9388 * jQuery Color Animations v2.1.2
9389 * https://github.com/jquery/jquery-color
9390 *
9391 * Copyright 2014 jQuery Foundation and other contributors
9392 * Released under the MIT license.
9393 * http://jquery.org/license
9394 *
9395 * Date: Wed Jan 16 08:47:09 2013 -0600
9396 */
9397 (function( jQuery, undefined ) {
9398
9399 var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
9400
9401 // plusequals test for += 100 -= 100
9402 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
9403 // a set of RE's that can match strings and generate color tuples.
9404 stringParsers = [ {
9405 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
9406 parse: function( execResult ) {
9407 return [
9408 execResult[ 1 ],
9409 execResult[ 2 ],
9410 execResult[ 3 ],
9411 execResult[ 4 ]
9412 ];
9413 }
9414 }, {
9415 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
9416 parse: function( execResult ) {
9417 return [
9418 execResult[ 1 ] * 2.55,
9419 execResult[ 2 ] * 2.55,
9420 execResult[ 3 ] * 2.55,
9421 execResult[ 4 ]
9422 ];
9423 }
9424 }, {
9425 // this regex ignores A-F because it's compared against an already lowercased string
9426 re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
9427 parse: function( execResult ) {
9428 return [
9429 parseInt( execResult[ 1 ], 16 ),
9430 parseInt( execResult[ 2 ], 16 ),
9431 parseInt( execResult[ 3 ], 16 )
9432 ];
9433 }
9434 }, {
9435 // this regex ignores A-F because it's compared against an already lowercased string
9436 re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
9437 parse: function( execResult ) {
9438 return [
9439 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
9440 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
9441 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
9442 ];
9443 }
9444 }, {
9445 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
9446 space: "hsla",
9447 parse: function( execResult ) {
9448 return [
9449 execResult[ 1 ],
9450 execResult[ 2 ] / 100,
9451 execResult[ 3 ] / 100,
9452 execResult[ 4 ]
9453 ];
9454 }
9455 } ],
9456
9457 // jQuery.Color( )
9458 color = jQuery.Color = function( color, green, blue, alpha ) {
9459 return new jQuery.Color.fn.parse( color, green, blue, alpha );
9460 },
9461 spaces = {
9462 rgba: {
9463 props: {
9464 red: {
9465 idx: 0,
9466 type: "byte"
9467 },
9468 green: {
9469 idx: 1,
9470 type: "byte"
9471 },
9472 blue: {
9473 idx: 2,
9474 type: "byte"
9475 }
9476 }
9477 },
9478
9479 hsla: {
9480 props: {
9481 hue: {
9482 idx: 0,
9483 type: "degrees"
9484 },
9485 saturation: {
9486 idx: 1,
9487 type: "percent"
9488 },
9489 lightness: {
9490 idx: 2,
9491 type: "percent"
9492 }
9493 }
9494 }
9495 },
9496 propTypes = {
9497 "byte": {
9498 floor: true,
9499 max: 255
9500 },
9501 "percent": {
9502 max: 1
9503 },
9504 "degrees": {
9505 mod: 360,
9506 floor: true
9507 }
9508 },
9509 support = color.support = {},
9510
9511 // element for support tests
9512 supportElem = jQuery( "<p>" )[ 0 ],
9513
9514 // colors = jQuery.Color.names
9515 colors,
9516
9517 // local aliases of functions called often
9518 each = jQuery.each;
9519
9520 // determine rgba support immediately
9521 supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
9522 support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
9523
9524 // define cache name and alpha properties
9525 // for rgba and hsla spaces
9526 each( spaces, function( spaceName, space ) {
9527 space.cache = "_" + spaceName;
9528 space.props.alpha = {
9529 idx: 3,
9530 type: "percent",
9531 def: 1
9532 };
9533 });
9534
9535 function clamp( value, prop, allowEmpty ) {
9536 var type = propTypes[ prop.type ] || {};
9537
9538 if ( value == null ) {
9539 return (allowEmpty || !prop.def) ? null : prop.def;
9540 }
9541
9542 // ~~ is an short way of doing floor for positive numbers
9543 value = type.floor ? ~~value : parseFloat( value );
9544
9545 // IE will pass in empty strings as value for alpha,
9546 // which will hit this case
9547 if ( isNaN( value ) ) {
9548 return prop.def;
9549 }
9550
9551 if ( type.mod ) {
9552 // we add mod before modding to make sure that negatives values
9553 // get converted properly: -10 -> 350
9554 return (value + type.mod) % type.mod;
9555 }
9556
9557 // for now all property types without mod have min and max
9558 return 0 > value ? 0 : type.max < value ? type.max : value;
9559 }
9560
9561 function stringParse( string ) {
9562 var inst = color(),
9563 rgba = inst._rgba = [];
9564
9565 string = string.toLowerCase();
9566
9567 each( stringParsers, function( i, parser ) {
9568 var parsed,
9569 match = parser.re.exec( string ),
9570 values = match && parser.parse( match ),
9571 spaceName = parser.space || "rgba";
9572
9573 if ( values ) {
9574 parsed = inst[ spaceName ]( values );
9575
9576 // if this was an rgba parse the assignment might happen twice
9577 // oh well....
9578 inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
9579 rgba = inst._rgba = parsed._rgba;
9580
9581 // exit each( stringParsers ) here because we matched
9582 return false;
9583 }
9584 });
9585
9586 // Found a stringParser that handled it
9587 if ( rgba.length ) {
9588
9589 // if this came from a parsed string, force "transparent" when alpha is 0
9590 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
9591 if ( rgba.join() === "0,0,0,0" ) {
9592 jQuery.extend( rgba, colors.transparent );
9593 }
9594 return inst;
9595 }
9596
9597 // named colors
9598 return colors[ string ];
9599 }
9600
9601 color.fn = jQuery.extend( color.prototype, {
9602 parse: function( red, green, blue, alpha ) {
9603 if ( red === undefined ) {
9604 this._rgba = [ null, null, null, null ];
9605 return this;
9606 }
9607 if ( red.jquery || red.nodeType ) {
9608 red = jQuery( red ).css( green );
9609 green = undefined;
9610 }
9611
9612 var inst = this,
9613 type = jQuery.type( red ),
9614 rgba = this._rgba = [];
9615
9616 // more than 1 argument specified - assume ( red, green, blue, alpha )
9617 if ( green !== undefined ) {
9618 red = [ red, green, blue, alpha ];
9619 type = "array";
9620 }
9621
9622 if ( type === "string" ) {
9623 return this.parse( stringParse( red ) || colors._default );
9624 }
9625
9626 if ( type === "array" ) {
9627 each( spaces.rgba.props, function( key, prop ) {
9628 rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
9629 });
9630 return this;
9631 }
9632
9633 if ( type === "object" ) {
9634 if ( red instanceof color ) {
9635 each( spaces, function( spaceName, space ) {
9636 if ( red[ space.cache ] ) {
9637 inst[ space.cache ] = red[ space.cache ].slice();
9638 }
9639 });
9640 } else {
9641 each( spaces, function( spaceName, space ) {
9642 var cache = space.cache;
9643 each( space.props, function( key, prop ) {
9644
9645 // if the cache doesn't exist, and we know how to convert
9646 if ( !inst[ cache ] && space.to ) {
9647
9648 // if the value was null, we don't need to copy it
9649 // if the key was alpha, we don't need to copy it either
9650 if ( key === "alpha" || red[ key ] == null ) {
9651 return;
9652 }
9653 inst[ cache ] = space.to( inst._rgba );
9654 }
9655
9656 // this is the only case where we allow nulls for ALL properties.
9657 // call clamp with alwaysAllowEmpty
9658 inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
9659 });
9660
9661 // everything defined but alpha?
9662 if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
9663 // use the default of 1
9664 inst[ cache ][ 3 ] = 1;
9665 if ( space.from ) {
9666 inst._rgba = space.from( inst[ cache ] );
9667 }
9668 }
9669 });
9670 }
9671 return this;
9672 }
9673 },
9674 is: function( compare ) {
9675 var is = color( compare ),
9676 same = true,
9677 inst = this;
9678
9679 each( spaces, function( _, space ) {
9680 var localCache,
9681 isCache = is[ space.cache ];
9682 if (isCache) {
9683 localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
9684 each( space.props, function( _, prop ) {
9685 if ( isCache[ prop.idx ] != null ) {
9686 same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
9687 return same;
9688 }
9689 });
9690 }
9691 return same;
9692 });
9693 return same;
9694 },
9695 _space: function() {
9696 var used = [],
9697 inst = this;
9698 each( spaces, function( spaceName, space ) {
9699 if ( inst[ space.cache ] ) {
9700 used.push( spaceName );
9701 }
9702 });
9703 return used.pop();
9704 },
9705 transition: function( other, distance ) {
9706 var end = color( other ),
9707 spaceName = end._space(),
9708 space = spaces[ spaceName ],
9709 startColor = this.alpha() === 0 ? color( "transparent" ) : this,
9710 start = startColor[ space.cache ] || space.to( startColor._rgba ),
9711 result = start.slice();
9712
9713 end = end[ space.cache ];
9714 each( space.props, function( key, prop ) {
9715 var index = prop.idx,
9716 startValue = start[ index ],
9717 endValue = end[ index ],
9718 type = propTypes[ prop.type ] || {};
9719
9720 // if null, don't override start value
9721 if ( endValue === null ) {
9722 return;
9723 }
9724 // if null - use end
9725 if ( startValue === null ) {
9726 result[ index ] = endValue;
9727 } else {
9728 if ( type.mod ) {
9729 if ( endValue - startValue > type.mod / 2 ) {
9730 startValue += type.mod;
9731 } else if ( startValue - endValue > type.mod / 2 ) {
9732 startValue -= type.mod;
9733 }
9734 }
9735 result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
9736 }
9737 });
9738 return this[ spaceName ]( result );
9739 },
9740 blend: function( opaque ) {
9741 // if we are already opaque - return ourself
9742 if ( this._rgba[ 3 ] === 1 ) {
9743 return this;
9744 }
9745
9746 var rgb = this._rgba.slice(),
9747 a = rgb.pop(),
9748 blend = color( opaque )._rgba;
9749
9750 return color( jQuery.map( rgb, function( v, i ) {
9751 return ( 1 - a ) * blend[ i ] + a * v;
9752 }));
9753 },
9754 toRgbaString: function() {
9755 var prefix = "rgba(",
9756 rgba = jQuery.map( this._rgba, function( v, i ) {
9757 return v == null ? ( i > 2 ? 1 : 0 ) : v;
9758 });
9759
9760 if ( rgba[ 3 ] === 1 ) {
9761 rgba.pop();
9762 prefix = "rgb(";
9763 }
9764
9765 return prefix + rgba.join() + ")";
9766 },
9767 toHslaString: function() {
9768 var prefix = "hsla(",
9769 hsla = jQuery.map( this.hsla(), function( v, i ) {
9770 if ( v == null ) {
9771 v = i > 2 ? 1 : 0;
9772 }
9773
9774 // catch 1 and 2
9775 if ( i && i < 3 ) {
9776 v = Math.round( v * 100 ) + "%";
9777 }
9778 return v;
9779 });
9780
9781 if ( hsla[ 3 ] === 1 ) {
9782 hsla.pop();
9783 prefix = "hsl(";
9784 }
9785 return prefix + hsla.join() + ")";
9786 },
9787 toHexString: function( includeAlpha ) {
9788 var rgba = this._rgba.slice(),
9789 alpha = rgba.pop();
9790
9791 if ( includeAlpha ) {
9792 rgba.push( ~~( alpha * 255 ) );
9793 }
9794
9795 return "#" + jQuery.map( rgba, function( v ) {
9796
9797 // default to 0 when nulls exist
9798 v = ( v || 0 ).toString( 16 );
9799 return v.length === 1 ? "0" + v : v;
9800 }).join("");
9801 },
9802 toString: function() {
9803 return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
9804 }
9805 });
9806 color.fn.parse.prototype = color.fn;
9807
9808 // hsla conversions adapted from:
9809 // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
9810
9811 function hue2rgb( p, q, h ) {
9812 h = ( h + 1 ) % 1;
9813 if ( h * 6 < 1 ) {
9814 return p + ( q - p ) * h * 6;
9815 }
9816 if ( h * 2 < 1) {
9817 return q;
9818 }
9819 if ( h * 3 < 2 ) {
9820 return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6;
9821 }
9822 return p;
9823 }
9824
9825 spaces.hsla.to = function( rgba ) {
9826 if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
9827 return [ null, null, null, rgba[ 3 ] ];
9828 }
9829 var r = rgba[ 0 ] / 255,
9830 g = rgba[ 1 ] / 255,
9831 b = rgba[ 2 ] / 255,
9832 a = rgba[ 3 ],
9833 max = Math.max( r, g, b ),
9834 min = Math.min( r, g, b ),
9835 diff = max - min,
9836 add = max + min,
9837 l = add * 0.5,
9838 h, s;
9839
9840 if ( min === max ) {
9841 h = 0;
9842 } else if ( r === max ) {
9843 h = ( 60 * ( g - b ) / diff ) + 360;
9844 } else if ( g === max ) {
9845 h = ( 60 * ( b - r ) / diff ) + 120;
9846 } else {
9847 h = ( 60 * ( r - g ) / diff ) + 240;
9848 }
9849
9850 // chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
9851 // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
9852 if ( diff === 0 ) {
9853 s = 0;
9854 } else if ( l <= 0.5 ) {
9855 s = diff / add;
9856 } else {
9857 s = diff / ( 2 - add );
9858 }
9859 return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
9860 };
9861
9862 spaces.hsla.from = function( hsla ) {
9863 if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
9864 return [ null, null, null, hsla[ 3 ] ];
9865 }
9866 var h = hsla[ 0 ] / 360,
9867 s = hsla[ 1 ],
9868 l = hsla[ 2 ],
9869 a = hsla[ 3 ],
9870 q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
9871 p = 2 * l - q;
9872
9873 return [
9874 Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
9875 Math.round( hue2rgb( p, q, h ) * 255 ),
9876 Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
9877 a
9878 ];
9879 };
9880
9881 each( spaces, function( spaceName, space ) {
9882 var props = space.props,
9883 cache = space.cache,
9884 to = space.to,
9885 from = space.from;
9886
9887 // makes rgba() and hsla()
9888 color.fn[ spaceName ] = function( value ) {
9889
9890 // generate a cache for this space if it doesn't exist
9891 if ( to && !this[ cache ] ) {
9892 this[ cache ] = to( this._rgba );
9893 }
9894 if ( value === undefined ) {
9895 return this[ cache ].slice();
9896 }
9897
9898 var ret,
9899 type = jQuery.type( value ),
9900 arr = ( type === "array" || type === "object" ) ? value : arguments,
9901 local = this[ cache ].slice();
9902
9903 each( props, function( key, prop ) {
9904 var val = arr[ type === "object" ? key : prop.idx ];
9905 if ( val == null ) {
9906 val = local[ prop.idx ];
9907 }
9908 local[ prop.idx ] = clamp( val, prop );
9909 });
9910
9911 if ( from ) {
9912 ret = color( from( local ) );
9913 ret[ cache ] = local;
9914 return ret;
9915 } else {
9916 return color( local );
9917 }
9918 };
9919
9920 // makes red() green() blue() alpha() hue() saturation() lightness()
9921 each( props, function( key, prop ) {
9922 // alpha is included in more than one space
9923 if ( color.fn[ key ] ) {
9924 return;
9925 }
9926 color.fn[ key ] = function( value ) {
9927 var vtype = jQuery.type( value ),
9928 fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
9929 local = this[ fn ](),
9930 cur = local[ prop.idx ],
9931 match;
9932
9933 if ( vtype === "undefined" ) {
9934 return cur;
9935 }
9936
9937 if ( vtype === "function" ) {
9938 value = value.call( this, cur );
9939 vtype = jQuery.type( value );
9940 }
9941 if ( value == null && prop.empty ) {
9942 return this;
9943 }
9944 if ( vtype === "string" ) {
9945 match = rplusequals.exec( value );
9946 if ( match ) {
9947 value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
9948 }
9949 }
9950 local[ prop.idx ] = value;
9951 return this[ fn ]( local );
9952 };
9953 });
9954 });
9955
9956 // add cssHook and .fx.step function for each named hook.
9957 // accept a space separated string of properties
9958 color.hook = function( hook ) {
9959 var hooks = hook.split( " " );
9960 each( hooks, function( i, hook ) {
9961 jQuery.cssHooks[ hook ] = {
9962 set: function( elem, value ) {
9963 var parsed, curElem,
9964 backgroundColor = "";
9965
9966 if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
9967 value = color( parsed || value );
9968 if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
9969 curElem = hook === "backgroundColor" ? elem.parentNode : elem;
9970 while (
9971 (backgroundColor === "" || backgroundColor === "transparent") &&
9972 curElem && curElem.style
9973 ) {
9974 try {
9975 backgroundColor = jQuery.css( curElem, "backgroundColor" );
9976 curElem = curElem.parentNode;
9977 } catch ( e ) {
9978 }
9979 }
9980
9981 value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
9982 backgroundColor :
9983 "_default" );
9984 }
9985
9986 value = value.toRgbaString();
9987 }
9988 try {
9989 elem.style[ hook ] = value;
9990 } catch ( e ) {
9991 // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
9992 }
9993 }
9994 };
9995 jQuery.fx.step[ hook ] = function( fx ) {
9996 if ( !fx.colorInit ) {
9997 fx.start = color( fx.elem, hook );
9998 fx.end = color( fx.end );
9999 fx.colorInit = true;
10000 }
10001 jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
10002 };
10003 });
10004
10005 };
10006
10007 color.hook( stepHooks );
10008
10009 jQuery.cssHooks.borderColor = {
10010 expand: function( value ) {
10011 var expanded = {};
10012
10013 each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
10014 expanded[ "border" + part + "Color" ] = value;
10015 });
10016 return expanded;
10017 }
10018 };
10019
10020 // Basic color names only.
10021 // Usage of any of the other color names requires adding yourself or including
10022 // jquery.color.svg-names.js.
10023 colors = jQuery.Color.names = {
10024 // 4.1. Basic color keywords
10025 aqua: "#00ffff",
10026 black: "#000000",
10027 blue: "#0000ff",
10028 fuchsia: "#ff00ff",
10029 gray: "#808080",
10030 green: "#008000",
10031 lime: "#00ff00",
10032 maroon: "#800000",
10033 navy: "#000080",
10034 olive: "#808000",
10035 purple: "#800080",
10036 red: "#ff0000",
10037 silver: "#c0c0c0",
10038 teal: "#008080",
10039 white: "#ffffff",
10040 yellow: "#ffff00",
10041
10042 // 4.2.3. "transparent" color keyword
10043 transparent: [ null, null, null, 0 ],
10044
10045 _default: "#ffffff"
10046 };
10047
10048 })( jQuery );
10049
10050 /******************************************************************************/
10051 /****************************** CLASS ANIMATIONS ******************************/
10052 /******************************************************************************/
10053 (function() {
10054
10055 var classAnimationActions = [ "add", "remove", "toggle" ],
10056 shorthandStyles = {
10057 border: 1,
10058 borderBottom: 1,
10059 borderColor: 1,
10060 borderLeft: 1,
10061 borderRight: 1,
10062 borderTop: 1,
10063 borderWidth: 1,
10064 margin: 1,
10065 padding: 1
10066 };
10067
10068 $.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) {
10069 $.fx.step[ prop ] = function( fx ) {
10070 if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
10071 jQuery.style( fx.elem, prop, fx.end );
10072 fx.setAttr = true;
10073 }
10074 };
10075 });
10076
10077 function getElementStyles( elem ) {
10078 var key, len,
10079 style = elem.ownerDocument.defaultView ?
10080 elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
10081 elem.currentStyle,
10082 styles = {};
10083
10084 if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
10085 len = style.length;
10086 while ( len-- ) {
10087 key = style[ len ];
10088 if ( typeof style[ key ] === "string" ) {
10089 styles[ $.camelCase( key ) ] = style[ key ];
10090 }
10091 }
10092 // support: Opera, IE <9
10093 } else {
10094 for ( key in style ) {
10095 if ( typeof style[ key ] === "string" ) {
10096 styles[ key ] = style[ key ];
10097 }
10098 }
10099 }
10100
10101 return styles;
10102 }
10103
10104 function styleDifference( oldStyle, newStyle ) {
10105 var diff = {},
10106 name, value;
10107
10108 for ( name in newStyle ) {
10109 value = newStyle[ name ];
10110 if ( oldStyle[ name ] !== value ) {
10111 if ( !shorthandStyles[ name ] ) {
10112 if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
10113 diff[ name ] = value;
10114 }
10115 }
10116 }
10117 }
10118
10119 return diff;
10120 }
10121
10122 // support: jQuery <1.8
10123 if ( !$.fn.addBack ) {
10124 $.fn.addBack = function( selector ) {
10125 return this.add( selector == null ?
10126 this.prevObject : this.prevObject.filter( selector )
10127 );
10128 };
10129 }
10130
10131 $.effects.animateClass = function( value, duration, easing, callback ) {
10132 var o = $.speed( duration, easing, callback );
10133
10134 return this.queue( function() {
10135 var animated = $( this ),
10136 baseClass = animated.attr( "class" ) || "",
10137 applyClassChange,
10138 allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
10139
10140 // map the animated objects to store the original styles.
10141 allAnimations = allAnimations.map(function() {
10142 var el = $( this );
10143 return {
10144 el: el,
10145 start: getElementStyles( this )
10146 };
10147 });
10148
10149 // apply class change
10150 applyClassChange = function() {
10151 $.each( classAnimationActions, function(i, action) {
10152 if ( value[ action ] ) {
10153 animated[ action + "Class" ]( value[ action ] );
10154 }
10155 });
10156 };
10157 applyClassChange();
10158
10159 // map all animated objects again - calculate new styles and diff
10160 allAnimations = allAnimations.map(function() {
10161 this.end = getElementStyles( this.el[ 0 ] );
10162 this.diff = styleDifference( this.start, this.end );
10163 return this;
10164 });
10165
10166 // apply original class
10167 animated.attr( "class", baseClass );
10168
10169 // map all animated objects again - this time collecting a promise
10170 allAnimations = allAnimations.map(function() {
10171 var styleInfo = this,
10172 dfd = $.Deferred(),
10173 opts = $.extend({}, o, {
10174 queue: false,
10175 complete: function() {
10176 dfd.resolve( styleInfo );
10177 }
10178 });
10179
10180 this.el.animate( this.diff, opts );
10181 return dfd.promise();
10182 });
10183
10184 // once all animations have completed:
10185 $.when.apply( $, allAnimations.get() ).done(function() {
10186
10187 // set the final class
10188 applyClassChange();
10189
10190 // for each animated element,
10191 // clear all css properties that were animated
10192 $.each( arguments, function() {
10193 var el = this.el;
10194 $.each( this.diff, function(key) {
10195 el.css( key, "" );
10196 });
10197 });
10198
10199 // this is guarnteed to be there if you use jQuery.speed()
10200 // it also handles dequeuing the next anim...
10201 o.complete.call( animated[ 0 ] );
10202 });
10203 });
10204 };
10205
10206 $.fn.extend({
10207 addClass: (function( orig ) {
10208 return function( classNames, speed, easing, callback ) {
10209 return speed ?
10210 $.effects.animateClass.call( this,
10211 { add: classNames }, speed, easing, callback ) :
10212 orig.apply( this, arguments );
10213 };
10214 })( $.fn.addClass ),
10215
10216 removeClass: (function( orig ) {
10217 return function( classNames, speed, easing, callback ) {
10218 return arguments.length > 1 ?
10219 $.effects.animateClass.call( this,
10220 { remove: classNames }, speed, easing, callback ) :
10221 orig.apply( this, arguments );
10222 };
10223 })( $.fn.removeClass ),
10224
10225 toggleClass: (function( orig ) {
10226 return function( classNames, force, speed, easing, callback ) {
10227 if ( typeof force === "boolean" || force === undefined ) {
10228 if ( !speed ) {
10229 // without speed parameter
10230 return orig.apply( this, arguments );
10231 } else {
10232 return $.effects.animateClass.call( this,
10233 (force ? { add: classNames } : { remove: classNames }),
10234 speed, easing, callback );
10235 }
10236 } else {
10237 // without force parameter
10238 return $.effects.animateClass.call( this,
10239 { toggle: classNames }, force, speed, easing );
10240 }
10241 };
10242 })( $.fn.toggleClass ),
10243
10244 switchClass: function( remove, add, speed, easing, callback) {
10245 return $.effects.animateClass.call( this, {
10246 add: add,
10247 remove: remove
10248 }, speed, easing, callback );
10249 }
10250 });
10251
10252 })();
10253
10254 /******************************************************************************/
10255 /*********************************** EFFECTS **********************************/
10256 /******************************************************************************/
10257
10258 (function() {
10259
10260 $.extend( $.effects, {
10261 version: "1.11.4",
10262
10263 // Saves a set of properties in a data storage
10264 save: function( element, set ) {
10265 for ( var i = 0; i < set.length; i++ ) {
10266 if ( set[ i ] !== null ) {
10267 element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
10268 }
10269 }
10270 },
10271
10272 // Restores a set of previously saved properties from a data storage
10273 restore: function( element, set ) {
10274 var val, i;
10275 for ( i = 0; i < set.length; i++ ) {
10276 if ( set[ i ] !== null ) {
10277 val = element.data( dataSpace + set[ i ] );
10278 // support: jQuery 1.6.2
10279 // http://bugs.jquery.com/ticket/9917
10280 // jQuery 1.6.2 incorrectly returns undefined for any falsy value.
10281 // We can't differentiate between "" and 0 here, so we just assume
10282 // empty string since it's likely to be a more common value...
10283 if ( val === undefined ) {
10284 val = "";
10285 }
10286 element.css( set[ i ], val );
10287 }
10288 }
10289 },
10290
10291 setMode: function( el, mode ) {
10292 if (mode === "toggle") {
10293 mode = el.is( ":hidden" ) ? "show" : "hide";
10294 }
10295 return mode;
10296 },
10297
10298 // Translates a [top,left] array into a baseline value
10299 // this should be a little more flexible in the future to handle a string & hash
10300 getBaseline: function( origin, original ) {
10301 var y, x;
10302 switch ( origin[ 0 ] ) {
10303 case "top": y = 0; break;
10304 case "middle": y = 0.5; break;
10305 case "bottom": y = 1; break;
10306 default: y = origin[ 0 ] / original.height;
10307 }
10308 switch ( origin[ 1 ] ) {
10309 case "left": x = 0; break;
10310 case "center": x = 0.5; break;
10311 case "right": x = 1; break;
10312 default: x = origin[ 1 ] / original.width;
10313 }
10314 return {
10315 x: x,
10316 y: y
10317 };
10318 },
10319
10320 // Wraps the element around a wrapper that copies position properties
10321 createWrapper: function( element ) {
10322
10323 // if the element is already wrapped, return it
10324 if ( element.parent().is( ".ui-effects-wrapper" )) {
10325 return element.parent();
10326 }
10327
10328 // wrap the element
10329 var props = {
10330 width: element.outerWidth(true),
10331 height: element.outerHeight(true),
10332 "float": element.css( "float" )
10333 },
10334 wrapper = $( "<div></div>" )
10335 .addClass( "ui-effects-wrapper" )
10336 .css({
10337 fontSize: "100%",
10338 background: "transparent",
10339 border: "none",
10340 margin: 0,
10341 padding: 0
10342 }),
10343 // Store the size in case width/height are defined in % - Fixes #5245
10344 size = {
10345 width: element.width(),
10346 height: element.height()
10347 },
10348 active = document.activeElement;
10349
10350 // support: Firefox
10351 // Firefox incorrectly exposes anonymous content
10352 // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
10353 try {
10354 active.id;
10355 } catch ( e ) {
10356 active = document.body;
10357 }
10358
10359 element.wrap( wrapper );
10360
10361 // Fixes #7595 - Elements lose focus when wrapped.
10362 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
10363 $( active ).focus();
10364 }
10365
10366 wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element
10367
10368 // transfer positioning properties to the wrapper
10369 if ( element.css( "position" ) === "static" ) {
10370 wrapper.css({ position: "relative" });
10371 element.css({ position: "relative" });
10372 } else {
10373 $.extend( props, {
10374 position: element.css( "position" ),
10375 zIndex: element.css( "z-index" )
10376 });
10377 $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
10378 props[ pos ] = element.css( pos );
10379 if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
10380 props[ pos ] = "auto";
10381 }
10382 });
10383 element.css({
10384 position: "relative",
10385 top: 0,
10386 left: 0,
10387 right: "auto",
10388 bottom: "auto"
10389 });
10390 }
10391 element.css(size);
10392
10393 return wrapper.css( props ).show();
10394 },
10395
10396 removeWrapper: function( element ) {
10397 var active = document.activeElement;
10398
10399 if ( element.parent().is( ".ui-effects-wrapper" ) ) {
10400 element.parent().replaceWith( element );
10401
10402 // Fixes #7595 - Elements lose focus when wrapped.
10403 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
10404 $( active ).focus();
10405 }
10406 }
10407
10408 return element;
10409 },
10410
10411 setTransition: function( element, list, factor, value ) {
10412 value = value || {};
10413 $.each( list, function( i, x ) {
10414 var unit = element.cssUnit( x );
10415 if ( unit[ 0 ] > 0 ) {
10416 value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
10417 }
10418 });
10419 return value;
10420 }
10421 });
10422
10423 // return an effect options object for the given parameters:
10424 function _normalizeArguments( effect, options, speed, callback ) {
10425
10426 // allow passing all options as the first parameter
10427 if ( $.isPlainObject( effect ) ) {
10428 options = effect;
10429 effect = effect.effect;
10430 }
10431
10432 // convert to an object
10433 effect = { effect: effect };
10434
10435 // catch (effect, null, ...)
10436 if ( options == null ) {
10437 options = {};
10438 }
10439
10440 // catch (effect, callback)
10441 if ( $.isFunction( options ) ) {
10442 callback = options;
10443 speed = null;
10444 options = {};
10445 }
10446
10447 // catch (effect, speed, ?)
10448 if ( typeof options === "number" || $.fx.speeds[ options ] ) {
10449 callback = speed;
10450 speed = options;
10451 options = {};
10452 }
10453
10454 // catch (effect, options, callback)
10455 if ( $.isFunction( speed ) ) {
10456 callback = speed;
10457 speed = null;
10458 }
10459
10460 // add options to effect
10461 if ( options ) {
10462 $.extend( effect, options );
10463 }
10464
10465 speed = speed || options.duration;
10466 effect.duration = $.fx.off ? 0 :
10467 typeof speed === "number" ? speed :
10468 speed in $.fx.speeds ? $.fx.speeds[ speed ] :
10469 $.fx.speeds._default;
10470
10471 effect.complete = callback || options.complete;
10472
10473 return effect;
10474 }
10475
10476 function standardAnimationOption( option ) {
10477 // Valid standard speeds (nothing, number, named speed)
10478 if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
10479 return true;
10480 }
10481
10482 // Invalid strings - treat as "normal" speed
10483 if ( typeof option === "string" && !$.effects.effect[ option ] ) {
10484 return true;
10485 }
10486
10487 // Complete callback
10488 if ( $.isFunction( option ) ) {
10489 return true;
10490 }
10491
10492 // Options hash (but not naming an effect)
10493 if ( typeof option === "object" && !option.effect ) {
10494 return true;
10495 }
10496
10497 // Didn't match any standard API
10498 return false;
10499 }
10500
10501 $.fn.extend({
10502 effect: function( /* effect, options, speed, callback */ ) {
10503 var args = _normalizeArguments.apply( this, arguments ),
10504 mode = args.mode,
10505 queue = args.queue,
10506 effectMethod = $.effects.effect[ args.effect ];
10507
10508 if ( $.fx.off || !effectMethod ) {
10509 // delegate to the original method (e.g., .show()) if possible
10510 if ( mode ) {
10511 return this[ mode ]( args.duration, args.complete );
10512 } else {
10513 return this.each( function() {
10514 if ( args.complete ) {
10515 args.complete.call( this );
10516 }
10517 });
10518 }
10519 }
10520
10521 function run( next ) {
10522 var elem = $( this ),
10523 complete = args.complete,
10524 mode = args.mode;
10525
10526 function done() {
10527 if ( $.isFunction( complete ) ) {
10528 complete.call( elem[0] );
10529 }
10530 if ( $.isFunction( next ) ) {
10531 next();
10532 }
10533 }
10534
10535 // If the element already has the correct final state, delegate to
10536 // the core methods so the internal tracking of "olddisplay" works.
10537 if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
10538 elem[ mode ]();
10539 done();
10540 } else {
10541 effectMethod.call( elem[0], args, done );
10542 }
10543 }
10544
10545 return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
10546 },
10547
10548 show: (function( orig ) {
10549 return function( option ) {
10550 if ( standardAnimationOption( option ) ) {
10551 return orig.apply( this, arguments );
10552 } else {
10553 var args = _normalizeArguments.apply( this, arguments );
10554 args.mode = "show";
10555 return this.effect.call( this, args );
10556 }
10557 };
10558 })( $.fn.show ),
10559
10560 hide: (function( orig ) {
10561 return function( option ) {
10562 if ( standardAnimationOption( option ) ) {
10563 return orig.apply( this, arguments );
10564 } else {
10565 var args = _normalizeArguments.apply( this, arguments );
10566 args.mode = "hide";
10567 return this.effect.call( this, args );
10568 }
10569 };
10570 })( $.fn.hide ),
10571
10572 toggle: (function( orig ) {
10573 return function( option ) {
10574 if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
10575 return orig.apply( this, arguments );
10576 } else {
10577 var args = _normalizeArguments.apply( this, arguments );
10578 args.mode = "toggle";
10579 return this.effect.call( this, args );
10580 }
10581 };
10582 })( $.fn.toggle ),
10583
10584 // helper functions
10585 cssUnit: function(key) {
10586 var style = this.css( key ),
10587 val = [];
10588
10589 $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
10590 if ( style.indexOf( unit ) > 0 ) {
10591 val = [ parseFloat( style ), unit ];
10592 }
10593 });
10594 return val;
10595 }
10596 });
10597
10598 })();
10599
10600 /******************************************************************************/
10601 /*********************************** EASING ***********************************/
10602 /******************************************************************************/
10603
10604 (function() {
10605
10606 // based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
10607
10608 var baseEasings = {};
10609
10610 $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
10611 baseEasings[ name ] = function( p ) {
10612 return Math.pow( p, i + 2 );
10613 };
10614 });
10615
10616 $.extend( baseEasings, {
10617 Sine: function( p ) {
10618 return 1 - Math.cos( p * Math.PI / 2 );
10619 },
10620 Circ: function( p ) {
10621 return 1 - Math.sqrt( 1 - p * p );
10622 },
10623 Elastic: function( p ) {
10624 return p === 0 || p === 1 ? p :
10625 -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 );
10626 },
10627 Back: function( p ) {
10628 return p * p * ( 3 * p - 2 );
10629 },
10630 Bounce: function( p ) {
10631 var pow2,
10632 bounce = 4;
10633
10634 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
10635 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
10636 }
10637 });
10638
10639 $.each( baseEasings, function( name, easeIn ) {
10640 $.easing[ "easeIn" + name ] = easeIn;
10641 $.easing[ "easeOut" + name ] = function( p ) {
10642 return 1 - easeIn( 1 - p );
10643 };
10644 $.easing[ "easeInOut" + name ] = function( p ) {
10645 return p < 0.5 ?
10646 easeIn( p * 2 ) / 2 :
10647 1 - easeIn( p * -2 + 2 ) / 2;
10648 };
10649 });
10650
10651 })();
10652
10653 var effect = $.effects;
10654
10655
10656 /*!
10657 * jQuery UI Effects Blind 1.11.4
10658 * http://jqueryui.com
10659 *
10660 * Copyright jQuery Foundation and other contributors
10661 * Released under the MIT license.
10662 * http://jquery.org/license
10663 *
10664 * http://api.jqueryui.com/blind-effect/
10665 */
10666
10667
10668 var effectBlind = $.effects.effect.blind = function( o, done ) {
10669 // Create element
10670 var el = $( this ),
10671 rvertical = /up|down|vertical/,
10672 rpositivemotion = /up|left|vertical|horizontal/,
10673 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10674 mode = $.effects.setMode( el, o.mode || "hide" ),
10675 direction = o.direction || "up",
10676 vertical = rvertical.test( direction ),
10677 ref = vertical ? "height" : "width",
10678 ref2 = vertical ? "top" : "left",
10679 motion = rpositivemotion.test( direction ),
10680 animation = {},
10681 show = mode === "show",
10682 wrapper, distance, margin;
10683
10684 // if already wrapped, the wrapper's properties are my property. #6245
10685 if ( el.parent().is( ".ui-effects-wrapper" ) ) {
10686 $.effects.save( el.parent(), props );
10687 } else {
10688 $.effects.save( el, props );
10689 }
10690 el.show();
10691 wrapper = $.effects.createWrapper( el ).css({
10692 overflow: "hidden"
10693 });
10694
10695 distance = wrapper[ ref ]();
10696 margin = parseFloat( wrapper.css( ref2 ) ) || 0;
10697
10698 animation[ ref ] = show ? distance : 0;
10699 if ( !motion ) {
10700 el
10701 .css( vertical ? "bottom" : "right", 0 )
10702 .css( vertical ? "top" : "left", "auto" )
10703 .css({ position: "absolute" });
10704
10705 animation[ ref2 ] = show ? margin : distance + margin;
10706 }
10707
10708 // start at 0 if we are showing
10709 if ( show ) {
10710 wrapper.css( ref, 0 );
10711 if ( !motion ) {
10712 wrapper.css( ref2, margin + distance );
10713 }
10714 }
10715
10716 // Animate
10717 wrapper.animate( animation, {
10718 duration: o.duration,
10719 easing: o.easing,
10720 queue: false,
10721 complete: function() {
10722 if ( mode === "hide" ) {
10723 el.hide();
10724 }
10725 $.effects.restore( el, props );
10726 $.effects.removeWrapper( el );
10727 done();
10728 }
10729 });
10730 };
10731
10732
10733 /*!
10734 * jQuery UI Effects Bounce 1.11.4
10735 * http://jqueryui.com
10736 *
10737 * Copyright jQuery Foundation and other contributors
10738 * Released under the MIT license.
10739 * http://jquery.org/license
10740 *
10741 * http://api.jqueryui.com/bounce-effect/
10742 */
10743
10744
10745 var effectBounce = $.effects.effect.bounce = function( o, done ) {
10746 var el = $( this ),
10747 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10748
10749 // defaults:
10750 mode = $.effects.setMode( el, o.mode || "effect" ),
10751 hide = mode === "hide",
10752 show = mode === "show",
10753 direction = o.direction || "up",
10754 distance = o.distance,
10755 times = o.times || 5,
10756
10757 // number of internal animations
10758 anims = times * 2 + ( show || hide ? 1 : 0 ),
10759 speed = o.duration / anims,
10760 easing = o.easing,
10761
10762 // utility:
10763 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
10764 motion = ( direction === "up" || direction === "left" ),
10765 i,
10766 upAnim,
10767 downAnim,
10768
10769 // we will need to re-assemble the queue to stack our animations in place
10770 queue = el.queue(),
10771 queuelen = queue.length;
10772
10773 // Avoid touching opacity to prevent clearType and PNG issues in IE
10774 if ( show || hide ) {
10775 props.push( "opacity" );
10776 }
10777
10778 $.effects.save( el, props );
10779 el.show();
10780 $.effects.createWrapper( el ); // Create Wrapper
10781
10782 // default distance for the BIGGEST bounce is the outer Distance / 3
10783 if ( !distance ) {
10784 distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
10785 }
10786
10787 if ( show ) {
10788 downAnim = { opacity: 1 };
10789 downAnim[ ref ] = 0;
10790
10791 // if we are showing, force opacity 0 and set the initial position
10792 // then do the "first" animation
10793 el.css( "opacity", 0 )
10794 .css( ref, motion ? -distance * 2 : distance * 2 )
10795 .animate( downAnim, speed, easing );
10796 }
10797
10798 // start at the smallest distance if we are hiding
10799 if ( hide ) {
10800 distance = distance / Math.pow( 2, times - 1 );
10801 }
10802
10803 downAnim = {};
10804 downAnim[ ref ] = 0;
10805 // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
10806 for ( i = 0; i < times; i++ ) {
10807 upAnim = {};
10808 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
10809
10810 el.animate( upAnim, speed, easing )
10811 .animate( downAnim, speed, easing );
10812
10813 distance = hide ? distance * 2 : distance / 2;
10814 }
10815
10816 // Last Bounce when Hiding
10817 if ( hide ) {
10818 upAnim = { opacity: 0 };
10819 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
10820
10821 el.animate( upAnim, speed, easing );
10822 }
10823
10824 el.queue(function() {
10825 if ( hide ) {
10826 el.hide();
10827 }
10828 $.effects.restore( el, props );
10829 $.effects.removeWrapper( el );
10830 done();
10831 });
10832
10833 // inject all the animations we just queued to be first in line (after "inprogress")
10834 if ( queuelen > 1) {
10835 queue.splice.apply( queue,
10836 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
10837 }
10838 el.dequeue();
10839
10840 };
10841
10842
10843 /*!
10844 * jQuery UI Effects Clip 1.11.4
10845 * http://jqueryui.com
10846 *
10847 * Copyright jQuery Foundation and other contributors
10848 * Released under the MIT license.
10849 * http://jquery.org/license
10850 *
10851 * http://api.jqueryui.com/clip-effect/
10852 */
10853
10854
10855 var effectClip = $.effects.effect.clip = function( o, done ) {
10856 // Create element
10857 var el = $( this ),
10858 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10859 mode = $.effects.setMode( el, o.mode || "hide" ),
10860 show = mode === "show",
10861 direction = o.direction || "vertical",
10862 vert = direction === "vertical",
10863 size = vert ? "height" : "width",
10864 position = vert ? "top" : "left",
10865 animation = {},
10866 wrapper, animate, distance;
10867
10868 // Save & Show
10869 $.effects.save( el, props );
10870 el.show();
10871
10872 // Create Wrapper
10873 wrapper = $.effects.createWrapper( el ).css({
10874 overflow: "hidden"
10875 });
10876 animate = ( el[0].tagName === "IMG" ) ? wrapper : el;
10877 distance = animate[ size ]();
10878
10879 // Shift
10880 if ( show ) {
10881 animate.css( size, 0 );
10882 animate.css( position, distance / 2 );
10883 }
10884
10885 // Create Animation Object:
10886 animation[ size ] = show ? distance : 0;
10887 animation[ position ] = show ? 0 : distance / 2;
10888
10889 // Animate
10890 animate.animate( animation, {
10891 queue: false,
10892 duration: o.duration,
10893 easing: o.easing,
10894 complete: function() {
10895 if ( !show ) {
10896 el.hide();
10897 }
10898 $.effects.restore( el, props );
10899 $.effects.removeWrapper( el );
10900 done();
10901 }
10902 });
10903
10904 };
10905
10906
10907 /*!
10908 * jQuery UI Effects Drop 1.11.4
10909 * http://jqueryui.com
10910 *
10911 * Copyright jQuery Foundation and other contributors
10912 * Released under the MIT license.
10913 * http://jquery.org/license
10914 *
10915 * http://api.jqueryui.com/drop-effect/
10916 */
10917
10918
10919 var effectDrop = $.effects.effect.drop = function( o, done ) {
10920
10921 var el = $( this ),
10922 props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
10923 mode = $.effects.setMode( el, o.mode || "hide" ),
10924 show = mode === "show",
10925 direction = o.direction || "left",
10926 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
10927 motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
10928 animation = {
10929 opacity: show ? 1 : 0
10930 },
10931 distance;
10932
10933 // Adjust
10934 $.effects.save( el, props );
10935 el.show();
10936 $.effects.createWrapper( el );
10937
10938 distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2;
10939
10940 if ( show ) {
10941 el
10942 .css( "opacity", 0 )
10943 .css( ref, motion === "pos" ? -distance : distance );
10944 }
10945
10946 // Animation
10947 animation[ ref ] = ( show ?
10948 ( motion === "pos" ? "+=" : "-=" ) :
10949 ( motion === "pos" ? "-=" : "+=" ) ) +
10950 distance;
10951
10952 // Animate
10953 el.animate( animation, {
10954 queue: false,
10955 duration: o.duration,
10956 easing: o.easing,
10957 complete: function() {
10958 if ( mode === "hide" ) {
10959 el.hide();
10960 }
10961 $.effects.restore( el, props );
10962 $.effects.removeWrapper( el );
10963 done();
10964 }
10965 });
10966 };
10967
10968
10969 /*!
10970 * jQuery UI Effects Explode 1.11.4
10971 * http://jqueryui.com
10972 *
10973 * Copyright jQuery Foundation and other contributors
10974 * Released under the MIT license.
10975 * http://jquery.org/license
10976 *
10977 * http://api.jqueryui.com/explode-effect/
10978 */
10979
10980
10981 var effectExplode = $.effects.effect.explode = function( o, done ) {
10982
10983 var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3,
10984 cells = rows,
10985 el = $( this ),
10986 mode = $.effects.setMode( el, o.mode || "hide" ),
10987 show = mode === "show",
10988
10989 // show and then visibility:hidden the element before calculating offset
10990 offset = el.show().css( "visibility", "hidden" ).offset(),
10991
10992 // width and height of a piece
10993 width = Math.ceil( el.outerWidth() / cells ),
10994 height = Math.ceil( el.outerHeight() / rows ),
10995 pieces = [],
10996
10997 // loop
10998 i, j, left, top, mx, my;
10999
11000 // children animate complete:
11001 function childComplete() {
11002 pieces.push( this );
11003 if ( pieces.length === rows * cells ) {
11004 animComplete();
11005 }
11006 }
11007
11008 // clone the element for each row and cell.
11009 for ( i = 0; i < rows ; i++ ) { // ===>
11010 top = offset.top + i * height;
11011 my = i - ( rows - 1 ) / 2 ;
11012
11013 for ( j = 0; j < cells ; j++ ) { // |||
11014 left = offset.left + j * width;
11015 mx = j - ( cells - 1 ) / 2 ;
11016
11017 // Create a clone of the now hidden main element that will be absolute positioned
11018 // within a wrapper div off the -left and -top equal to size of our pieces
11019 el
11020 .clone()
11021 .appendTo( "body" )
11022 .wrap( "<div></div>" )
11023 .css({
11024 position: "absolute",
11025 visibility: "visible",
11026 left: -j * width,
11027 top: -i * height
11028 })
11029
11030 // select the wrapper - make it overflow: hidden and absolute positioned based on
11031 // where the original was located +left and +top equal to the size of pieces
11032 .parent()
11033 .addClass( "ui-effects-explode" )
11034 .css({
11035 position: "absolute",
11036 overflow: "hidden",
11037 width: width,
11038 height: height,
11039 left: left + ( show ? mx * width : 0 ),
11040 top: top + ( show ? my * height : 0 ),
11041 opacity: show ? 0 : 1
11042 }).animate({
11043 left: left + ( show ? 0 : mx * width ),
11044 top: top + ( show ? 0 : my * height ),
11045 opacity: show ? 1 : 0
11046 }, o.duration || 500, o.easing, childComplete );
11047 }
11048 }
11049
11050 function animComplete() {
11051 el.css({
11052 visibility: "visible"
11053 });
11054 $( pieces ).remove();
11055 if ( !show ) {
11056 el.hide();
11057 }
11058 done();
11059 }
11060 };
11061
11062
11063 /*!
11064 * jQuery UI Effects Fade 1.11.4
11065 * http://jqueryui.com
11066 *
11067 * Copyright jQuery Foundation and other contributors
11068 * Released under the MIT license.
11069 * http://jquery.org/license
11070 *
11071 * http://api.jqueryui.com/fade-effect/
11072 */
11073
11074
11075 var effectFade = $.effects.effect.fade = function( o, done ) {
11076 var el = $( this ),
11077 mode = $.effects.setMode( el, o.mode || "toggle" );
11078
11079 el.animate({
11080 opacity: mode
11081 }, {
11082 queue: false,
11083 duration: o.duration,
11084 easing: o.easing,
11085 complete: done
11086 });
11087 };
11088
11089
11090 /*!
11091 * jQuery UI Effects Fold 1.11.4
11092 * http://jqueryui.com
11093 *
11094 * Copyright jQuery Foundation and other contributors
11095 * Released under the MIT license.
11096 * http://jquery.org/license
11097 *
11098 * http://api.jqueryui.com/fold-effect/
11099 */
11100
11101
11102 var effectFold = $.effects.effect.fold = function( o, done ) {
11103
11104 // Create element
11105 var el = $( this ),
11106 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
11107 mode = $.effects.setMode( el, o.mode || "hide" ),
11108 show = mode === "show",
11109 hide = mode === "hide",
11110 size = o.size || 15,
11111 percent = /([0-9]+)%/.exec( size ),
11112 horizFirst = !!o.horizFirst,
11113 widthFirst = show !== horizFirst,
11114 ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ],
11115 duration = o.duration / 2,
11116 wrapper, distance,
11117 animation1 = {},
11118 animation2 = {};
11119
11120 $.effects.save( el, props );
11121 el.show();
11122
11123 // Create Wrapper
11124 wrapper = $.effects.createWrapper( el ).css({
11125 overflow: "hidden"
11126 });
11127 distance = widthFirst ?
11128 [ wrapper.width(), wrapper.height() ] :
11129 [ wrapper.height(), wrapper.width() ];
11130
11131 if ( percent ) {
11132 size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
11133 }
11134 if ( show ) {
11135 wrapper.css( horizFirst ? {
11136 height: 0,
11137 width: size
11138 } : {
11139 height: size,
11140 width: 0
11141 });
11142 }
11143
11144 // Animation
11145 animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size;
11146 animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0;
11147
11148 // Animate
11149 wrapper
11150 .animate( animation1, duration, o.easing )
11151 .animate( animation2, duration, o.easing, function() {
11152 if ( hide ) {
11153 el.hide();
11154 }
11155 $.effects.restore( el, props );
11156 $.effects.removeWrapper( el );
11157 done();
11158 });
11159
11160 };
11161
11162
11163 /*!
11164 * jQuery UI Effects Highlight 1.11.4
11165 * http://jqueryui.com
11166 *
11167 * Copyright jQuery Foundation and other contributors
11168 * Released under the MIT license.
11169 * http://jquery.org/license
11170 *
11171 * http://api.jqueryui.com/highlight-effect/
11172 */
11173
11174
11175 var effectHighlight = $.effects.effect.highlight = function( o, done ) {
11176 var elem = $( this ),
11177 props = [ "backgroundImage", "backgroundColor", "opacity" ],
11178 mode = $.effects.setMode( elem, o.mode || "show" ),
11179 animation = {
11180 backgroundColor: elem.css( "backgroundColor" )
11181 };
11182
11183 if (mode === "hide") {
11184 animation.opacity = 0;
11185 }
11186
11187 $.effects.save( elem, props );
11188
11189 elem
11190 .show()
11191 .css({
11192 backgroundImage: "none",
11193 backgroundColor: o.color || "#ffff99"
11194 })
11195 .animate( animation, {
11196 queue: false,
11197 duration: o.duration,
11198 easing: o.easing,
11199 complete: function() {
11200 if ( mode === "hide" ) {
11201 elem.hide();
11202 }
11203 $.effects.restore( elem, props );
11204 done();
11205 }
11206 });
11207 };
11208
11209
11210 /*!
11211 * jQuery UI Effects Size 1.11.4
11212 * http://jqueryui.com
11213 *
11214 * Copyright jQuery Foundation and other contributors
11215 * Released under the MIT license.
11216 * http://jquery.org/license
11217 *
11218 * http://api.jqueryui.com/size-effect/
11219 */
11220
11221
11222 var effectSize = $.effects.effect.size = function( o, done ) {
11223
11224 // Create element
11225 var original, baseline, factor,
11226 el = $( this ),
11227 props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ],
11228
11229 // Always restore
11230 props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ],
11231
11232 // Copy for children
11233 props2 = [ "width", "height", "overflow" ],
11234 cProps = [ "fontSize" ],
11235 vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
11236 hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
11237
11238 // Set options
11239 mode = $.effects.setMode( el, o.mode || "effect" ),
11240 restore = o.restore || mode !== "effect",
11241 scale = o.scale || "both",
11242 origin = o.origin || [ "middle", "center" ],
11243 position = el.css( "position" ),
11244 props = restore ? props0 : props1,
11245 zero = {
11246 height: 0,
11247 width: 0,
11248 outerHeight: 0,
11249 outerWidth: 0
11250 };
11251
11252 if ( mode === "show" ) {
11253 el.show();
11254 }
11255 original = {
11256 height: el.height(),
11257 width: el.width(),
11258 outerHeight: el.outerHeight(),
11259 outerWidth: el.outerWidth()
11260 };
11261
11262 if ( o.mode === "toggle" && mode === "show" ) {
11263 el.from = o.to || zero;
11264 el.to = o.from || original;
11265 } else {
11266 el.from = o.from || ( mode === "show" ? zero : original );
11267 el.to = o.to || ( mode === "hide" ? zero : original );
11268 }
11269
11270 // Set scaling factor
11271 factor = {
11272 from: {
11273 y: el.from.height / original.height,
11274 x: el.from.width / original.width
11275 },
11276 to: {
11277 y: el.to.height / original.height,
11278 x: el.to.width / original.width
11279 }
11280 };
11281
11282 // Scale the css box
11283 if ( scale === "box" || scale === "both" ) {
11284
11285 // Vertical props scaling
11286 if ( factor.from.y !== factor.to.y ) {
11287 props = props.concat( vProps );
11288 el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
11289 el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
11290 }
11291
11292 // Horizontal props scaling
11293 if ( factor.from.x !== factor.to.x ) {
11294 props = props.concat( hProps );
11295 el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
11296 el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
11297 }
11298 }
11299
11300 // Scale the content
11301 if ( scale === "content" || scale === "both" ) {
11302
11303 // Vertical props scaling
11304 if ( factor.from.y !== factor.to.y ) {
11305 props = props.concat( cProps ).concat( props2 );
11306 el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
11307 el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
11308 }
11309 }
11310
11311 $.effects.save( el, props );
11312 el.show();
11313 $.effects.createWrapper( el );
11314 el.css( "overflow", "hidden" ).css( el.from );
11315
11316 // Adjust
11317 if (origin) { // Calculate baseline shifts
11318 baseline = $.effects.getBaseline( origin, original );
11319 el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
11320 el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
11321 el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
11322 el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
11323 }
11324 el.css( el.from ); // set top & left
11325
11326 // Animate
11327 if ( scale === "content" || scale === "both" ) { // Scale the children
11328
11329 // Add margins/font-size
11330 vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps);
11331 hProps = hProps.concat([ "marginLeft", "marginRight" ]);
11332 props2 = props0.concat(vProps).concat(hProps);
11333
11334 el.find( "*[width]" ).each( function() {
11335 var child = $( this ),
11336 c_original = {
11337 height: child.height(),
11338 width: child.width(),
11339 outerHeight: child.outerHeight(),
11340 outerWidth: child.outerWidth()
11341 };
11342 if (restore) {
11343 $.effects.save(child, props2);
11344 }
11345
11346 child.from = {
11347 height: c_original.height * factor.from.y,
11348 width: c_original.width * factor.from.x,
11349 outerHeight: c_original.outerHeight * factor.from.y,
11350 outerWidth: c_original.outerWidth * factor.from.x
11351 };
11352 child.to = {
11353 height: c_original.height * factor.to.y,
11354 width: c_original.width * factor.to.x,
11355 outerHeight: c_original.height * factor.to.y,
11356 outerWidth: c_original.width * factor.to.x
11357 };
11358
11359 // Vertical props scaling
11360 if ( factor.from.y !== factor.to.y ) {
11361 child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
11362 child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
11363 }
11364
11365 // Horizontal props scaling
11366 if ( factor.from.x !== factor.to.x ) {
11367 child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
11368 child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
11369 }
11370
11371 // Animate children
11372 child.css( child.from );
11373 child.animate( child.to, o.duration, o.easing, function() {
11374
11375 // Restore children
11376 if ( restore ) {
11377 $.effects.restore( child, props2 );
11378 }
11379 });
11380 });
11381 }
11382
11383 // Animate
11384 el.animate( el.to, {
11385 queue: false,
11386 duration: o.duration,
11387 easing: o.easing,
11388 complete: function() {
11389 if ( el.to.opacity === 0 ) {
11390 el.css( "opacity", el.from.opacity );
11391 }
11392 if ( mode === "hide" ) {
11393 el.hide();
11394 }
11395 $.effects.restore( el, props );
11396 if ( !restore ) {
11397
11398 // we need to calculate our new positioning based on the scaling
11399 if ( position === "static" ) {
11400 el.css({
11401 position: "relative",
11402 top: el.to.top,
11403 left: el.to.left
11404 });
11405 } else {
11406 $.each([ "top", "left" ], function( idx, pos ) {
11407 el.css( pos, function( _, str ) {
11408 var val = parseInt( str, 10 ),
11409 toRef = idx ? el.to.left : el.to.top;
11410
11411 // if original was "auto", recalculate the new value from wrapper
11412 if ( str === "auto" ) {
11413 return toRef + "px";
11414 }
11415
11416 return val + toRef + "px";
11417 });
11418 });
11419 }
11420 }
11421
11422 $.effects.removeWrapper( el );
11423 done();
11424 }
11425 });
11426
11427 };
11428
11429
11430 /*!
11431 * jQuery UI Effects Scale 1.11.4
11432 * http://jqueryui.com
11433 *
11434 * Copyright jQuery Foundation and other contributors
11435 * Released under the MIT license.
11436 * http://jquery.org/license
11437 *
11438 * http://api.jqueryui.com/scale-effect/
11439 */
11440
11441
11442 var effectScale = $.effects.effect.scale = function( o, done ) {
11443
11444 // Create element
11445 var el = $( this ),
11446 options = $.extend( true, {}, o ),
11447 mode = $.effects.setMode( el, o.mode || "effect" ),
11448 percent = parseInt( o.percent, 10 ) ||
11449 ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ),
11450 direction = o.direction || "both",
11451 origin = o.origin,
11452 original = {
11453 height: el.height(),
11454 width: el.width(),
11455 outerHeight: el.outerHeight(),
11456 outerWidth: el.outerWidth()
11457 },
11458 factor = {
11459 y: direction !== "horizontal" ? (percent / 100) : 1,
11460 x: direction !== "vertical" ? (percent / 100) : 1
11461 };
11462
11463 // We are going to pass this effect to the size effect:
11464 options.effect = "size";
11465 options.queue = false;
11466 options.complete = done;
11467
11468 // Set default origin and restore for show/hide
11469 if ( mode !== "effect" ) {
11470 options.origin = origin || [ "middle", "center" ];
11471 options.restore = true;
11472 }
11473
11474 options.from = o.from || ( mode === "show" ? {
11475 height: 0,
11476 width: 0,
11477 outerHeight: 0,
11478 outerWidth: 0
11479 } : original );
11480 options.to = {
11481 height: original.height * factor.y,
11482 width: original.width * factor.x,
11483 outerHeight: original.outerHeight * factor.y,
11484 outerWidth: original.outerWidth * factor.x
11485 };
11486
11487 // Fade option to support puff
11488 if ( options.fade ) {
11489 if ( mode === "show" ) {
11490 options.from.opacity = 0;
11491 options.to.opacity = 1;
11492 }
11493 if ( mode === "hide" ) {
11494 options.from.opacity = 1;
11495 options.to.opacity = 0;
11496 }
11497 }
11498
11499 // Animate
11500 el.effect( options );
11501
11502 };
11503
11504
11505 /*!
11506 * jQuery UI Effects Puff 1.11.4
11507 * http://jqueryui.com
11508 *
11509 * Copyright jQuery Foundation and other contributors
11510 * Released under the MIT license.
11511 * http://jquery.org/license
11512 *
11513 * http://api.jqueryui.com/puff-effect/
11514 */
11515
11516
11517 var effectPuff = $.effects.effect.puff = function( o, done ) {
11518 var elem = $( this ),
11519 mode = $.effects.setMode( elem, o.mode || "hide" ),
11520 hide = mode === "hide",
11521 percent = parseInt( o.percent, 10 ) || 150,
11522 factor = percent / 100,
11523 original = {
11524 height: elem.height(),
11525 width: elem.width(),
11526 outerHeight: elem.outerHeight(),
11527 outerWidth: elem.outerWidth()
11528 };
11529
11530 $.extend( o, {
11531 effect: "scale",
11532 queue: false,
11533 fade: true,
11534 mode: mode,
11535 complete: done,
11536 percent: hide ? percent : 100,
11537 from: hide ?
11538 original :
11539 {
11540 height: original.height * factor,
11541 width: original.width * factor,
11542 outerHeight: original.outerHeight * factor,
11543 outerWidth: original.outerWidth * factor
11544 }
11545 });
11546
11547 elem.effect( o );
11548 };
11549
11550
11551 /*!
11552 * jQuery UI Effects Pulsate 1.11.4
11553 * http://jqueryui.com
11554 *
11555 * Copyright jQuery Foundation and other contributors
11556 * Released under the MIT license.
11557 * http://jquery.org/license
11558 *
11559 * http://api.jqueryui.com/pulsate-effect/
11560 */
11561
11562
11563 var effectPulsate = $.effects.effect.pulsate = function( o, done ) {
11564 var elem = $( this ),
11565 mode = $.effects.setMode( elem, o.mode || "show" ),
11566 show = mode === "show",
11567 hide = mode === "hide",
11568 showhide = ( show || mode === "hide" ),
11569
11570 // showing or hiding leaves of the "last" animation
11571 anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
11572 duration = o.duration / anims,
11573 animateTo = 0,
11574 queue = elem.queue(),
11575 queuelen = queue.length,
11576 i;
11577
11578 if ( show || !elem.is(":visible")) {
11579 elem.css( "opacity", 0 ).show();
11580 animateTo = 1;
11581 }
11582
11583 // anims - 1 opacity "toggles"
11584 for ( i = 1; i < anims; i++ ) {
11585 elem.animate({
11586 opacity: animateTo
11587 }, duration, o.easing );
11588 animateTo = 1 - animateTo;
11589 }
11590
11591 elem.animate({
11592 opacity: animateTo
11593 }, duration, o.easing);
11594
11595 elem.queue(function() {
11596 if ( hide ) {
11597 elem.hide();
11598 }
11599 done();
11600 });
11601
11602 // We just queued up "anims" animations, we need to put them next in the queue
11603 if ( queuelen > 1 ) {
11604 queue.splice.apply( queue,
11605 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
11606 }
11607 elem.dequeue();
11608 };
11609
11610
11611 /*!
11612 * jQuery UI Effects Shake 1.11.4
11613 * http://jqueryui.com
11614 *
11615 * Copyright jQuery Foundation and other contributors
11616 * Released under the MIT license.
11617 * http://jquery.org/license
11618 *
11619 * http://api.jqueryui.com/shake-effect/
11620 */
11621
11622
11623 var effectShake = $.effects.effect.shake = function( o, done ) {
11624
11625 var el = $( this ),
11626 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
11627 mode = $.effects.setMode( el, o.mode || "effect" ),
11628 direction = o.direction || "left",
11629 distance = o.distance || 20,
11630 times = o.times || 3,
11631 anims = times * 2 + 1,
11632 speed = Math.round( o.duration / anims ),
11633 ref = (direction === "up" || direction === "down") ? "top" : "left",
11634 positiveMotion = (direction === "up" || direction === "left"),
11635 animation = {},
11636 animation1 = {},
11637 animation2 = {},
11638 i,
11639
11640 // we will need to re-assemble the queue to stack our animations in place
11641 queue = el.queue(),
11642 queuelen = queue.length;
11643
11644 $.effects.save( el, props );
11645 el.show();
11646 $.effects.createWrapper( el );
11647
11648 // Animation
11649 animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
11650 animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
11651 animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
11652
11653 // Animate
11654 el.animate( animation, speed, o.easing );
11655
11656 // Shakes
11657 for ( i = 1; i < times; i++ ) {
11658 el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing );
11659 }
11660 el
11661 .animate( animation1, speed, o.easing )
11662 .animate( animation, speed / 2, o.easing )
11663 .queue(function() {
11664 if ( mode === "hide" ) {
11665 el.hide();
11666 }
11667 $.effects.restore( el, props );
11668 $.effects.removeWrapper( el );
11669 done();
11670 });
11671
11672 // inject all the animations we just queued to be first in line (after "inprogress")
11673 if ( queuelen > 1) {
11674 queue.splice.apply( queue,
11675 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
11676 }
11677 el.dequeue();
11678
11679 };
11680
11681
11682 /*!
11683 * jQuery UI Effects Slide 1.11.4
11684 * http://jqueryui.com
11685 *
11686 * Copyright jQuery Foundation and other contributors
11687 * Released under the MIT license.
11688 * http://jquery.org/license
11689 *
11690 * http://api.jqueryui.com/slide-effect/
11691 */
11692
11693
11694 var effectSlide = $.effects.effect.slide = function( o, done ) {
11695
11696 // Create element
11697 var el = $( this ),
11698 props = [ "position", "top", "bottom", "left", "right", "width", "height" ],
11699 mode = $.effects.setMode( el, o.mode || "show" ),
11700 show = mode === "show",
11701 direction = o.direction || "left",
11702 ref = (direction === "up" || direction === "down") ? "top" : "left",
11703 positiveMotion = (direction === "up" || direction === "left"),
11704 distance,
11705 animation = {};
11706
11707 // Adjust
11708 $.effects.save( el, props );
11709 el.show();
11710 distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true );
11711
11712 $.effects.createWrapper( el ).css({
11713 overflow: "hidden"
11714 });
11715
11716 if ( show ) {
11717 el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance );
11718 }
11719
11720 // Animation
11721 animation[ ref ] = ( show ?
11722 ( positiveMotion ? "+=" : "-=") :
11723 ( positiveMotion ? "-=" : "+=")) +
11724 distance;
11725
11726 // Animate
11727 el.animate( animation, {
11728 queue: false,
11729 duration: o.duration,
11730 easing: o.easing,
11731 complete: function() {
11732 if ( mode === "hide" ) {
11733 el.hide();
11734 }
11735 $.effects.restore( el, props );
11736 $.effects.removeWrapper( el );
11737 done();
11738 }
11739 });
11740 };
11741
11742
11743 /*!
11744 * jQuery UI Effects Transfer 1.11.4
11745 * http://jqueryui.com
11746 *
11747 * Copyright jQuery Foundation and other contributors
11748 * Released under the MIT license.
11749 * http://jquery.org/license
11750 *
11751 * http://api.jqueryui.com/transfer-effect/
11752 */
11753
11754
11755 var effectTransfer = $.effects.effect.transfer = function( o, done ) {
11756 var elem = $( this ),
11757 target = $( o.to ),
11758 targetFixed = target.css( "position" ) === "fixed",
11759 body = $("body"),
11760 fixTop = targetFixed ? body.scrollTop() : 0,
11761 fixLeft = targetFixed ? body.scrollLeft() : 0,
11762 endPosition = target.offset(),
11763 animation = {
11764 top: endPosition.top - fixTop,
11765 left: endPosition.left - fixLeft,
11766 height: target.innerHeight(),
11767 width: target.innerWidth()
11768 },
11769 startPosition = elem.offset(),
11770 transfer = $( "<div class='ui-effects-transfer'></div>" )
11771 .appendTo( document.body )
11772 .addClass( o.className )
11773 .css({
11774 top: startPosition.top - fixTop,
11775 left: startPosition.left - fixLeft,
11776 height: elem.innerHeight(),
11777 width: elem.innerWidth(),
11778 position: targetFixed ? "fixed" : "absolute"
11779 })
11780 .animate( animation, o.duration, o.easing, function() {
11781 transfer.remove();
11782 done();
11783 });
11784 };
11785
11786
11787 /*!
11788 * jQuery UI Progressbar 1.11.4
11789 * http://jqueryui.com
11790 *
11791 * Copyright jQuery Foundation and other contributors
11792 * Released under the MIT license.
11793 * http://jquery.org/license
11794 *
11795 * http://api.jqueryui.com/progressbar/
11796 */
11797
11798
11799 var progressbar = $.widget( "ui.progressbar", {
11800 version: "1.11.4",
11801 options: {
11802 max: 100,
11803 value: 0,
11804
11805 change: null,
11806 complete: null
11807 },
11808
11809 min: 0,
11810
11811 _create: function() {
11812 // Constrain initial value
11813 this.oldValue = this.options.value = this._constrainedValue();
11814
11815 this.element
11816 .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
11817 .attr({
11818 // Only set static values, aria-valuenow and aria-valuemax are
11819 // set inside _refreshValue()
11820 role: "progressbar",
11821 "aria-valuemin": this.min
11822 });
11823
11824 this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
11825 .appendTo( this.element );
11826
11827 this._refreshValue();
11828 },
11829
11830 _destroy: function() {
11831 this.element
11832 .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
11833 .removeAttr( "role" )
11834 .removeAttr( "aria-valuemin" )
11835 .removeAttr( "aria-valuemax" )
11836 .removeAttr( "aria-valuenow" );
11837
11838 this.valueDiv.remove();
11839 },
11840
11841 value: function( newValue ) {
11842 if ( newValue === undefined ) {
11843 return this.options.value;
11844 }
11845
11846 this.options.value = this._constrainedValue( newValue );
11847 this._refreshValue();
11848 },
11849
11850 _constrainedValue: function( newValue ) {
11851 if ( newValue === undefined ) {
11852 newValue = this.options.value;
11853 }
11854
11855 this.indeterminate = newValue === false;
11856
11857 // sanitize value
11858 if ( typeof newValue !== "number" ) {
11859 newValue = 0;
11860 }
11861
11862 return this.indeterminate ? false :
11863 Math.min( this.options.max, Math.max( this.min, newValue ) );
11864 },
11865
11866 _setOptions: function( options ) {
11867 // Ensure "value" option is set after other values (like max)
11868 var value = options.value;
11869 delete options.value;
11870
11871 this._super( options );
11872
11873 this.options.value = this._constrainedValue( value );
11874 this._refreshValue();
11875 },
11876
11877 _setOption: function( key, value ) {
11878 if ( key === "max" ) {
11879 // Don't allow a max less than min
11880 value = Math.max( this.min, value );
11881 }
11882 if ( key === "disabled" ) {
11883 this.element
11884 .toggleClass( "ui-state-disabled", !!value )
11885 .attr( "aria-disabled", value );
11886 }
11887 this._super( key, value );
11888 },
11889
11890 _percentage: function() {
11891 return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
11892 },
11893
11894 _refreshValue: function() {
11895 var value = this.options.value,
11896 percentage = this._percentage();
11897
11898 this.valueDiv
11899 .toggle( this.indeterminate || value > this.min )
11900 .toggleClass( "ui-corner-right", value === this.options.max )
11901 .width( percentage.toFixed(0) + "%" );
11902
11903 this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate );
11904
11905 if ( this.indeterminate ) {
11906 this.element.removeAttr( "aria-valuenow" );
11907 if ( !this.overlayDiv ) {
11908 this.overlayDiv = $( "<div class='ui-progressbar-overlay'></div>" ).appendTo( this.valueDiv );
11909 }
11910 } else {
11911 this.element.attr({
11912 "aria-valuemax": this.options.max,
11913 "aria-valuenow": value
11914 });
11915 if ( this.overlayDiv ) {
11916 this.overlayDiv.remove();
11917 this.overlayDiv = null;
11918 }
11919 }
11920
11921 if ( this.oldValue !== value ) {
11922 this.oldValue = value;
11923 this._trigger( "change" );
11924 }
11925 if ( value === this.options.max ) {
11926 this._trigger( "complete" );
11927 }
11928 }
11929 });
11930
11931
11932 /*!
11933 * jQuery UI Selectable 1.11.4
11934 * http://jqueryui.com
11935 *
11936 * Copyright jQuery Foundation and other contributors
11937 * Released under the MIT license.
11938 * http://jquery.org/license
11939 *
11940 * http://api.jqueryui.com/selectable/
11941 */
11942
11943
11944 var selectable = $.widget("ui.selectable", $.ui.mouse, {
11945 version: "1.11.4",
11946 options: {
11947 appendTo: "body",
11948 autoRefresh: true,
11949 distance: 0,
11950 filter: "*",
11951 tolerance: "touch",
11952
11953 // callbacks
11954 selected: null,
11955 selecting: null,
11956 start: null,
11957 stop: null,
11958 unselected: null,
11959 unselecting: null
11960 },
11961 _create: function() {
11962 var selectees,
11963 that = this;
11964
11965 this.element.addClass("ui-selectable");
11966
11967 this.dragged = false;
11968
11969 // cache selectee children based on filter
11970 this.refresh = function() {
11971 selectees = $(that.options.filter, that.element[0]);
11972 selectees.addClass("ui-selectee");
11973 selectees.each(function() {
11974 var $this = $(this),
11975 pos = $this.offset();
11976 $.data(this, "selectable-item", {
11977 element: this,
11978 $element: $this,
11979 left: pos.left,
11980 top: pos.top,
11981 right: pos.left + $this.outerWidth(),
11982 bottom: pos.top + $this.outerHeight(),
11983 startselected: false,
11984 selected: $this.hasClass("ui-selected"),
11985 selecting: $this.hasClass("ui-selecting"),
11986 unselecting: $this.hasClass("ui-unselecting")
11987 });
11988 });
11989 };
11990 this.refresh();
11991
11992 this.selectees = selectees.addClass("ui-selectee");
11993
11994 this._mouseInit();
11995
11996 this.helper = $("<div class='ui-selectable-helper'></div>");
11997 },
11998
11999 _destroy: function() {
12000 this.selectees
12001 .removeClass("ui-selectee")
12002 .removeData("selectable-item");
12003 this.element
12004 .removeClass("ui-selectable ui-selectable-disabled");
12005 this._mouseDestroy();
12006 },
12007
12008 _mouseStart: function(event) {
12009 var that = this,
12010 options = this.options;
12011
12012 this.opos = [ event.pageX, event.pageY ];
12013
12014 if (this.options.disabled) {
12015 return;
12016 }
12017
12018 this.selectees = $(options.filter, this.element[0]);
12019
12020 this._trigger("start", event);
12021
12022 $(options.appendTo).append(this.helper);
12023 // position helper (lasso)
12024 this.helper.css({
12025 "left": event.pageX,
12026 "top": event.pageY,
12027 "width": 0,
12028 "height": 0
12029 });
12030
12031 if (options.autoRefresh) {
12032 this.refresh();
12033 }
12034
12035 this.selectees.filter(".ui-selected").each(function() {
12036 var selectee = $.data(this, "selectable-item");
12037 selectee.startselected = true;
12038 if (!event.metaKey && !event.ctrlKey) {
12039 selectee.$element.removeClass("ui-selected");
12040 selectee.selected = false;
12041 selectee.$element.addClass("ui-unselecting");
12042 selectee.unselecting = true;
12043 // selectable UNSELECTING callback
12044 that._trigger("unselecting", event, {
12045 unselecting: selectee.element
12046 });
12047 }
12048 });
12049
12050 $(event.target).parents().addBack().each(function() {
12051 var doSelect,
12052 selectee = $.data(this, "selectable-item");
12053 if (selectee) {
12054 doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected");
12055 selectee.$element
12056 .removeClass(doSelect ? "ui-unselecting" : "ui-selected")
12057 .addClass(doSelect ? "ui-selecting" : "ui-unselecting");
12058 selectee.unselecting = !doSelect;
12059 selectee.selecting = doSelect;
12060 selectee.selected = doSelect;
12061 // selectable (UN)SELECTING callback
12062 if (doSelect) {
12063 that._trigger("selecting", event, {
12064 selecting: selectee.element
12065 });
12066 } else {
12067 that._trigger("unselecting", event, {
12068 unselecting: selectee.element
12069 });
12070 }
12071 return false;
12072 }
12073 });
12074
12075 },
12076
12077 _mouseDrag: function(event) {
12078
12079 this.dragged = true;
12080
12081 if (this.options.disabled) {
12082 return;
12083 }
12084
12085 var tmp,
12086 that = this,
12087 options = this.options,
12088 x1 = this.opos[0],
12089 y1 = this.opos[1],
12090 x2 = event.pageX,
12091 y2 = event.pageY;
12092
12093 if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; }
12094 if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; }
12095 this.helper.css({ left: x1, top: y1, width: x2 - x1, height: y2 - y1 });
12096
12097 this.selectees.each(function() {
12098 var selectee = $.data(this, "selectable-item"),
12099 hit = false;
12100
12101 //prevent helper from being selected if appendTo: selectable
12102 if (!selectee || selectee.element === that.element[0]) {
12103 return;
12104 }
12105
12106 if (options.tolerance === "touch") {
12107 hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
12108 } else if (options.tolerance === "fit") {
12109 hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
12110 }
12111
12112 if (hit) {
12113 // SELECT
12114 if (selectee.selected) {
12115 selectee.$element.removeClass("ui-selected");
12116 selectee.selected = false;
12117 }
12118 if (selectee.unselecting) {
12119 selectee.$element.removeClass("ui-unselecting");
12120 selectee.unselecting = false;
12121 }
12122 if (!selectee.selecting) {
12123 selectee.$element.addClass("ui-selecting");
12124 selectee.selecting = true;
12125 // selectable SELECTING callback
12126 that._trigger("selecting", event, {
12127 selecting: selectee.element
12128 });
12129 }
12130 } else {
12131 // UNSELECT
12132 if (selectee.selecting) {
12133 if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
12134 selectee.$element.removeClass("ui-selecting");
12135 selectee.selecting = false;
12136 selectee.$element.addClass("ui-selected");
12137 selectee.selected = true;
12138 } else {
12139 selectee.$element.removeClass("ui-selecting");
12140 selectee.selecting = false;
12141 if (selectee.startselected) {
12142 selectee.$element.addClass("ui-unselecting");
12143 selectee.unselecting = true;
12144 }
12145 // selectable UNSELECTING callback
12146 that._trigger("unselecting", event, {
12147 unselecting: selectee.element
12148 });
12149 }
12150 }
12151 if (selectee.selected) {
12152 if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
12153 selectee.$element.removeClass("ui-selected");
12154 selectee.selected = false;
12155
12156 selectee.$element.addClass("ui-unselecting");
12157 selectee.unselecting = true;
12158 // selectable UNSELECTING callback
12159 that._trigger("unselecting", event, {
12160 unselecting: selectee.element
12161 });
12162 }
12163 }
12164 }
12165 });
12166
12167 return false;
12168 },
12169
12170 _mouseStop: function(event) {
12171 var that = this;
12172
12173 this.dragged = false;
12174
12175 $(".ui-unselecting", this.element[0]).each(function() {
12176 var selectee = $.data(this, "selectable-item");
12177 selectee.$element.removeClass("ui-unselecting");
12178 selectee.unselecting = false;
12179 selectee.startselected = false;
12180 that._trigger("unselected", event, {
12181 unselected: selectee.element
12182 });
12183 });
12184 $(".ui-selecting", this.element[0]).each(function() {
12185 var selectee = $.data(this, "selectable-item");
12186 selectee.$element.removeClass("ui-selecting").addClass("ui-selected");
12187 selectee.selecting = false;
12188 selectee.selected = true;
12189 selectee.startselected = true;
12190 that._trigger("selected", event, {
12191 selected: selectee.element
12192 });
12193 });
12194 this._trigger("stop", event);
12195
12196 this.helper.remove();
12197
12198 return false;
12199 }
12200
12201 });
12202
12203
12204 /*!
12205 * jQuery UI Selectmenu 1.11.4
12206 * http://jqueryui.com
12207 *
12208 * Copyright jQuery Foundation and other contributors
12209 * Released under the MIT license.
12210 * http://jquery.org/license
12211 *
12212 * http://api.jqueryui.com/selectmenu
12213 */
12214
12215
12216 var selectmenu = $.widget( "ui.selectmenu", {
12217 version: "1.11.4",
12218 defaultElement: "<select>",
12219 options: {
12220 appendTo: null,
12221 disabled: null,
12222 icons: {
12223 button: "ui-icon-triangle-1-s"
12224 },
12225 position: {
12226 my: "left top",
12227 at: "left bottom",
12228 collision: "none"
12229 },
12230 width: null,
12231
12232 // callbacks
12233 change: null,
12234 close: null,
12235 focus: null,
12236 open: null,
12237 select: null
12238 },
12239
12240 _create: function() {
12241 var selectmenuId = this.element.uniqueId().attr( "id" );
12242 this.ids = {
12243 element: selectmenuId,
12244 button: selectmenuId + "-button",
12245 menu: selectmenuId + "-menu"
12246 };
12247
12248 this._drawButton();
12249 this._drawMenu();
12250
12251 if ( this.options.disabled ) {
12252 this.disable();
12253 }
12254 },
12255
12256 _drawButton: function() {
12257 var that = this;
12258
12259 // Associate existing label with the new button
12260 this.label = $( "label[for='" + this.ids.element + "']" ).attr( "for", this.ids.button );
12261 this._on( this.label, {
12262 click: function( event ) {
12263 this.button.focus();
12264 event.preventDefault();
12265 }
12266 });
12267
12268 // Hide original select element
12269 this.element.hide();
12270
12271 // Create button
12272 this.button = $( "<span>", {
12273 "class": "ui-selectmenu-button ui-widget ui-state-default ui-corner-all",
12274 tabindex: this.options.disabled ? -1 : 0,
12275 id: this.ids.button,
12276 role: "combobox",
12277 "aria-expanded": "false",
12278 "aria-autocomplete": "list",
12279 "aria-owns": this.ids.menu,
12280 "aria-haspopup": "true"
12281 })
12282 .insertAfter( this.element );
12283
12284 $( "<span>", {
12285 "class": "ui-icon " + this.options.icons.button
12286 })
12287 .prependTo( this.button );
12288
12289 this.buttonText = $( "<span>", {
12290 "class": "ui-selectmenu-text"
12291 })
12292 .appendTo( this.button );
12293
12294 this._setText( this.buttonText, this.element.find( "option:selected" ).text() );
12295 this._resizeButton();
12296
12297 this._on( this.button, this._buttonEvents );
12298 this.button.one( "focusin", function() {
12299
12300 // Delay rendering the menu items until the button receives focus.
12301 // The menu may have already been rendered via a programmatic open.
12302 if ( !that.menuItems ) {
12303 that._refreshMenu();
12304 }
12305 });
12306 this._hoverable( this.button );
12307 this._focusable( this.button );
12308 },
12309
12310 _drawMenu: function() {
12311 var that = this;
12312
12313 // Create menu
12314 this.menu = $( "<ul>", {
12315 "aria-hidden": "true",
12316 "aria-labelledby": this.ids.button,
12317 id: this.ids.menu
12318 });
12319
12320 // Wrap menu
12321 this.menuWrap = $( "<div>", {
12322 "class": "ui-selectmenu-menu ui-front"
12323 })
12324 .append( this.menu )
12325 .appendTo( this._appendTo() );
12326
12327 // Initialize menu widget
12328 this.menuInstance = this.menu
12329 .menu({
12330 role: "listbox",
12331 select: function( event, ui ) {
12332 event.preventDefault();
12333
12334 // support: IE8
12335 // If the item was selected via a click, the text selection
12336 // will be destroyed in IE
12337 that._setSelection();
12338
12339 that._select( ui.item.data( "ui-selectmenu-item" ), event );
12340 },
12341 focus: function( event, ui ) {
12342 var item = ui.item.data( "ui-selectmenu-item" );
12343
12344 // Prevent inital focus from firing and check if its a newly focused item
12345 if ( that.focusIndex != null && item.index !== that.focusIndex ) {
12346 that._trigger( "focus", event, { item: item } );
12347 if ( !that.isOpen ) {
12348 that._select( item, event );
12349 }
12350 }
12351 that.focusIndex = item.index;
12352
12353 that.button.attr( "aria-activedescendant",
12354 that.menuItems.eq( item.index ).attr( "id" ) );
12355 }
12356 })
12357 .menu( "instance" );
12358
12359 // Adjust menu styles to dropdown
12360 this.menu
12361 .addClass( "ui-corner-bottom" )
12362 .removeClass( "ui-corner-all" );
12363
12364 // Don't close the menu on mouseleave
12365 this.menuInstance._off( this.menu, "mouseleave" );
12366
12367 // Cancel the menu's collapseAll on document click
12368 this.menuInstance._closeOnDocumentClick = function() {
12369 return false;
12370 };
12371
12372 // Selects often contain empty items, but never contain dividers
12373 this.menuInstance._isDivider = function() {
12374 return false;
12375 };
12376 },
12377
12378 refresh: function() {
12379 this._refreshMenu();
12380 this._setText( this.buttonText, this._getSelectedItem().text() );
12381 if ( !this.options.width ) {
12382 this._resizeButton();
12383 }
12384 },
12385
12386 _refreshMenu: function() {
12387 this.menu.empty();
12388
12389 var item,
12390 options = this.element.find( "option" );
12391
12392 if ( !options.length ) {
12393 return;
12394 }
12395
12396 this._parseOptions( options );
12397 this._renderMenu( this.menu, this.items );
12398
12399 this.menuInstance.refresh();
12400 this.menuItems = this.menu.find( "li" ).not( ".ui-selectmenu-optgroup" );
12401
12402 item = this._getSelectedItem();
12403
12404 // Update the menu to have the correct item focused
12405 this.menuInstance.focus( null, item );
12406 this._setAria( item.data( "ui-selectmenu-item" ) );
12407
12408 // Set disabled state
12409 this._setOption( "disabled", this.element.prop( "disabled" ) );
12410 },
12411
12412 open: function( event ) {
12413 if ( this.options.disabled ) {
12414 return;
12415 }
12416
12417 // If this is the first time the menu is being opened, render the items
12418 if ( !this.menuItems ) {
12419 this._refreshMenu();
12420 } else {
12421
12422 // Menu clears focus on close, reset focus to selected item
12423 this.menu.find( ".ui-state-focus" ).removeClass( "ui-state-focus" );
12424 this.menuInstance.focus( null, this._getSelectedItem() );
12425 }
12426
12427 this.isOpen = true;
12428 this._toggleAttr();
12429 this._resizeMenu();
12430 this._position();
12431
12432 this._on( this.document, this._documentClick );
12433
12434 this._trigger( "open", event );
12435 },
12436
12437 _position: function() {
12438 this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) );
12439 },
12440
12441 close: function( event ) {
12442 if ( !this.isOpen ) {
12443 return;
12444 }
12445
12446 this.isOpen = false;
12447 this._toggleAttr();
12448
12449 this.range = null;
12450 this._off( this.document );
12451
12452 this._trigger( "close", event );
12453 },
12454
12455 widget: function() {
12456 return this.button;
12457 },
12458
12459 menuWidget: function() {
12460 return this.menu;
12461 },
12462
12463 _renderMenu: function( ul, items ) {
12464 var that = this,
12465 currentOptgroup = "";
12466
12467 $.each( items, function( index, item ) {
12468 if ( item.optgroup !== currentOptgroup ) {
12469 $( "<li>", {
12470 "class": "ui-selectmenu-optgroup ui-menu-divider" +
12471 ( item.element.parent( "optgroup" ).prop( "disabled" ) ?
12472 " ui-state-disabled" :
12473 "" ),
12474 text: item.optgroup
12475 })
12476 .appendTo( ul );
12477
12478 currentOptgroup = item.optgroup;
12479 }
12480
12481 that._renderItemData( ul, item );
12482 });
12483 },
12484
12485 _renderItemData: function( ul, item ) {
12486 return this._renderItem( ul, item ).data( "ui-selectmenu-item", item );
12487 },
12488
12489 _renderItem: function( ul, item ) {
12490 var li = $( "<li>" );
12491
12492 if ( item.disabled ) {
12493 li.addClass( "ui-state-disabled" );
12494 }
12495 this._setText( li, item.label );
12496
12497 return li.appendTo( ul );
12498 },
12499
12500 _setText: function( element, value ) {
12501 if ( value ) {
12502 element.text( value );
12503 } else {
12504 element.html( "&#160;" );
12505 }
12506 },
12507
12508 _move: function( direction, event ) {
12509 var item, next,
12510 filter = ".ui-menu-item";
12511
12512 if ( this.isOpen ) {
12513 item = this.menuItems.eq( this.focusIndex );
12514 } else {
12515 item = this.menuItems.eq( this.element[ 0 ].selectedIndex );
12516 filter += ":not(.ui-state-disabled)";
12517 }
12518
12519 if ( direction === "first" || direction === "last" ) {
12520 next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 );
12521 } else {
12522 next = item[ direction + "All" ]( filter ).eq( 0 );
12523 }
12524
12525 if ( next.length ) {
12526 this.menuInstance.focus( event, next );
12527 }
12528 },
12529
12530 _getSelectedItem: function() {
12531 return this.menuItems.eq( this.element[ 0 ].selectedIndex );
12532 },
12533
12534 _toggle: function( event ) {
12535 this[ this.isOpen ? "close" : "open" ]( event );
12536 },
12537
12538 _setSelection: function() {
12539 var selection;
12540
12541 if ( !this.range ) {
12542 return;
12543 }
12544
12545 if ( window.getSelection ) {
12546 selection = window.getSelection();
12547 selection.removeAllRanges();
12548 selection.addRange( this.range );
12549
12550 // support: IE8
12551 } else {
12552 this.range.select();
12553 }
12554
12555 // support: IE
12556 // Setting the text selection kills the button focus in IE, but
12557 // restoring the focus doesn't kill the selection.
12558 this.button.focus();
12559 },
12560
12561 _documentClick: {
12562 mousedown: function( event ) {
12563 if ( !this.isOpen ) {
12564 return;
12565 }
12566
12567 if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" + this.ids.button ).length ) {
12568 this.close( event );
12569 }
12570 }
12571 },
12572
12573 _buttonEvents: {
12574
12575 // Prevent text selection from being reset when interacting with the selectmenu (#10144)
12576 mousedown: function() {
12577 var selection;
12578
12579 if ( window.getSelection ) {
12580 selection = window.getSelection();
12581 if ( selection.rangeCount ) {
12582 this.range = selection.getRangeAt( 0 );
12583 }
12584
12585 // support: IE8
12586 } else {
12587 this.range = document.selection.createRange();
12588 }
12589 },
12590
12591 click: function( event ) {
12592 this._setSelection();
12593 this._toggle( event );
12594 },
12595
12596 keydown: function( event ) {
12597 var preventDefault = true;
12598 switch ( event.keyCode ) {
12599 case $.ui.keyCode.TAB:
12600 case $.ui.keyCode.ESCAPE:
12601 this.close( event );
12602 preventDefault = false;
12603 break;
12604 case $.ui.keyCode.ENTER:
12605 if ( this.isOpen ) {
12606 this._selectFocusedItem( event );
12607 }
12608 break;
12609 case $.ui.keyCode.UP:
12610 if ( event.altKey ) {
12611 this._toggle( event );
12612 } else {
12613 this._move( "prev", event );
12614 }
12615 break;
12616 case $.ui.keyCode.DOWN:
12617 if ( event.altKey ) {
12618 this._toggle( event );
12619 } else {
12620 this._move( "next", event );
12621 }
12622 break;
12623 case $.ui.keyCode.SPACE:
12624 if ( this.isOpen ) {
12625 this._selectFocusedItem( event );
12626 } else {
12627 this._toggle( event );
12628 }
12629 break;
12630 case $.ui.keyCode.LEFT:
12631 this._move( "prev", event );
12632 break;
12633 case $.ui.keyCode.RIGHT:
12634 this._move( "next", event );
12635 break;
12636 case $.ui.keyCode.HOME:
12637 case $.ui.keyCode.PAGE_UP:
12638 this._move( "first", event );
12639 break;
12640 case $.ui.keyCode.END:
12641 case $.ui.keyCode.PAGE_DOWN:
12642 this._move( "last", event );
12643 break;
12644 default:
12645 this.menu.trigger( event );
12646 preventDefault = false;
12647 }
12648
12649 if ( preventDefault ) {
12650 event.preventDefault();
12651 }
12652 }
12653 },
12654
12655 _selectFocusedItem: function( event ) {
12656 var item = this.menuItems.eq( this.focusIndex );
12657 if ( !item.hasClass( "ui-state-disabled" ) ) {
12658 this._select( item.data( "ui-selectmenu-item" ), event );
12659 }
12660 },
12661
12662 _select: function( item, event ) {
12663 var oldIndex = this.element[ 0 ].selectedIndex;
12664
12665 // Change native select element
12666 this.element[ 0 ].selectedIndex = item.index;
12667 this._setText( this.buttonText, item.label );
12668 this._setAria( item );
12669 this._trigger( "select", event, { item: item } );
12670
12671 if ( item.index !== oldIndex ) {
12672 this._trigger( "change", event, { item: item } );
12673 }
12674
12675 this.close( event );
12676 },
12677
12678 _setAria: function( item ) {
12679 var id = this.menuItems.eq( item.index ).attr( "id" );
12680
12681 this.button.attr({
12682 "aria-labelledby": id,
12683 "aria-activedescendant": id
12684 });
12685 this.menu.attr( "aria-activedescendant", id );
12686 },
12687
12688 _setOption: function( key, value ) {
12689 if ( key === "icons" ) {
12690 this.button.find( "span.ui-icon" )
12691 .removeClass( this.options.icons.button )
12692 .addClass( value.button );
12693 }
12694
12695 this._super( key, value );
12696
12697 if ( key === "appendTo" ) {
12698 this.menuWrap.appendTo( this._appendTo() );
12699 }
12700
12701 if ( key === "disabled" ) {
12702 this.menuInstance.option( "disabled", value );
12703 this.button
12704 .toggleClass( "ui-state-disabled", value )
12705 .attr( "aria-disabled", value );
12706
12707 this.element.prop( "disabled", value );
12708 if ( value ) {
12709 this.button.attr( "tabindex", -1 );
12710 this.close();
12711 } else {
12712 this.button.attr( "tabindex", 0 );
12713 }
12714 }
12715
12716 if ( key === "width" ) {
12717 this._resizeButton();
12718 }
12719 },
12720
12721 _appendTo: function() {
12722 var element = this.options.appendTo;
12723
12724 if ( element ) {
12725 element = element.jquery || element.nodeType ?
12726 $( element ) :
12727 this.document.find( element ).eq( 0 );
12728 }
12729
12730 if ( !element || !element[ 0 ] ) {
12731 element = this.element.closest( ".ui-front" );
12732 }
12733
12734 if ( !element.length ) {
12735 element = this.document[ 0 ].body;
12736 }
12737
12738 return element;
12739 },
12740
12741 _toggleAttr: function() {
12742 this.button
12743 .toggleClass( "ui-corner-top", this.isOpen )
12744 .toggleClass( "ui-corner-all", !this.isOpen )
12745 .attr( "aria-expanded", this.isOpen );
12746 this.menuWrap.toggleClass( "ui-selectmenu-open", this.isOpen );
12747 this.menu.attr( "aria-hidden", !this.isOpen );
12748 },
12749
12750 _resizeButton: function() {
12751 var width = this.options.width;
12752
12753 if ( !width ) {
12754 width = this.element.show().outerWidth();
12755 this.element.hide();
12756 }
12757
12758 this.button.outerWidth( width );
12759 },
12760
12761 _resizeMenu: function() {
12762 this.menu.outerWidth( Math.max(
12763 this.button.outerWidth(),
12764
12765 // support: IE10
12766 // IE10 wraps long text (possibly a rounding bug)
12767 // so we add 1px to avoid the wrapping
12768 this.menu.width( "" ).outerWidth() + 1
12769 ) );
12770 },
12771
12772 _getCreateOptions: function() {
12773 return { disabled: this.element.prop( "disabled" ) };
12774 },
12775
12776 _parseOptions: function( options ) {
12777 var data = [];
12778 options.each(function( index, item ) {
12779 var option = $( item ),
12780 optgroup = option.parent( "optgroup" );
12781 data.push({
12782 element: option,
12783 index: index,
12784 value: option.val(),
12785 label: option.text(),
12786 optgroup: optgroup.attr( "label" ) || "",
12787 disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" )
12788 });
12789 });
12790 this.items = data;
12791 },
12792
12793 _destroy: function() {
12794 this.menuWrap.remove();
12795 this.button.remove();
12796 this.element.show();
12797 this.element.removeUniqueId();
12798 this.label.attr( "for", this.ids.element );
12799 }
12800 });
12801
12802
12803 /*!
12804 * jQuery UI Slider 1.11.4
12805 * http://jqueryui.com
12806 *
12807 * Copyright jQuery Foundation and other contributors
12808 * Released under the MIT license.
12809 * http://jquery.org/license
12810 *
12811 * http://api.jqueryui.com/slider/
12812 */
12813
12814
12815 var slider = $.widget( "ui.slider", $.ui.mouse, {
12816 version: "1.11.4",
12817 widgetEventPrefix: "slide",
12818
12819 options: {
12820 animate: false,
12821 distance: 0,
12822 max: 100,
12823 min: 0,
12824 orientation: "horizontal",
12825 range: false,
12826 step: 1,
12827 value: 0,
12828 values: null,
12829
12830 // callbacks
12831 change: null,
12832 slide: null,
12833 start: null,
12834 stop: null
12835 },
12836
12837 // number of pages in a slider
12838 // (how many times can you page up/down to go through the whole range)
12839 numPages: 5,
12840
12841 _create: function() {
12842 this._keySliding = false;
12843 this._mouseSliding = false;
12844 this._animateOff = true;
12845 this._handleIndex = null;
12846 this._detectOrientation();
12847 this._mouseInit();
12848 this._calculateNewMax();
12849
12850 this.element
12851 .addClass( "ui-slider" +
12852 " ui-slider-" + this.orientation +
12853 " ui-widget" +
12854 " ui-widget-content" +
12855 " ui-corner-all");
12856
12857 this._refresh();
12858 this._setOption( "disabled", this.options.disabled );
12859
12860 this._animateOff = false;
12861 },
12862
12863 _refresh: function() {
12864 this._createRange();
12865 this._createHandles();
12866 this._setupEvents();
12867 this._refreshValue();
12868 },
12869
12870 _createHandles: function() {
12871 var i, handleCount,
12872 options = this.options,
12873 existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
12874 handle = "<span class='ui-slider-handle ui-state-default ui-corner-all' tabindex='0'></span>",
12875 handles = [];
12876
12877 handleCount = ( options.values && options.values.length ) || 1;
12878
12879 if ( existingHandles.length > handleCount ) {
12880 existingHandles.slice( handleCount ).remove();
12881 existingHandles = existingHandles.slice( 0, handleCount );
12882 }
12883
12884 for ( i = existingHandles.length; i < handleCount; i++ ) {
12885 handles.push( handle );
12886 }
12887
12888 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
12889
12890 this.handle = this.handles.eq( 0 );
12891
12892 this.handles.each(function( i ) {
12893 $( this ).data( "ui-slider-handle-index", i );
12894 });
12895 },
12896
12897 _createRange: function() {
12898 var options = this.options,
12899 classes = "";
12900
12901 if ( options.range ) {
12902 if ( options.range === true ) {
12903 if ( !options.values ) {
12904 options.values = [ this._valueMin(), this._valueMin() ];
12905 } else if ( options.values.length && options.values.length !== 2 ) {
12906 options.values = [ options.values[0], options.values[0] ];
12907 } else if ( $.isArray( options.values ) ) {
12908 options.values = options.values.slice(0);
12909 }
12910 }
12911
12912 if ( !this.range || !this.range.length ) {
12913 this.range = $( "<div></div>" )
12914 .appendTo( this.element );
12915
12916 classes = "ui-slider-range" +
12917 // note: this isn't the most fittingly semantic framework class for this element,
12918 // but worked best visually with a variety of themes
12919 " ui-widget-header ui-corner-all";
12920 } else {
12921 this.range.removeClass( "ui-slider-range-min ui-slider-range-max" )
12922 // Handle range switching from true to min/max
12923 .css({
12924 "left": "",
12925 "bottom": ""
12926 });
12927 }
12928
12929 this.range.addClass( classes +
12930 ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) );
12931 } else {
12932 if ( this.range ) {
12933 this.range.remove();
12934 }
12935 this.range = null;
12936 }
12937 },
12938
12939 _setupEvents: function() {
12940 this._off( this.handles );
12941 this._on( this.handles, this._handleEvents );
12942 this._hoverable( this.handles );
12943 this._focusable( this.handles );
12944 },
12945
12946 _destroy: function() {
12947 this.handles.remove();
12948 if ( this.range ) {
12949 this.range.remove();
12950 }
12951
12952 this.element
12953 .removeClass( "ui-slider" +
12954 " ui-slider-horizontal" +
12955 " ui-slider-vertical" +
12956 " ui-widget" +
12957 " ui-widget-content" +
12958 " ui-corner-all" );
12959
12960 this._mouseDestroy();
12961 },
12962
12963 _mouseCapture: function( event ) {
12964 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
12965 that = this,
12966 o = this.options;
12967
12968 if ( o.disabled ) {
12969 return false;
12970 }
12971
12972 this.elementSize = {
12973 width: this.element.outerWidth(),
12974 height: this.element.outerHeight()
12975 };
12976 this.elementOffset = this.element.offset();
12977
12978 position = { x: event.pageX, y: event.pageY };
12979 normValue = this._normValueFromMouse( position );
12980 distance = this._valueMax() - this._valueMin() + 1;
12981 this.handles.each(function( i ) {
12982 var thisDistance = Math.abs( normValue - that.values(i) );
12983 if (( distance > thisDistance ) ||
12984 ( distance === thisDistance &&
12985 (i === that._lastChangedValue || that.values(i) === o.min ))) {
12986 distance = thisDistance;
12987 closestHandle = $( this );
12988 index = i;
12989 }
12990 });
12991
12992 allowed = this._start( event, index );
12993 if ( allowed === false ) {
12994 return false;
12995 }
12996 this._mouseSliding = true;
12997
12998 this._handleIndex = index;
12999
13000 closestHandle
13001 .addClass( "ui-state-active" )
13002 .focus();
13003
13004 offset = closestHandle.offset();
13005 mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
13006 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
13007 left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
13008 top: event.pageY - offset.top -
13009 ( closestHandle.height() / 2 ) -
13010 ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
13011 ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
13012 ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
13013 };
13014
13015 if ( !this.handles.hasClass( "ui-state-hover" ) ) {
13016 this._slide( event, index, normValue );
13017 }
13018 this._animateOff = true;
13019 return true;
13020 },
13021
13022 _mouseStart: function() {
13023 return true;
13024 },
13025
13026 _mouseDrag: function( event ) {
13027 var position = { x: event.pageX, y: event.pageY },
13028 normValue = this._normValueFromMouse( position );
13029
13030 this._slide( event, this._handleIndex, normValue );
13031
13032 return false;
13033 },
13034
13035 _mouseStop: function( event ) {
13036 this.handles.removeClass( "ui-state-active" );
13037 this._mouseSliding = false;
13038
13039 this._stop( event, this._handleIndex );
13040 this._change( event, this._handleIndex );
13041
13042 this._handleIndex = null;
13043 this._clickOffset = null;
13044 this._animateOff = false;
13045
13046 return false;
13047 },
13048
13049 _detectOrientation: function() {
13050 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
13051 },
13052
13053 _normValueFromMouse: function( position ) {
13054 var pixelTotal,
13055 pixelMouse,
13056 percentMouse,
13057 valueTotal,
13058 valueMouse;
13059
13060 if ( this.orientation === "horizontal" ) {
13061 pixelTotal = this.elementSize.width;
13062 pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
13063 } else {
13064 pixelTotal = this.elementSize.height;
13065 pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
13066 }
13067
13068 percentMouse = ( pixelMouse / pixelTotal );
13069 if ( percentMouse > 1 ) {
13070 percentMouse = 1;
13071 }
13072 if ( percentMouse < 0 ) {
13073 percentMouse = 0;
13074 }
13075 if ( this.orientation === "vertical" ) {
13076 percentMouse = 1 - percentMouse;
13077 }
13078
13079 valueTotal = this._valueMax() - this._valueMin();
13080 valueMouse = this._valueMin() + percentMouse * valueTotal;
13081
13082 return this._trimAlignValue( valueMouse );
13083 },
13084
13085 _start: function( event, index ) {
13086 var uiHash = {
13087 handle: this.handles[ index ],
13088 value: this.value()
13089 };
13090 if ( this.options.values && this.options.values.length ) {
13091 uiHash.value = this.values( index );
13092 uiHash.values = this.values();
13093 }
13094 return this._trigger( "start", event, uiHash );
13095 },
13096
13097 _slide: function( event, index, newVal ) {
13098 var otherVal,
13099 newValues,
13100 allowed;
13101
13102 if ( this.options.values && this.options.values.length ) {
13103 otherVal = this.values( index ? 0 : 1 );
13104
13105 if ( ( this.options.values.length === 2 && this.options.range === true ) &&
13106 ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
13107 ) {
13108 newVal = otherVal;
13109 }
13110
13111 if ( newVal !== this.values( index ) ) {
13112 newValues = this.values();
13113 newValues[ index ] = newVal;
13114 // A slide can be canceled by returning false from the slide callback
13115 allowed = this._trigger( "slide", event, {
13116 handle: this.handles[ index ],
13117 value: newVal,
13118 values: newValues
13119 } );
13120 otherVal = this.values( index ? 0 : 1 );
13121 if ( allowed !== false ) {
13122 this.values( index, newVal );
13123 }
13124 }
13125 } else {
13126 if ( newVal !== this.value() ) {
13127 // A slide can be canceled by returning false from the slide callback
13128 allowed = this._trigger( "slide", event, {
13129 handle: this.handles[ index ],
13130 value: newVal
13131 } );
13132 if ( allowed !== false ) {
13133 this.value( newVal );
13134 }
13135 }
13136 }
13137 },
13138
13139 _stop: function( event, index ) {
13140 var uiHash = {
13141 handle: this.handles[ index ],
13142 value: this.value()
13143 };
13144 if ( this.options.values && this.options.values.length ) {
13145 uiHash.value = this.values( index );
13146 uiHash.values = this.values();
13147 }
13148
13149 this._trigger( "stop", event, uiHash );
13150 },
13151
13152 _change: function( event, index ) {
13153 if ( !this._keySliding && !this._mouseSliding ) {
13154 var uiHash = {
13155 handle: this.handles[ index ],
13156 value: this.value()
13157 };
13158 if ( this.options.values && this.options.values.length ) {
13159 uiHash.value = this.values( index );
13160 uiHash.values = this.values();
13161 }
13162
13163 //store the last changed value index for reference when handles overlap
13164 this._lastChangedValue = index;
13165
13166 this._trigger( "change", event, uiHash );
13167 }
13168 },
13169
13170 value: function( newValue ) {
13171 if ( arguments.length ) {
13172 this.options.value = this._trimAlignValue( newValue );
13173 this._refreshValue();
13174 this._change( null, 0 );
13175 return;
13176 }
13177
13178 return this._value();
13179 },
13180
13181 values: function( index, newValue ) {
13182 var vals,
13183 newValues,
13184 i;
13185
13186 if ( arguments.length > 1 ) {
13187 this.options.values[ index ] = this._trimAlignValue( newValue );
13188 this._refreshValue();
13189 this._change( null, index );
13190 return;
13191 }
13192
13193 if ( arguments.length ) {
13194 if ( $.isArray( arguments[ 0 ] ) ) {
13195 vals = this.options.values;
13196 newValues = arguments[ 0 ];
13197 for ( i = 0; i < vals.length; i += 1 ) {
13198 vals[ i ] = this._trimAlignValue( newValues[ i ] );
13199 this._change( null, i );
13200 }
13201 this._refreshValue();
13202 } else {
13203 if ( this.options.values && this.options.values.length ) {
13204 return this._values( index );
13205 } else {
13206 return this.value();
13207 }
13208 }
13209 } else {
13210 return this._values();
13211 }
13212 },
13213
13214 _setOption: function( key, value ) {
13215 var i,
13216 valsLength = 0;
13217
13218 if ( key === "range" && this.options.range === true ) {
13219 if ( value === "min" ) {
13220 this.options.value = this._values( 0 );
13221 this.options.values = null;
13222 } else if ( value === "max" ) {
13223 this.options.value = this._values( this.options.values.length - 1 );
13224 this.options.values = null;
13225 }
13226 }
13227
13228 if ( $.isArray( this.options.values ) ) {
13229 valsLength = this.options.values.length;
13230 }
13231
13232 if ( key === "disabled" ) {
13233 this.element.toggleClass( "ui-state-disabled", !!value );
13234 }
13235
13236 this._super( key, value );
13237
13238 switch ( key ) {
13239 case "orientation":
13240 this._detectOrientation();
13241 this.element
13242 .removeClass( "ui-slider-horizontal ui-slider-vertical" )
13243 .addClass( "ui-slider-" + this.orientation );
13244 this._refreshValue();
13245
13246 // Reset positioning from previous orientation
13247 this.handles.css( value === "horizontal" ? "bottom" : "left", "" );
13248 break;
13249 case "value":
13250 this._animateOff = true;
13251 this._refreshValue();
13252 this._change( null, 0 );
13253 this._animateOff = false;
13254 break;
13255 case "values":
13256 this._animateOff = true;
13257 this._refreshValue();
13258 for ( i = 0; i < valsLength; i += 1 ) {
13259 this._change( null, i );
13260 }
13261 this._animateOff = false;
13262 break;
13263 case "step":
13264 case "min":
13265 case "max":
13266 this._animateOff = true;
13267 this._calculateNewMax();
13268 this._refreshValue();
13269 this._animateOff = false;
13270 break;
13271 case "range":
13272 this._animateOff = true;
13273 this._refresh();
13274 this._animateOff = false;
13275 break;
13276 }
13277 },
13278
13279 //internal value getter
13280 // _value() returns value trimmed by min and max, aligned by step
13281 _value: function() {
13282 var val = this.options.value;
13283 val = this._trimAlignValue( val );
13284
13285 return val;
13286 },
13287
13288 //internal values getter
13289 // _values() returns array of values trimmed by min and max, aligned by step
13290 // _values( index ) returns single value trimmed by min and max, aligned by step
13291 _values: function( index ) {
13292 var val,
13293 vals,
13294 i;
13295
13296 if ( arguments.length ) {
13297 val = this.options.values[ index ];
13298 val = this._trimAlignValue( val );
13299
13300 return val;
13301 } else if ( this.options.values && this.options.values.length ) {
13302 // .slice() creates a copy of the array
13303 // this copy gets trimmed by min and max and then returned
13304 vals = this.options.values.slice();
13305 for ( i = 0; i < vals.length; i += 1) {
13306 vals[ i ] = this._trimAlignValue( vals[ i ] );
13307 }
13308
13309 return vals;
13310 } else {
13311 return [];
13312 }
13313 },
13314
13315 // returns the step-aligned value that val is closest to, between (inclusive) min and max
13316 _trimAlignValue: function( val ) {
13317 if ( val <= this._valueMin() ) {
13318 return this._valueMin();
13319 }
13320 if ( val >= this._valueMax() ) {
13321 return this._valueMax();
13322 }
13323 var step = ( this.options.step > 0 ) ? this.options.step : 1,
13324 valModStep = (val - this._valueMin()) % step,
13325 alignValue = val - valModStep;
13326
13327 if ( Math.abs(valModStep) * 2 >= step ) {
13328 alignValue += ( valModStep > 0 ) ? step : ( -step );
13329 }
13330
13331 // Since JavaScript has problems with large floats, round
13332 // the final value to 5 digits after the decimal point (see #4124)
13333 return parseFloat( alignValue.toFixed(5) );
13334 },
13335
13336 _calculateNewMax: function() {
13337 var max = this.options.max,
13338 min = this._valueMin(),
13339 step = this.options.step,
13340 aboveMin = Math.floor( ( +( max - min ).toFixed( this._precision() ) ) / step ) * step;
13341 max = aboveMin + min;
13342 this.max = parseFloat( max.toFixed( this._precision() ) );
13343 },
13344
13345 _precision: function() {
13346 var precision = this._precisionOf( this.options.step );
13347 if ( this.options.min !== null ) {
13348 precision = Math.max( precision, this._precisionOf( this.options.min ) );
13349 }
13350 return precision;
13351 },
13352
13353 _precisionOf: function( num ) {
13354 var str = num.toString(),
13355 decimal = str.indexOf( "." );
13356 return decimal === -1 ? 0 : str.length - decimal - 1;
13357 },
13358
13359 _valueMin: function() {
13360 return this.options.min;
13361 },
13362
13363 _valueMax: function() {
13364 return this.max;
13365 },
13366
13367 _refreshValue: function() {
13368 var lastValPercent, valPercent, value, valueMin, valueMax,
13369 oRange = this.options.range,
13370 o = this.options,
13371 that = this,
13372 animate = ( !this._animateOff ) ? o.animate : false,
13373 _set = {};
13374
13375 if ( this.options.values && this.options.values.length ) {
13376 this.handles.each(function( i ) {
13377 valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
13378 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
13379 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
13380 if ( that.options.range === true ) {
13381 if ( that.orientation === "horizontal" ) {
13382 if ( i === 0 ) {
13383 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
13384 }
13385 if ( i === 1 ) {
13386 that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
13387 }
13388 } else {
13389 if ( i === 0 ) {
13390 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
13391 }
13392 if ( i === 1 ) {
13393 that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
13394 }
13395 }
13396 }
13397 lastValPercent = valPercent;
13398 });
13399 } else {
13400 value = this.value();
13401 valueMin = this._valueMin();
13402 valueMax = this._valueMax();
13403 valPercent = ( valueMax !== valueMin ) ?
13404 ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
13405 0;
13406 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
13407 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
13408
13409 if ( oRange === "min" && this.orientation === "horizontal" ) {
13410 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
13411 }
13412 if ( oRange === "max" && this.orientation === "horizontal" ) {
13413 this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
13414 }
13415 if ( oRange === "min" && this.orientation === "vertical" ) {
13416 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
13417 }
13418 if ( oRange === "max" && this.orientation === "vertical" ) {
13419 this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
13420 }
13421 }
13422 },
13423
13424 _handleEvents: {
13425 keydown: function( event ) {
13426 var allowed, curVal, newVal, step,
13427 index = $( event.target ).data( "ui-slider-handle-index" );
13428
13429 switch ( event.keyCode ) {
13430 case $.ui.keyCode.HOME:
13431 case $.ui.keyCode.END:
13432 case $.ui.keyCode.PAGE_UP:
13433 case $.ui.keyCode.PAGE_DOWN:
13434 case $.ui.keyCode.UP:
13435 case $.ui.keyCode.RIGHT:
13436 case $.ui.keyCode.DOWN:
13437 case $.ui.keyCode.LEFT:
13438 event.preventDefault();
13439 if ( !this._keySliding ) {
13440 this._keySliding = true;
13441 $( event.target ).addClass( "ui-state-active" );
13442 allowed = this._start( event, index );
13443 if ( allowed === false ) {
13444 return;
13445 }
13446 }
13447 break;
13448 }
13449
13450 step = this.options.step;
13451 if ( this.options.values && this.options.values.length ) {
13452 curVal = newVal = this.values( index );
13453 } else {
13454 curVal = newVal = this.value();
13455 }
13456
13457 switch ( event.keyCode ) {
13458 case $.ui.keyCode.HOME:
13459 newVal = this._valueMin();
13460 break;
13461 case $.ui.keyCode.END:
13462 newVal = this._valueMax();
13463 break;
13464 case $.ui.keyCode.PAGE_UP:
13465 newVal = this._trimAlignValue(
13466 curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages )
13467 );
13468 break;
13469 case $.ui.keyCode.PAGE_DOWN:
13470 newVal = this._trimAlignValue(
13471 curVal - ( (this._valueMax() - this._valueMin()) / this.numPages ) );
13472 break;
13473 case $.ui.keyCode.UP:
13474 case $.ui.keyCode.RIGHT:
13475 if ( curVal === this._valueMax() ) {
13476 return;
13477 }
13478 newVal = this._trimAlignValue( curVal + step );
13479 break;
13480 case $.ui.keyCode.DOWN:
13481 case $.ui.keyCode.LEFT:
13482 if ( curVal === this._valueMin() ) {
13483 return;
13484 }
13485 newVal = this._trimAlignValue( curVal - step );
13486 break;
13487 }
13488
13489 this._slide( event, index, newVal );
13490 },
13491 keyup: function( event ) {
13492 var index = $( event.target ).data( "ui-slider-handle-index" );
13493
13494 if ( this._keySliding ) {
13495 this._keySliding = false;
13496 this._stop( event, index );
13497 this._change( event, index );
13498 $( event.target ).removeClass( "ui-state-active" );
13499 }
13500 }
13501 }
13502 });
13503
13504
13505 /*!
13506 * jQuery UI Sortable 1.11.4
13507 * http://jqueryui.com
13508 *
13509 * Copyright jQuery Foundation and other contributors
13510 * Released under the MIT license.
13511 * http://jquery.org/license
13512 *
13513 * http://api.jqueryui.com/sortable/
13514 */
13515
13516
13517 var sortable = $.widget("ui.sortable", $.ui.mouse, {
13518 version: "1.11.4",
13519 widgetEventPrefix: "sort",
13520 ready: false,
13521 options: {
13522 appendTo: "parent",
13523 axis: false,
13524 connectWith: false,
13525 containment: false,
13526 cursor: "auto",
13527 cursorAt: false,
13528 dropOnEmpty: true,
13529 forcePlaceholderSize: false,
13530 forceHelperSize: false,
13531 grid: false,
13532 handle: false,
13533 helper: "original",
13534 items: "> *",
13535 opacity: false,
13536 placeholder: false,
13537 revert: false,
13538 scroll: true,
13539 scrollSensitivity: 20,
13540 scrollSpeed: 20,
13541 scope: "default",
13542 tolerance: "intersect",
13543 zIndex: 1000,
13544
13545 // callbacks
13546 activate: null,
13547 beforeStop: null,
13548 change: null,
13549 deactivate: null,
13550 out: null,
13551 over: null,
13552 receive: null,
13553 remove: null,
13554 sort: null,
13555 start: null,
13556 stop: null,
13557 update: null
13558 },
13559
13560 _isOverAxis: function( x, reference, size ) {
13561 return ( x >= reference ) && ( x < ( reference + size ) );
13562 },
13563
13564 _isFloating: function( item ) {
13565 return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display"));
13566 },
13567
13568 _create: function() {
13569 this.containerCache = {};
13570 this.element.addClass("ui-sortable");
13571
13572 //Get the items
13573 this.refresh();
13574
13575 //Let's determine the parent's offset
13576 this.offset = this.element.offset();
13577
13578 //Initialize mouse events for interaction
13579 this._mouseInit();
13580
13581 this._setHandleClassName();
13582
13583 //We're ready to go
13584 this.ready = true;
13585
13586 },
13587
13588 _setOption: function( key, value ) {
13589 this._super( key, value );
13590
13591 if ( key === "handle" ) {
13592 this._setHandleClassName();
13593 }
13594 },
13595
13596 _setHandleClassName: function() {
13597 this.element.find( ".ui-sortable-handle" ).removeClass( "ui-sortable-handle" );
13598 $.each( this.items, function() {
13599 ( this.instance.options.handle ?
13600 this.item.find( this.instance.options.handle ) : this.item )
13601 .addClass( "ui-sortable-handle" );
13602 });
13603 },
13604
13605 _destroy: function() {
13606 this.element
13607 .removeClass( "ui-sortable ui-sortable-disabled" )
13608 .find( ".ui-sortable-handle" )
13609 .removeClass( "ui-sortable-handle" );
13610 this._mouseDestroy();
13611
13612 for ( var i = this.items.length - 1; i >= 0; i-- ) {
13613 this.items[i].item.removeData(this.widgetName + "-item");
13614 }
13615
13616 return this;
13617 },
13618
13619 _mouseCapture: function(event, overrideHandle) {
13620 var currentItem = null,
13621 validHandle = false,
13622 that = this;
13623
13624 if (this.reverting) {
13625 return false;
13626 }
13627
13628 if(this.options.disabled || this.options.type === "static") {
13629 return false;
13630 }
13631
13632 //We have to refresh the items data once first
13633 this._refreshItems(event);
13634
13635 //Find out if the clicked node (or one of its parents) is a actual item in this.items
13636 $(event.target).parents().each(function() {
13637 if($.data(this, that.widgetName + "-item") === that) {
13638 currentItem = $(this);
13639 return false;
13640 }
13641 });
13642 if($.data(event.target, that.widgetName + "-item") === that) {
13643 currentItem = $(event.target);
13644 }
13645
13646 if(!currentItem) {
13647 return false;
13648 }
13649 if(this.options.handle && !overrideHandle) {
13650 $(this.options.handle, currentItem).find("*").addBack().each(function() {
13651 if(this === event.target) {
13652 validHandle = true;
13653 }
13654 });
13655 if(!validHandle) {
13656 return false;
13657 }
13658 }
13659
13660 this.currentItem = currentItem;
13661 this._removeCurrentsFromItems();
13662 return true;
13663
13664 },
13665
13666 _mouseStart: function(event, overrideHandle, noActivation) {
13667
13668 var i, body,
13669 o = this.options;
13670
13671 this.currentContainer = this;
13672
13673 //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
13674 this.refreshPositions();
13675
13676 //Create and append the visible helper
13677 this.helper = this._createHelper(event);
13678
13679 //Cache the helper size
13680 this._cacheHelperProportions();
13681
13682 /*
13683 * - Position generation -
13684 * This block generates everything position related - it's the core of draggables.
13685 */
13686
13687 //Cache the margins of the original element
13688 this._cacheMargins();
13689
13690 //Get the next scrolling parent
13691 this.scrollParent = this.helper.scrollParent();
13692
13693 //The element's absolute position on the page minus margins
13694 this.offset = this.currentItem.offset();
13695 this.offset = {
13696 top: this.offset.top - this.margins.top,
13697 left: this.offset.left - this.margins.left
13698 };
13699
13700 $.extend(this.offset, {
13701 click: { //Where the click happened, relative to the element
13702 left: event.pageX - this.offset.left,
13703 top: event.pageY - this.offset.top
13704 },
13705 parent: this._getParentOffset(),
13706 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
13707 });
13708
13709 // Only after we got the offset, we can change the helper's position to absolute
13710 // TODO: Still need to figure out a way to make relative sorting possible
13711 this.helper.css("position", "absolute");
13712 this.cssPosition = this.helper.css("position");
13713
13714 //Generate the original position
13715 this.originalPosition = this._generatePosition(event);
13716 this.originalPageX = event.pageX;
13717 this.originalPageY = event.pageY;
13718
13719 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
13720 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
13721
13722 //Cache the former DOM position
13723 this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
13724
13725 //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
13726 if(this.helper[0] !== this.currentItem[0]) {
13727 this.currentItem.hide();
13728 }
13729
13730 //Create the placeholder
13731 this._createPlaceholder();
13732
13733 //Set a containment if given in the options
13734 if(o.containment) {
13735 this._setContainment();
13736 }
13737
13738 if( o.cursor && o.cursor !== "auto" ) { // cursor option
13739 body = this.document.find( "body" );
13740
13741 // support: IE
13742 this.storedCursor = body.css( "cursor" );
13743 body.css( "cursor", o.cursor );
13744
13745 this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body );
13746 }
13747
13748 if(o.opacity) { // opacity option
13749 if (this.helper.css("opacity")) {
13750 this._storedOpacity = this.helper.css("opacity");
13751 }
13752 this.helper.css("opacity", o.opacity);
13753 }
13754
13755 if(o.zIndex) { // zIndex option
13756 if (this.helper.css("zIndex")) {
13757 this._storedZIndex = this.helper.css("zIndex");
13758 }
13759 this.helper.css("zIndex", o.zIndex);
13760 }
13761
13762 //Prepare scrolling
13763 if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") {
13764 this.overflowOffset = this.scrollParent.offset();
13765 }
13766
13767 //Call callbacks
13768 this._trigger("start", event, this._uiHash());
13769
13770 //Recache the helper size
13771 if(!this._preserveHelperProportions) {
13772 this._cacheHelperProportions();
13773 }
13774
13775
13776 //Post "activate" events to possible containers
13777 if( !noActivation ) {
13778 for ( i = this.containers.length - 1; i >= 0; i-- ) {
13779 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
13780 }
13781 }
13782
13783 //Prepare possible droppables
13784 if($.ui.ddmanager) {
13785 $.ui.ddmanager.current = this;
13786 }
13787
13788 if ($.ui.ddmanager && !o.dropBehaviour) {
13789 $.ui.ddmanager.prepareOffsets(this, event);
13790 }
13791
13792 this.dragging = true;
13793
13794 this.helper.addClass("ui-sortable-helper");
13795 this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
13796 return true;
13797
13798 },
13799
13800 _mouseDrag: function(event) {
13801 var i, item, itemElement, intersection,
13802 o = this.options,
13803 scrolled = false;
13804
13805 //Compute the helpers position
13806 this.position = this._generatePosition(event);
13807 this.positionAbs = this._convertPositionTo("absolute");
13808
13809 if (!this.lastPositionAbs) {
13810 this.lastPositionAbs = this.positionAbs;
13811 }
13812
13813 //Do scrolling
13814 if(this.options.scroll) {
13815 if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") {
13816
13817 if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
13818 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
13819 } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
13820 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
13821 }
13822
13823 if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
13824 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
13825 } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
13826 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
13827 }
13828
13829 } else {
13830
13831 if(event.pageY - this.document.scrollTop() < o.scrollSensitivity) {
13832 scrolled = this.document.scrollTop(this.document.scrollTop() - o.scrollSpeed);
13833 } else if(this.window.height() - (event.pageY - this.document.scrollTop()) < o.scrollSensitivity) {
13834 scrolled = this.document.scrollTop(this.document.scrollTop() + o.scrollSpeed);
13835 }
13836
13837 if(event.pageX - this.document.scrollLeft() < o.scrollSensitivity) {
13838 scrolled = this.document.scrollLeft(this.document.scrollLeft() - o.scrollSpeed);
13839 } else if(this.window.width() - (event.pageX - this.document.scrollLeft()) < o.scrollSensitivity) {
13840 scrolled = this.document.scrollLeft(this.document.scrollLeft() + o.scrollSpeed);
13841 }
13842
13843 }
13844
13845 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
13846 $.ui.ddmanager.prepareOffsets(this, event);
13847 }
13848 }
13849
13850 //Regenerate the absolute position used for position checks
13851 this.positionAbs = this._convertPositionTo("absolute");
13852
13853 //Set the helper position
13854 if(!this.options.axis || this.options.axis !== "y") {
13855 this.helper[0].style.left = this.position.left+"px";
13856 }
13857 if(!this.options.axis || this.options.axis !== "x") {
13858 this.helper[0].style.top = this.position.top+"px";
13859 }
13860
13861 //Rearrange
13862 for (i = this.items.length - 1; i >= 0; i--) {
13863
13864 //Cache variables and intersection, continue if no intersection
13865 item = this.items[i];
13866 itemElement = item.item[0];
13867 intersection = this._intersectsWithPointer(item);
13868 if (!intersection) {
13869 continue;
13870 }
13871
13872 // Only put the placeholder inside the current Container, skip all
13873 // items from other containers. This works because when moving
13874 // an item from one container to another the
13875 // currentContainer is switched before the placeholder is moved.
13876 //
13877 // Without this, moving items in "sub-sortables" can cause
13878 // the placeholder to jitter between the outer and inner container.
13879 if (item.instance !== this.currentContainer) {
13880 continue;
13881 }
13882
13883 // cannot intersect with itself
13884 // no useless actions that have been done before
13885 // no action if the item moved is the parent of the item checked
13886 if (itemElement !== this.currentItem[0] &&
13887 this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement &&
13888 !$.contains(this.placeholder[0], itemElement) &&
13889 (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true)
13890 ) {
13891
13892 this.direction = intersection === 1 ? "down" : "up";
13893
13894 if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
13895 this._rearrange(event, item);
13896 } else {
13897 break;
13898 }
13899
13900 this._trigger("change", event, this._uiHash());
13901 break;
13902 }
13903 }
13904
13905 //Post events to containers
13906 this._contactContainers(event);
13907
13908 //Interconnect with droppables
13909 if($.ui.ddmanager) {
13910 $.ui.ddmanager.drag(this, event);
13911 }
13912
13913 //Call callbacks
13914 this._trigger("sort", event, this._uiHash());
13915
13916 this.lastPositionAbs = this.positionAbs;
13917 return false;
13918
13919 },
13920
13921 _mouseStop: function(event, noPropagation) {
13922
13923 if(!event) {
13924 return;
13925 }
13926
13927 //If we are using droppables, inform the manager about the drop
13928 if ($.ui.ddmanager && !this.options.dropBehaviour) {
13929 $.ui.ddmanager.drop(this, event);
13930 }
13931
13932 if(this.options.revert) {
13933 var that = this,
13934 cur = this.placeholder.offset(),
13935 axis = this.options.axis,
13936 animation = {};
13937
13938 if ( !axis || axis === "x" ) {
13939 animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollLeft);
13940 }
13941 if ( !axis || axis === "y" ) {
13942 animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollTop);
13943 }
13944 this.reverting = true;
13945 $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() {
13946 that._clear(event);
13947 });
13948 } else {
13949 this._clear(event, noPropagation);
13950 }
13951
13952 return false;
13953
13954 },
13955
13956 cancel: function() {
13957
13958 if(this.dragging) {
13959
13960 this._mouseUp({ target: null });
13961
13962 if(this.options.helper === "original") {
13963 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
13964 } else {
13965 this.currentItem.show();
13966 }
13967
13968 //Post deactivating events to containers
13969 for (var i = this.containers.length - 1; i >= 0; i--){
13970 this.containers[i]._trigger("deactivate", null, this._uiHash(this));
13971 if(this.containers[i].containerCache.over) {
13972 this.containers[i]._trigger("out", null, this._uiHash(this));
13973 this.containers[i].containerCache.over = 0;
13974 }
13975 }
13976
13977 }
13978
13979 if (this.placeholder) {
13980 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
13981 if(this.placeholder[0].parentNode) {
13982 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
13983 }
13984 if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) {
13985 this.helper.remove();
13986 }
13987
13988 $.extend(this, {
13989 helper: null,
13990 dragging: false,
13991 reverting: false,
13992 _noFinalSort: null
13993 });
13994
13995 if(this.domPosition.prev) {
13996 $(this.domPosition.prev).after(this.currentItem);
13997 } else {
13998 $(this.domPosition.parent).prepend(this.currentItem);
13999 }
14000 }
14001
14002 return this;
14003
14004 },
14005
14006 serialize: function(o) {
14007
14008 var items = this._getItemsAsjQuery(o && o.connected),
14009 str = [];
14010 o = o || {};
14011
14012 $(items).each(function() {
14013 var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/));
14014 if (res) {
14015 str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2]));
14016 }
14017 });
14018
14019 if(!str.length && o.key) {
14020 str.push(o.key + "=");
14021 }
14022
14023 return str.join("&");
14024
14025 },
14026
14027 toArray: function(o) {
14028
14029 var items = this._getItemsAsjQuery(o && o.connected),
14030 ret = [];
14031
14032 o = o || {};
14033
14034 items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); });
14035 return ret;
14036
14037 },
14038
14039 /* Be careful with the following core functions */
14040 _intersectsWith: function(item) {
14041
14042 var x1 = this.positionAbs.left,
14043 x2 = x1 + this.helperProportions.width,
14044 y1 = this.positionAbs.top,
14045 y2 = y1 + this.helperProportions.height,
14046 l = item.left,
14047 r = l + item.width,
14048 t = item.top,
14049 b = t + item.height,
14050 dyClick = this.offset.click.top,
14051 dxClick = this.offset.click.left,
14052 isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ),
14053 isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ),
14054 isOverElement = isOverElementHeight && isOverElementWidth;
14055
14056 if ( this.options.tolerance === "pointer" ||
14057 this.options.forcePointerForContainers ||
14058 (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"])
14059 ) {
14060 return isOverElement;
14061 } else {
14062
14063 return (l < x1 + (this.helperProportions.width / 2) && // Right Half
14064 x2 - (this.helperProportions.width / 2) < r && // Left Half
14065 t < y1 + (this.helperProportions.height / 2) && // Bottom Half
14066 y2 - (this.helperProportions.height / 2) < b ); // Top Half
14067
14068 }
14069 },
14070
14071 _intersectsWithPointer: function(item) {
14072
14073 var isOverElementHeight = (this.options.axis === "x") || this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
14074 isOverElementWidth = (this.options.axis === "y") || this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
14075 isOverElement = isOverElementHeight && isOverElementWidth,
14076 verticalDirection = this._getDragVerticalDirection(),
14077 horizontalDirection = this._getDragHorizontalDirection();
14078
14079 if (!isOverElement) {
14080 return false;
14081 }
14082
14083 return this.floating ?
14084 ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 )
14085 : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) );
14086
14087 },
14088
14089 _intersectsWithSides: function(item) {
14090
14091 var isOverBottomHalf = this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
14092 isOverRightHalf = this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
14093 verticalDirection = this._getDragVerticalDirection(),
14094 horizontalDirection = this._getDragHorizontalDirection();
14095
14096 if (this.floating && horizontalDirection) {
14097 return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf));
14098 } else {
14099 return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf));
14100 }
14101
14102 },
14103
14104 _getDragVerticalDirection: function() {
14105 var delta = this.positionAbs.top - this.lastPositionAbs.top;
14106 return delta !== 0 && (delta > 0 ? "down" : "up");
14107 },
14108
14109 _getDragHorizontalDirection: function() {
14110 var delta = this.positionAbs.left - this.lastPositionAbs.left;
14111 return delta !== 0 && (delta > 0 ? "right" : "left");
14112 },
14113
14114 refresh: function(event) {
14115 this._refreshItems(event);
14116 this._setHandleClassName();
14117 this.refreshPositions();
14118 return this;
14119 },
14120
14121 _connectWith: function() {
14122 var options = this.options;
14123 return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith;
14124 },
14125
14126 _getItemsAsjQuery: function(connected) {
14127
14128 var i, j, cur, inst,
14129 items = [],
14130 queries = [],
14131 connectWith = this._connectWith();
14132
14133 if(connectWith && connected) {
14134 for (i = connectWith.length - 1; i >= 0; i--){
14135 cur = $(connectWith[i], this.document[0]);
14136 for ( j = cur.length - 1; j >= 0; j--){
14137 inst = $.data(cur[j], this.widgetFullName);
14138 if(inst && inst !== this && !inst.options.disabled) {
14139 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]);
14140 }
14141 }
14142 }
14143 }
14144
14145 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]);
14146
14147 function addItems() {
14148 items.push( this );
14149 }
14150 for (i = queries.length - 1; i >= 0; i--){
14151 queries[i][0].each( addItems );
14152 }
14153
14154 return $(items);
14155
14156 },
14157
14158 _removeCurrentsFromItems: function() {
14159
14160 var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
14161
14162 this.items = $.grep(this.items, function (item) {
14163 for (var j=0; j < list.length; j++) {
14164 if(list[j] === item.item[0]) {
14165 return false;
14166 }
14167 }
14168 return true;
14169 });
14170
14171 },
14172
14173 _refreshItems: function(event) {
14174
14175 this.items = [];
14176 this.containers = [this];
14177
14178 var i, j, cur, inst, targetData, _queries, item, queriesLength,
14179 items = this.items,
14180 queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]],
14181 connectWith = this._connectWith();
14182
14183 if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
14184 for (i = connectWith.length - 1; i >= 0; i--){
14185 cur = $(connectWith[i], this.document[0]);
14186 for (j = cur.length - 1; j >= 0; j--){
14187 inst = $.data(cur[j], this.widgetFullName);
14188 if(inst && inst !== this && !inst.options.disabled) {
14189 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
14190 this.containers.push(inst);
14191 }
14192 }
14193 }
14194 }
14195
14196 for (i = queries.length - 1; i >= 0; i--) {
14197 targetData = queries[i][1];
14198 _queries = queries[i][0];
14199
14200 for (j=0, queriesLength = _queries.length; j < queriesLength; j++) {
14201 item = $(_queries[j]);
14202
14203 item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager)
14204
14205 items.push({
14206 item: item,
14207 instance: targetData,
14208 width: 0, height: 0,
14209 left: 0, top: 0
14210 });
14211 }
14212 }
14213
14214 },
14215
14216 refreshPositions: function(fast) {
14217
14218 // Determine whether items are being displayed horizontally
14219 this.floating = this.items.length ?
14220 this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) :
14221 false;
14222
14223 //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
14224 if(this.offsetParent && this.helper) {
14225 this.offset.parent = this._getParentOffset();
14226 }
14227
14228 var i, item, t, p;
14229
14230 for (i = this.items.length - 1; i >= 0; i--){
14231 item = this.items[i];
14232
14233 //We ignore calculating positions of all connected containers when we're not over them
14234 if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) {
14235 continue;
14236 }
14237
14238 t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
14239
14240 if (!fast) {
14241 item.width = t.outerWidth();
14242 item.height = t.outerHeight();
14243 }
14244
14245 p = t.offset();
14246 item.left = p.left;
14247 item.top = p.top;
14248 }
14249
14250 if(this.options.custom && this.options.custom.refreshContainers) {
14251 this.options.custom.refreshContainers.call(this);
14252 } else {
14253 for (i = this.containers.length - 1; i >= 0; i--){
14254 p = this.containers[i].element.offset();
14255 this.containers[i].containerCache.left = p.left;
14256 this.containers[i].containerCache.top = p.top;
14257 this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
14258 this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
14259 }
14260 }
14261
14262 return this;
14263 },
14264
14265 _createPlaceholder: function(that) {
14266 that = that || this;
14267 var className,
14268 o = that.options;
14269
14270 if(!o.placeholder || o.placeholder.constructor === String) {
14271 className = o.placeholder;
14272 o.placeholder = {
14273 element: function() {
14274
14275 var nodeName = that.currentItem[0].nodeName.toLowerCase(),
14276 element = $( "<" + nodeName + ">", that.document[0] )
14277 .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
14278 .removeClass("ui-sortable-helper");
14279
14280 if ( nodeName === "tbody" ) {
14281 that._createTrPlaceholder(
14282 that.currentItem.find( "tr" ).eq( 0 ),
14283 $( "<tr>", that.document[ 0 ] ).appendTo( element )
14284 );
14285 } else if ( nodeName === "tr" ) {
14286 that._createTrPlaceholder( that.currentItem, element );
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 _createTrPlaceholder: function( sourceTr, targetTr ) {
14324 var that = this;
14325
14326 sourceTr.children().each(function() {
14327 $( "<td>&#160;</td>", that.document[ 0 ] )
14328 .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
14329 .appendTo( targetTr );
14330 });
14331 },
14332
14333 _contactContainers: function(event) {
14334 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom, floating, axis,
14335 innermostContainer = null,
14336 innermostIndex = null;
14337
14338 // get innermost container that intersects with item
14339 for (i = this.containers.length - 1; i >= 0; i--) {
14340
14341 // never consider a container that's located within the item itself
14342 if($.contains(this.currentItem[0], this.containers[i].element[0])) {
14343 continue;
14344 }
14345
14346 if(this._intersectsWith(this.containers[i].containerCache)) {
14347
14348 // if we've already found a container and it's more "inner" than this, then continue
14349 if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) {
14350 continue;
14351 }
14352
14353 innermostContainer = this.containers[i];
14354 innermostIndex = i;
14355
14356 } else {
14357 // container doesn't intersect. trigger "out" event if necessary
14358 if(this.containers[i].containerCache.over) {
14359 this.containers[i]._trigger("out", event, this._uiHash(this));
14360 this.containers[i].containerCache.over = 0;
14361 }
14362 }
14363
14364 }
14365
14366 // if no intersecting containers found, return
14367 if(!innermostContainer) {
14368 return;
14369 }
14370
14371 // move the item into the container if it's not there already
14372 if(this.containers.length === 1) {
14373 if (!this.containers[innermostIndex].containerCache.over) {
14374 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
14375 this.containers[innermostIndex].containerCache.over = 1;
14376 }
14377 } else {
14378
14379 //When entering a new container, we will find the item with the least distance and append our item near it
14380 dist = 10000;
14381 itemWithLeastDistance = null;
14382 floating = innermostContainer.floating || this._isFloating(this.currentItem);
14383 posProperty = floating ? "left" : "top";
14384 sizeProperty = floating ? "width" : "height";
14385 axis = floating ? "clientX" : "clientY";
14386
14387 for (j = this.items.length - 1; j >= 0; j--) {
14388 if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) {
14389 continue;
14390 }
14391 if(this.items[j].item[0] === this.currentItem[0]) {
14392 continue;
14393 }
14394
14395 cur = this.items[j].item.offset()[posProperty];
14396 nearBottom = false;
14397 if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
14398 nearBottom = true;
14399 }
14400
14401 if ( Math.abs( event[ axis ] - cur ) < dist ) {
14402 dist = Math.abs( event[ axis ] - cur );
14403 itemWithLeastDistance = this.items[ j ];
14404 this.direction = nearBottom ? "up": "down";
14405 }
14406 }
14407
14408 //Check if dropOnEmpty is enabled
14409 if(!itemWithLeastDistance && !this.options.dropOnEmpty) {
14410 return;
14411 }
14412
14413 if(this.currentContainer === this.containers[innermostIndex]) {
14414 if ( !this.currentContainer.containerCache.over ) {
14415 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
14416 this.currentContainer.containerCache.over = 1;
14417 }
14418 return;
14419 }
14420
14421 itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
14422 this._trigger("change", event, this._uiHash());
14423 this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
14424 this.currentContainer = this.containers[innermostIndex];
14425
14426 //Update the placeholder
14427 this.options.placeholder.update(this.currentContainer, this.placeholder);
14428
14429 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
14430 this.containers[innermostIndex].containerCache.over = 1;
14431 }
14432
14433
14434 },
14435
14436 _createHelper: function(event) {
14437
14438 var o = this.options,
14439 helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem);
14440
14441 //Add the helper to the DOM if that didn't happen already
14442 if(!helper.parents("body").length) {
14443 $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
14444 }
14445
14446 if(helper[0] === this.currentItem[0]) {
14447 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") };
14448 }
14449
14450 if(!helper[0].style.width || o.forceHelperSize) {
14451 helper.width(this.currentItem.width());
14452 }
14453 if(!helper[0].style.height || o.forceHelperSize) {
14454 helper.height(this.currentItem.height());
14455 }
14456
14457 return helper;
14458
14459 },
14460
14461 _adjustOffsetFromHelper: function(obj) {
14462 if (typeof obj === "string") {
14463 obj = obj.split(" ");
14464 }
14465 if ($.isArray(obj)) {
14466 obj = {left: +obj[0], top: +obj[1] || 0};
14467 }
14468 if ("left" in obj) {
14469 this.offset.click.left = obj.left + this.margins.left;
14470 }
14471 if ("right" in obj) {
14472 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
14473 }
14474 if ("top" in obj) {
14475 this.offset.click.top = obj.top + this.margins.top;
14476 }
14477 if ("bottom" in obj) {
14478 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
14479 }
14480 },
14481
14482 _getParentOffset: function() {
14483
14484
14485 //Get the offsetParent and cache its position
14486 this.offsetParent = this.helper.offsetParent();
14487 var po = this.offsetParent.offset();
14488
14489 // This is a special case where we need to modify a offset calculated on start, since the following happened:
14490 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
14491 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
14492 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
14493 if(this.cssPosition === "absolute" && this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) {
14494 po.left += this.scrollParent.scrollLeft();
14495 po.top += this.scrollParent.scrollTop();
14496 }
14497
14498 // This needs to be actually done for all browsers, since pageX/pageY includes this information
14499 // with an ugly IE fix
14500 if( this.offsetParent[0] === this.document[0].body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
14501 po = { top: 0, left: 0 };
14502 }
14503
14504 return {
14505 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
14506 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
14507 };
14508
14509 },
14510
14511 _getRelativeOffset: function() {
14512
14513 if(this.cssPosition === "relative") {
14514 var p = this.currentItem.position();
14515 return {
14516 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
14517 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
14518 };
14519 } else {
14520 return { top: 0, left: 0 };
14521 }
14522
14523 },
14524
14525 _cacheMargins: function() {
14526 this.margins = {
14527 left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
14528 top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
14529 };
14530 },
14531
14532 _cacheHelperProportions: function() {
14533 this.helperProportions = {
14534 width: this.helper.outerWidth(),
14535 height: this.helper.outerHeight()
14536 };
14537 },
14538
14539 _setContainment: function() {
14540
14541 var ce, co, over,
14542 o = this.options;
14543 if(o.containment === "parent") {
14544 o.containment = this.helper[0].parentNode;
14545 }
14546 if(o.containment === "document" || o.containment === "window") {
14547 this.containment = [
14548 0 - this.offset.relative.left - this.offset.parent.left,
14549 0 - this.offset.relative.top - this.offset.parent.top,
14550 o.containment === "document" ? this.document.width() : this.window.width() - this.helperProportions.width - this.margins.left,
14551 (o.containment === "document" ? this.document.width() : this.window.height() || this.document[0].body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
14552 ];
14553 }
14554
14555 if(!(/^(document|window|parent)$/).test(o.containment)) {
14556 ce = $(o.containment)[0];
14557 co = $(o.containment).offset();
14558 over = ($(ce).css("overflow") !== "hidden");
14559
14560 this.containment = [
14561 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
14562 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
14563 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,
14564 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
14565 ];
14566 }
14567
14568 },
14569
14570 _convertPositionTo: function(d, pos) {
14571
14572 if(!pos) {
14573 pos = this.position;
14574 }
14575 var mod = d === "absolute" ? 1 : -1,
14576 scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,
14577 scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
14578
14579 return {
14580 top: (
14581 pos.top + // The absolute mouse position
14582 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
14583 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
14584 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
14585 ),
14586 left: (
14587 pos.left + // The absolute mouse position
14588 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
14589 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
14590 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
14591 )
14592 };
14593
14594 },
14595
14596 _generatePosition: function(event) {
14597
14598 var top, left,
14599 o = this.options,
14600 pageX = event.pageX,
14601 pageY = event.pageY,
14602 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);
14603
14604 // This is another very weird special case that only happens for relative elements:
14605 // 1. If the css position is relative
14606 // 2. and the scroll parent is the document or similar to the offset parent
14607 // we have to refresh the relative offset during the scroll so there are no jumps
14608 if(this.cssPosition === "relative" && !(this.scrollParent[0] !== this.document[0] && this.scrollParent[0] !== this.offsetParent[0])) {
14609 this.offset.relative = this._getRelativeOffset();
14610 }
14611
14612 /*
14613 * - Position constraining -
14614 * Constrain the position to a mix of grid, containment.
14615 */
14616
14617 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
14618
14619 if(this.containment) {
14620 if(event.pageX - this.offset.click.left < this.containment[0]) {
14621 pageX = this.containment[0] + this.offset.click.left;
14622 }
14623 if(event.pageY - this.offset.click.top < this.containment[1]) {
14624 pageY = this.containment[1] + this.offset.click.top;
14625 }
14626 if(event.pageX - this.offset.click.left > this.containment[2]) {
14627 pageX = this.containment[2] + this.offset.click.left;
14628 }
14629 if(event.pageY - this.offset.click.top > this.containment[3]) {
14630 pageY = this.containment[3] + this.offset.click.top;
14631 }
14632 }
14633
14634 if(o.grid) {
14635 top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
14636 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;
14637
14638 left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
14639 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;
14640 }
14641
14642 }
14643
14644 return {
14645 top: (
14646 pageY - // The absolute mouse position
14647 this.offset.click.top - // Click offset (relative to the element)
14648 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
14649 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
14650 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
14651 ),
14652 left: (
14653 pageX - // The absolute mouse position
14654 this.offset.click.left - // Click offset (relative to the element)
14655 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
14656 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
14657 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
14658 )
14659 };
14660
14661 },
14662
14663 _rearrange: function(event, i, a, hardRefresh) {
14664
14665 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));
14666
14667 //Various things done here to improve the performance:
14668 // 1. we create a setTimeout, that calls refreshPositions
14669 // 2. on the instance, we have a counter variable, that get's higher after every append
14670 // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
14671 // 4. this lets only the last addition to the timeout stack through
14672 this.counter = this.counter ? ++this.counter : 1;
14673 var counter = this.counter;
14674
14675 this._delay(function() {
14676 if(counter === this.counter) {
14677 this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
14678 }
14679 });
14680
14681 },
14682
14683 _clear: function(event, noPropagation) {
14684
14685 this.reverting = false;
14686 // We delay all events that have to be triggered to after the point where the placeholder has been removed and
14687 // everything else normalized again
14688 var i,
14689 delayedTriggers = [];
14690
14691 // We first have to update the dom position of the actual currentItem
14692 // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
14693 if(!this._noFinalSort && this.currentItem.parent().length) {
14694 this.placeholder.before(this.currentItem);
14695 }
14696 this._noFinalSort = null;
14697
14698 if(this.helper[0] === this.currentItem[0]) {
14699 for(i in this._storedCSS) {
14700 if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") {
14701 this._storedCSS[i] = "";
14702 }
14703 }
14704 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
14705 } else {
14706 this.currentItem.show();
14707 }
14708
14709 if(this.fromOutside && !noPropagation) {
14710 delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
14711 }
14712 if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) {
14713 delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
14714 }
14715
14716 // Check if the items Container has Changed and trigger appropriate
14717 // events.
14718 if (this !== this.currentContainer) {
14719 if(!noPropagation) {
14720 delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
14721 delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
14722 delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
14723 }
14724 }
14725
14726
14727 //Post events to containers
14728 function delayEvent( type, instance, container ) {
14729 return function( event ) {
14730 container._trigger( type, event, instance._uiHash( instance ) );
14731 };
14732 }
14733 for (i = this.containers.length - 1; i >= 0; i--){
14734 if (!noPropagation) {
14735 delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
14736 }
14737 if(this.containers[i].containerCache.over) {
14738 delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
14739 this.containers[i].containerCache.over = 0;
14740 }
14741 }
14742
14743 //Do what was originally in plugins
14744 if ( this.storedCursor ) {
14745 this.document.find( "body" ).css( "cursor", this.storedCursor );
14746 this.storedStylesheet.remove();
14747 }
14748 if(this._storedOpacity) {
14749 this.helper.css("opacity", this._storedOpacity);
14750 }
14751 if(this._storedZIndex) {
14752 this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex);
14753 }
14754
14755 this.dragging = false;
14756
14757 if(!noPropagation) {
14758 this._trigger("beforeStop", event, this._uiHash());
14759 }
14760
14761 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
14762 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
14763
14764 if ( !this.cancelHelperRemoval ) {
14765 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
14766 this.helper.remove();
14767 }
14768 this.helper = null;
14769 }
14770
14771 if(!noPropagation) {
14772 for (i=0; i < delayedTriggers.length; i++) {
14773 delayedTriggers[i].call(this, event);
14774 } //Trigger all delayed events
14775 this._trigger("stop", event, this._uiHash());
14776 }
14777
14778 this.fromOutside = false;
14779 return !this.cancelHelperRemoval;
14780
14781 },
14782
14783 _trigger: function() {
14784 if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
14785 this.cancel();
14786 }
14787 },
14788
14789 _uiHash: function(_inst) {
14790 var inst = _inst || this;
14791 return {
14792 helper: inst.helper,
14793 placeholder: inst.placeholder || $([]),
14794 position: inst.position,
14795 originalPosition: inst.originalPosition,
14796 offset: inst.positionAbs,
14797 item: inst.currentItem,
14798 sender: _inst ? _inst.element : null
14799 };
14800 }
14801
14802 });
14803
14804
14805 /*!
14806 * jQuery UI Spinner 1.11.4
14807 * http://jqueryui.com
14808 *
14809 * Copyright jQuery Foundation and other contributors
14810 * Released under the MIT license.
14811 * http://jquery.org/license
14812 *
14813 * http://api.jqueryui.com/spinner/
14814 */
14815
14816
14817 function spinner_modifier( fn ) {
14818 return function() {
14819 var previous = this.element.val();
14820 fn.apply( this, arguments );
14821 this._refresh();
14822 if ( previous !== this.element.val() ) {
14823 this._trigger( "change" );
14824 }
14825 };
14826 }
14827
14828 var spinner = $.widget( "ui.spinner", {
14829 version: "1.11.4",
14830 defaultElement: "<input>",
14831 widgetEventPrefix: "spin",
14832 options: {
14833 culture: null,
14834 icons: {
14835 down: "ui-icon-triangle-1-s",
14836 up: "ui-icon-triangle-1-n"
14837 },
14838 incremental: true,
14839 max: null,
14840 min: null,
14841 numberFormat: null,
14842 page: 10,
14843 step: 1,
14844
14845 change: null,
14846 spin: null,
14847 start: null,
14848 stop: null
14849 },
14850
14851 _create: function() {
14852 // handle string values that need to be parsed
14853 this._setOption( "max", this.options.max );
14854 this._setOption( "min", this.options.min );
14855 this._setOption( "step", this.options.step );
14856
14857 // Only format if there is a value, prevents the field from being marked
14858 // as invalid in Firefox, see #9573.
14859 if ( this.value() !== "" ) {
14860 // Format the value, but don't constrain.
14861 this._value( this.element.val(), true );
14862 }
14863
14864 this._draw();
14865 this._on( this._events );
14866 this._refresh();
14867
14868 // turning off autocomplete prevents the browser from remembering the
14869 // value when navigating through history, so we re-enable autocomplete
14870 // if the page is unloaded before the widget is destroyed. #7790
14871 this._on( this.window, {
14872 beforeunload: function() {
14873 this.element.removeAttr( "autocomplete" );
14874 }
14875 });
14876 },
14877
14878 _getCreateOptions: function() {
14879 var options = {},
14880 element = this.element;
14881
14882 $.each( [ "min", "max", "step" ], function( i, option ) {
14883 var value = element.attr( option );
14884 if ( value !== undefined && value.length ) {
14885 options[ option ] = value;
14886 }
14887 });
14888
14889 return options;
14890 },
14891
14892 _events: {
14893 keydown: function( event ) {
14894 if ( this._start( event ) && this._keydown( event ) ) {
14895 event.preventDefault();
14896 }
14897 },
14898 keyup: "_stop",
14899 focus: function() {
14900 this.previous = this.element.val();
14901 },
14902 blur: function( event ) {
14903 if ( this.cancelBlur ) {
14904 delete this.cancelBlur;
14905 return;
14906 }
14907
14908 this._stop();
14909 this._refresh();
14910 if ( this.previous !== this.element.val() ) {
14911 this._trigger( "change", event );
14912 }
14913 },
14914 mousewheel: function( event, delta ) {
14915 if ( !delta ) {
14916 return;
14917 }
14918 if ( !this.spinning && !this._start( event ) ) {
14919 return false;
14920 }
14921
14922 this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
14923 clearTimeout( this.mousewheelTimer );
14924 this.mousewheelTimer = this._delay(function() {
14925 if ( this.spinning ) {
14926 this._stop( event );
14927 }
14928 }, 100 );
14929 event.preventDefault();
14930 },
14931 "mousedown .ui-spinner-button": function( event ) {
14932 var previous;
14933
14934 // We never want the buttons to have focus; whenever the user is
14935 // interacting with the spinner, the focus should be on the input.
14936 // If the input is focused then this.previous is properly set from
14937 // when the input first received focus. If the input is not focused
14938 // then we need to set this.previous based on the value before spinning.
14939 previous = this.element[0] === this.document[0].activeElement ?
14940 this.previous : this.element.val();
14941 function checkFocus() {
14942 var isActive = this.element[0] === this.document[0].activeElement;
14943 if ( !isActive ) {
14944 this.element.focus();
14945 this.previous = previous;
14946 // support: IE
14947 // IE sets focus asynchronously, so we need to check if focus
14948 // moved off of the input because the user clicked on the button.
14949 this._delay(function() {
14950 this.previous = previous;
14951 });
14952 }
14953 }
14954
14955 // ensure focus is on (or stays on) the text field
14956 event.preventDefault();
14957 checkFocus.call( this );
14958
14959 // support: IE
14960 // IE doesn't prevent moving focus even with event.preventDefault()
14961 // so we set a flag to know when we should ignore the blur event
14962 // and check (again) if focus moved off of the input.
14963 this.cancelBlur = true;
14964 this._delay(function() {
14965 delete this.cancelBlur;
14966 checkFocus.call( this );
14967 });
14968
14969 if ( this._start( event ) === false ) {
14970 return;
14971 }
14972
14973 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
14974 },
14975 "mouseup .ui-spinner-button": "_stop",
14976 "mouseenter .ui-spinner-button": function( event ) {
14977 // button will add ui-state-active if mouse was down while mouseleave and kept down
14978 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
14979 return;
14980 }
14981
14982 if ( this._start( event ) === false ) {
14983 return false;
14984 }
14985 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
14986 },
14987 // TODO: do we really want to consider this a stop?
14988 // shouldn't we just stop the repeater and wait until mouseup before
14989 // we trigger the stop event?
14990 "mouseleave .ui-spinner-button": "_stop"
14991 },
14992
14993 _draw: function() {
14994 var uiSpinner = this.uiSpinner = this.element
14995 .addClass( "ui-spinner-input" )
14996 .attr( "autocomplete", "off" )
14997 .wrap( this._uiSpinnerHtml() )
14998 .parent()
14999 // add buttons
15000 .append( this._buttonHtml() );
15001
15002 this.element.attr( "role", "spinbutton" );
15003
15004 // button bindings
15005 this.buttons = uiSpinner.find( ".ui-spinner-button" )
15006 .attr( "tabIndex", -1 )
15007 .button()
15008 .removeClass( "ui-corner-all" );
15009
15010 // IE 6 doesn't understand height: 50% for the buttons
15011 // unless the wrapper has an explicit height
15012 if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&
15013 uiSpinner.height() > 0 ) {
15014 uiSpinner.height( uiSpinner.height() );
15015 }
15016
15017 // disable spinner if element was already disabled
15018 if ( this.options.disabled ) {
15019 this.disable();
15020 }
15021 },
15022
15023 _keydown: function( event ) {
15024 var options = this.options,
15025 keyCode = $.ui.keyCode;
15026
15027 switch ( event.keyCode ) {
15028 case keyCode.UP:
15029 this._repeat( null, 1, event );
15030 return true;
15031 case keyCode.DOWN:
15032 this._repeat( null, -1, event );
15033 return true;
15034 case keyCode.PAGE_UP:
15035 this._repeat( null, options.page, event );
15036 return true;
15037 case keyCode.PAGE_DOWN:
15038 this._repeat( null, -options.page, event );
15039 return true;
15040 }
15041
15042 return false;
15043 },
15044
15045 _uiSpinnerHtml: function() {
15046 return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>";
15047 },
15048
15049 _buttonHtml: function() {
15050 return "" +
15051 "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" +
15052 "<span class='ui-icon " + this.options.icons.up + "'>&#9650;</span>" +
15053 "</a>" +
15054 "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" +
15055 "<span class='ui-icon " + this.options.icons.down + "'>&#9660;</span>" +
15056 "</a>";
15057 },
15058
15059 _start: function( event ) {
15060 if ( !this.spinning && this._trigger( "start", event ) === false ) {
15061 return false;
15062 }
15063
15064 if ( !this.counter ) {
15065 this.counter = 1;
15066 }
15067 this.spinning = true;
15068 return true;
15069 },
15070
15071 _repeat: function( i, steps, event ) {
15072 i = i || 500;
15073
15074 clearTimeout( this.timer );
15075 this.timer = this._delay(function() {
15076 this._repeat( 40, steps, event );
15077 }, i );
15078
15079 this._spin( steps * this.options.step, event );
15080 },
15081
15082 _spin: function( step, event ) {
15083 var value = this.value() || 0;
15084
15085 if ( !this.counter ) {
15086 this.counter = 1;
15087 }
15088
15089 value = this._adjustValue( value + step * this._increment( this.counter ) );
15090
15091 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) {
15092 this._value( value );
15093 this.counter++;
15094 }
15095 },
15096
15097 _increment: function( i ) {
15098 var incremental = this.options.incremental;
15099
15100 if ( incremental ) {
15101 return $.isFunction( incremental ) ?
15102 incremental( i ) :
15103 Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 );
15104 }
15105
15106 return 1;
15107 },
15108
15109 _precision: function() {
15110 var precision = this._precisionOf( this.options.step );
15111 if ( this.options.min !== null ) {
15112 precision = Math.max( precision, this._precisionOf( this.options.min ) );
15113 }
15114 return precision;
15115 },
15116
15117 _precisionOf: function( num ) {
15118 var str = num.toString(),
15119 decimal = str.indexOf( "." );
15120 return decimal === -1 ? 0 : str.length - decimal - 1;
15121 },
15122
15123 _adjustValue: function( value ) {
15124 var base, aboveMin,
15125 options = this.options;
15126
15127 // make sure we're at a valid step
15128 // - find out where we are relative to the base (min or 0)
15129 base = options.min !== null ? options.min : 0;
15130 aboveMin = value - base;
15131 // - round to the nearest step
15132 aboveMin = Math.round(aboveMin / options.step) * options.step;
15133 // - rounding is based on 0, so adjust back to our base
15134 value = base + aboveMin;
15135
15136 // fix precision from bad JS floating point math
15137 value = parseFloat( value.toFixed( this._precision() ) );
15138
15139 // clamp the value
15140 if ( options.max !== null && value > options.max) {
15141 return options.max;
15142 }
15143 if ( options.min !== null && value < options.min ) {
15144 return options.min;
15145 }
15146
15147 return value;
15148 },
15149
15150 _stop: function( event ) {
15151 if ( !this.spinning ) {
15152 return;
15153 }
15154
15155 clearTimeout( this.timer );
15156 clearTimeout( this.mousewheelTimer );
15157 this.counter = 0;
15158 this.spinning = false;
15159 this._trigger( "stop", event );
15160 },
15161
15162 _setOption: function( key, value ) {
15163 if ( key === "culture" || key === "numberFormat" ) {
15164 var prevValue = this._parse( this.element.val() );
15165 this.options[ key ] = value;
15166 this.element.val( this._format( prevValue ) );
15167 return;
15168 }
15169
15170 if ( key === "max" || key === "min" || key === "step" ) {
15171 if ( typeof value === "string" ) {
15172 value = this._parse( value );
15173 }
15174 }
15175 if ( key === "icons" ) {
15176 this.buttons.first().find( ".ui-icon" )
15177 .removeClass( this.options.icons.up )
15178 .addClass( value.up );
15179 this.buttons.last().find( ".ui-icon" )
15180 .removeClass( this.options.icons.down )
15181 .addClass( value.down );
15182 }
15183
15184 this._super( key, value );
15185
15186 if ( key === "disabled" ) {
15187 this.widget().toggleClass( "ui-state-disabled", !!value );
15188 this.element.prop( "disabled", !!value );
15189 this.buttons.button( value ? "disable" : "enable" );
15190 }
15191 },
15192
15193 _setOptions: spinner_modifier(function( options ) {
15194 this._super( options );
15195 }),
15196
15197 _parse: function( val ) {
15198 if ( typeof val === "string" && val !== "" ) {
15199 val = window.Globalize && this.options.numberFormat ?
15200 Globalize.parseFloat( val, 10, this.options.culture ) : +val;
15201 }
15202 return val === "" || isNaN( val ) ? null : val;
15203 },
15204
15205 _format: function( value ) {
15206 if ( value === "" ) {
15207 return "";
15208 }
15209 return window.Globalize && this.options.numberFormat ?
15210 Globalize.format( value, this.options.numberFormat, this.options.culture ) :
15211 value;
15212 },
15213
15214 _refresh: function() {
15215 this.element.attr({
15216 "aria-valuemin": this.options.min,
15217 "aria-valuemax": this.options.max,
15218 // TODO: what should we do with values that can't be parsed?
15219 "aria-valuenow": this._parse( this.element.val() )
15220 });
15221 },
15222
15223 isValid: function() {
15224 var value = this.value();
15225
15226 // null is invalid
15227 if ( value === null ) {
15228 return false;
15229 }
15230
15231 // if value gets adjusted, it's invalid
15232 return value === this._adjustValue( value );
15233 },
15234
15235 // update the value without triggering change
15236 _value: function( value, allowAny ) {
15237 var parsed;
15238 if ( value !== "" ) {
15239 parsed = this._parse( value );
15240 if ( parsed !== null ) {
15241 if ( !allowAny ) {
15242 parsed = this._adjustValue( parsed );
15243 }
15244 value = this._format( parsed );
15245 }
15246 }
15247 this.element.val( value );
15248 this._refresh();
15249 },
15250
15251 _destroy: function() {
15252 this.element
15253 .removeClass( "ui-spinner-input" )
15254 .prop( "disabled", false )
15255 .removeAttr( "autocomplete" )
15256 .removeAttr( "role" )
15257 .removeAttr( "aria-valuemin" )
15258 .removeAttr( "aria-valuemax" )
15259 .removeAttr( "aria-valuenow" );
15260 this.uiSpinner.replaceWith( this.element );
15261 },
15262
15263 stepUp: spinner_modifier(function( steps ) {
15264 this._stepUp( steps );
15265 }),
15266 _stepUp: function( steps ) {
15267 if ( this._start() ) {
15268 this._spin( (steps || 1) * this.options.step );
15269 this._stop();
15270 }
15271 },
15272
15273 stepDown: spinner_modifier(function( steps ) {
15274 this._stepDown( steps );
15275 }),
15276 _stepDown: function( steps ) {
15277 if ( this._start() ) {
15278 this._spin( (steps || 1) * -this.options.step );
15279 this._stop();
15280 }
15281 },
15282
15283 pageUp: spinner_modifier(function( pages ) {
15284 this._stepUp( (pages || 1) * this.options.page );
15285 }),
15286
15287 pageDown: spinner_modifier(function( pages ) {
15288 this._stepDown( (pages || 1) * this.options.page );
15289 }),
15290
15291 value: function( newVal ) {
15292 if ( !arguments.length ) {
15293 return this._parse( this.element.val() );
15294 }
15295 spinner_modifier( this._value ).call( this, newVal );
15296 },
15297
15298 widget: function() {
15299 return this.uiSpinner;
15300 }
15301 });
15302
15303
15304 /*!
15305 * jQuery UI Tabs 1.11.4
15306 * http://jqueryui.com
15307 *
15308 * Copyright jQuery Foundation and other contributors
15309 * Released under the MIT license.
15310 * http://jquery.org/license
15311 *
15312 * http://api.jqueryui.com/tabs/
15313 */
15314
15315
15316 var tabs = $.widget( "ui.tabs", {
15317 version: "1.11.4",
15318 delay: 300,
15319 options: {
15320 active: null,
15321 collapsible: false,
15322 event: "click",
15323 heightStyle: "content",
15324 hide: null,
15325 show: null,
15326
15327 // callbacks
15328 activate: null,
15329 beforeActivate: null,
15330 beforeLoad: null,
15331 load: null
15332 },
15333
15334 _isLocal: (function() {
15335 var rhash = /#.*$/;
15336
15337 return function( anchor ) {
15338 var anchorUrl, locationUrl;
15339
15340 // support: IE7
15341 // IE7 doesn't normalize the href property when set via script (#9317)
15342 anchor = anchor.cloneNode( false );
15343
15344 anchorUrl = anchor.href.replace( rhash, "" );
15345 locationUrl = location.href.replace( rhash, "" );
15346
15347 // decoding may throw an error if the URL isn't UTF-8 (#9518)
15348 try {
15349 anchorUrl = decodeURIComponent( anchorUrl );
15350 } catch ( error ) {}
15351 try {
15352 locationUrl = decodeURIComponent( locationUrl );
15353 } catch ( error ) {}
15354
15355 return anchor.hash.length > 1 && anchorUrl === locationUrl;
15356 };
15357 })(),
15358
15359 _create: function() {
15360 var that = this,
15361 options = this.options;
15362
15363 this.running = false;
15364
15365 this.element
15366 .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" )
15367 .toggleClass( "ui-tabs-collapsible", options.collapsible );
15368
15369 this._processTabs();
15370 options.active = this._initialActive();
15371
15372 // Take disabling tabs via class attribute from HTML
15373 // into account and update option properly.
15374 if ( $.isArray( options.disabled ) ) {
15375 options.disabled = $.unique( options.disabled.concat(
15376 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
15377 return that.tabs.index( li );
15378 })
15379 ) ).sort();
15380 }
15381
15382 // check for length avoids error when initializing empty list
15383 if ( this.options.active !== false && this.anchors.length ) {
15384 this.active = this._findActive( options.active );
15385 } else {
15386 this.active = $();
15387 }
15388
15389 this._refresh();
15390
15391 if ( this.active.length ) {
15392 this.load( options.active );
15393 }
15394 },
15395
15396 _initialActive: function() {
15397 var active = this.options.active,
15398 collapsible = this.options.collapsible,
15399 locationHash = location.hash.substring( 1 );
15400
15401 if ( active === null ) {
15402 // check the fragment identifier in the URL
15403 if ( locationHash ) {
15404 this.tabs.each(function( i, tab ) {
15405 if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
15406 active = i;
15407 return false;
15408 }
15409 });
15410 }
15411
15412 // check for a tab marked active via a class
15413 if ( active === null ) {
15414 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
15415 }
15416
15417 // no active tab, set to false
15418 if ( active === null || active === -1 ) {
15419 active = this.tabs.length ? 0 : false;
15420 }
15421 }
15422
15423 // handle numbers: negative, out of range
15424 if ( active !== false ) {
15425 active = this.tabs.index( this.tabs.eq( active ) );
15426 if ( active === -1 ) {
15427 active = collapsible ? false : 0;
15428 }
15429 }
15430
15431 // don't allow collapsible: false and active: false
15432 if ( !collapsible && active === false && this.anchors.length ) {
15433 active = 0;
15434 }
15435
15436 return active;
15437 },
15438
15439 _getCreateEventData: function() {
15440 return {
15441 tab: this.active,
15442 panel: !this.active.length ? $() : this._getPanelForTab( this.active )
15443 };
15444 },
15445
15446 _tabKeydown: function( event ) {
15447 var focusedTab = $( this.document[0].activeElement ).closest( "li" ),
15448 selectedIndex = this.tabs.index( focusedTab ),
15449 goingForward = true;
15450
15451 if ( this._handlePageNav( event ) ) {
15452 return;
15453 }
15454
15455 switch ( event.keyCode ) {
15456 case $.ui.keyCode.RIGHT:
15457 case $.ui.keyCode.DOWN:
15458 selectedIndex++;
15459 break;
15460 case $.ui.keyCode.UP:
15461 case $.ui.keyCode.LEFT:
15462 goingForward = false;
15463 selectedIndex--;
15464 break;
15465 case $.ui.keyCode.END:
15466 selectedIndex = this.anchors.length - 1;
15467 break;
15468 case $.ui.keyCode.HOME:
15469 selectedIndex = 0;
15470 break;
15471 case $.ui.keyCode.SPACE:
15472 // Activate only, no collapsing
15473 event.preventDefault();
15474 clearTimeout( this.activating );
15475 this._activate( selectedIndex );
15476 return;
15477 case $.ui.keyCode.ENTER:
15478 // Toggle (cancel delayed activation, allow collapsing)
15479 event.preventDefault();
15480 clearTimeout( this.activating );
15481 // Determine if we should collapse or activate
15482 this._activate( selectedIndex === this.options.active ? false : selectedIndex );
15483 return;
15484 default:
15485 return;
15486 }
15487
15488 // Focus the appropriate tab, based on which key was pressed
15489 event.preventDefault();
15490 clearTimeout( this.activating );
15491 selectedIndex = this._focusNextTab( selectedIndex, goingForward );
15492
15493 // Navigating with control/command key will prevent automatic activation
15494 if ( !event.ctrlKey && !event.metaKey ) {
15495
15496 // Update aria-selected immediately so that AT think the tab is already selected.
15497 // Otherwise AT may confuse the user by stating that they need to activate the tab,
15498 // but the tab will already be activated by the time the announcement finishes.
15499 focusedTab.attr( "aria-selected", "false" );
15500 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
15501
15502 this.activating = this._delay(function() {
15503 this.option( "active", selectedIndex );
15504 }, this.delay );
15505 }
15506 },
15507
15508 _panelKeydown: function( event ) {
15509 if ( this._handlePageNav( event ) ) {
15510 return;
15511 }
15512
15513 // Ctrl+up moves focus to the current tab
15514 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
15515 event.preventDefault();
15516 this.active.focus();
15517 }
15518 },
15519
15520 // Alt+page up/down moves focus to the previous/next tab (and activates)
15521 _handlePageNav: function( event ) {
15522 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
15523 this._activate( this._focusNextTab( this.options.active - 1, false ) );
15524 return true;
15525 }
15526 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
15527 this._activate( this._focusNextTab( this.options.active + 1, true ) );
15528 return true;
15529 }
15530 },
15531
15532 _findNextTab: function( index, goingForward ) {
15533 var lastTabIndex = this.tabs.length - 1;
15534
15535 function constrain() {
15536 if ( index > lastTabIndex ) {
15537 index = 0;
15538 }
15539 if ( index < 0 ) {
15540 index = lastTabIndex;
15541 }
15542 return index;
15543 }
15544
15545 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
15546 index = goingForward ? index + 1 : index - 1;
15547 }
15548
15549 return index;
15550 },
15551
15552 _focusNextTab: function( index, goingForward ) {
15553 index = this._findNextTab( index, goingForward );
15554 this.tabs.eq( index ).focus();
15555 return index;
15556 },
15557
15558 _setOption: function( key, value ) {
15559 if ( key === "active" ) {
15560 // _activate() will handle invalid values and update this.options
15561 this._activate( value );
15562 return;
15563 }
15564
15565 if ( key === "disabled" ) {
15566 // don't use the widget factory's disabled handling
15567 this._setupDisabled( value );
15568 return;
15569 }
15570
15571 this._super( key, value);
15572
15573 if ( key === "collapsible" ) {
15574 this.element.toggleClass( "ui-tabs-collapsible", value );
15575 // Setting collapsible: false while collapsed; open first panel
15576 if ( !value && this.options.active === false ) {
15577 this._activate( 0 );
15578 }
15579 }
15580
15581 if ( key === "event" ) {
15582 this._setupEvents( value );
15583 }
15584
15585 if ( key === "heightStyle" ) {
15586 this._setupHeightStyle( value );
15587 }
15588 },
15589
15590 _sanitizeSelector: function( hash ) {
15591 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
15592 },
15593
15594 refresh: function() {
15595 var options = this.options,
15596 lis = this.tablist.children( ":has(a[href])" );
15597
15598 // get disabled tabs from class attribute from HTML
15599 // this will get converted to a boolean if needed in _refresh()
15600 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
15601 return lis.index( tab );
15602 });
15603
15604 this._processTabs();
15605
15606 // was collapsed or no tabs
15607 if ( options.active === false || !this.anchors.length ) {
15608 options.active = false;
15609 this.active = $();
15610 // was active, but active tab is gone
15611 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
15612 // all remaining tabs are disabled
15613 if ( this.tabs.length === options.disabled.length ) {
15614 options.active = false;
15615 this.active = $();
15616 // activate previous tab
15617 } else {
15618 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
15619 }
15620 // was active, active tab still exists
15621 } else {
15622 // make sure active index is correct
15623 options.active = this.tabs.index( this.active );
15624 }
15625
15626 this._refresh();
15627 },
15628
15629 _refresh: function() {
15630 this._setupDisabled( this.options.disabled );
15631 this._setupEvents( this.options.event );
15632 this._setupHeightStyle( this.options.heightStyle );
15633
15634 this.tabs.not( this.active ).attr({
15635 "aria-selected": "false",
15636 "aria-expanded": "false",
15637 tabIndex: -1
15638 });
15639 this.panels.not( this._getPanelForTab( this.active ) )
15640 .hide()
15641 .attr({
15642 "aria-hidden": "true"
15643 });
15644
15645 // Make sure one tab is in the tab order
15646 if ( !this.active.length ) {
15647 this.tabs.eq( 0 ).attr( "tabIndex", 0 );
15648 } else {
15649 this.active
15650 .addClass( "ui-tabs-active ui-state-active" )
15651 .attr({
15652 "aria-selected": "true",
15653 "aria-expanded": "true",
15654 tabIndex: 0
15655 });
15656 this._getPanelForTab( this.active )
15657 .show()
15658 .attr({
15659 "aria-hidden": "false"
15660 });
15661 }
15662 },
15663
15664 _processTabs: function() {
15665 var that = this,
15666 prevTabs = this.tabs,
15667 prevAnchors = this.anchors,
15668 prevPanels = this.panels;
15669
15670 this.tablist = this._getList()
15671 .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
15672 .attr( "role", "tablist" )
15673
15674 // Prevent users from focusing disabled tabs via click
15675 .delegate( "> li", "mousedown" + this.eventNamespace, function( event ) {
15676 if ( $( this ).is( ".ui-state-disabled" ) ) {
15677 event.preventDefault();
15678 }
15679 })
15680
15681 // support: IE <9
15682 // Preventing the default action in mousedown doesn't prevent IE
15683 // from focusing the element, so if the anchor gets focused, blur.
15684 // We don't have to worry about focusing the previously focused
15685 // element since clicking on a non-focusable element should focus
15686 // the body anyway.
15687 .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() {
15688 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
15689 this.blur();
15690 }
15691 });
15692
15693 this.tabs = this.tablist.find( "> li:has(a[href])" )
15694 .addClass( "ui-state-default ui-corner-top" )
15695 .attr({
15696 role: "tab",
15697 tabIndex: -1
15698 });
15699
15700 this.anchors = this.tabs.map(function() {
15701 return $( "a", this )[ 0 ];
15702 })
15703 .addClass( "ui-tabs-anchor" )
15704 .attr({
15705 role: "presentation",
15706 tabIndex: -1
15707 });
15708
15709 this.panels = $();
15710
15711 this.anchors.each(function( i, anchor ) {
15712 var selector, panel, panelId,
15713 anchorId = $( anchor ).uniqueId().attr( "id" ),
15714 tab = $( anchor ).closest( "li" ),
15715 originalAriaControls = tab.attr( "aria-controls" );
15716
15717 // inline tab
15718 if ( that._isLocal( anchor ) ) {
15719 selector = anchor.hash;
15720 panelId = selector.substring( 1 );
15721 panel = that.element.find( that._sanitizeSelector( selector ) );
15722 // remote tab
15723 } else {
15724 // If the tab doesn't already have aria-controls,
15725 // generate an id by using a throw-away element
15726 panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
15727 selector = "#" + panelId;
15728 panel = that.element.find( selector );
15729 if ( !panel.length ) {
15730 panel = that._createPanel( panelId );
15731 panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
15732 }
15733 panel.attr( "aria-live", "polite" );
15734 }
15735
15736 if ( panel.length) {
15737 that.panels = that.panels.add( panel );
15738 }
15739 if ( originalAriaControls ) {
15740 tab.data( "ui-tabs-aria-controls", originalAriaControls );
15741 }
15742 tab.attr({
15743 "aria-controls": panelId,
15744 "aria-labelledby": anchorId
15745 });
15746 panel.attr( "aria-labelledby", anchorId );
15747 });
15748
15749 this.panels
15750 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
15751 .attr( "role", "tabpanel" );
15752
15753 // Avoid memory leaks (#10056)
15754 if ( prevTabs ) {
15755 this._off( prevTabs.not( this.tabs ) );
15756 this._off( prevAnchors.not( this.anchors ) );
15757 this._off( prevPanels.not( this.panels ) );
15758 }
15759 },
15760
15761 // allow overriding how to find the list for rare usage scenarios (#7715)
15762 _getList: function() {
15763 return this.tablist || this.element.find( "ol,ul" ).eq( 0 );
15764 },
15765
15766 _createPanel: function( id ) {
15767 return $( "<div>" )
15768 .attr( "id", id )
15769 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
15770 .data( "ui-tabs-destroy", true );
15771 },
15772
15773 _setupDisabled: function( disabled ) {
15774 if ( $.isArray( disabled ) ) {
15775 if ( !disabled.length ) {
15776 disabled = false;
15777 } else if ( disabled.length === this.anchors.length ) {
15778 disabled = true;
15779 }
15780 }
15781
15782 // disable tabs
15783 for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {
15784 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
15785 $( li )
15786 .addClass( "ui-state-disabled" )
15787 .attr( "aria-disabled", "true" );
15788 } else {
15789 $( li )
15790 .removeClass( "ui-state-disabled" )
15791 .removeAttr( "aria-disabled" );
15792 }
15793 }
15794
15795 this.options.disabled = disabled;
15796 },
15797
15798 _setupEvents: function( event ) {
15799 var events = {};
15800 if ( event ) {
15801 $.each( event.split(" "), function( index, eventName ) {
15802 events[ eventName ] = "_eventHandler";
15803 });
15804 }
15805
15806 this._off( this.anchors.add( this.tabs ).add( this.panels ) );
15807 // Always prevent the default action, even when disabled
15808 this._on( true, this.anchors, {
15809 click: function( event ) {
15810 event.preventDefault();
15811 }
15812 });
15813 this._on( this.anchors, events );
15814 this._on( this.tabs, { keydown: "_tabKeydown" } );
15815 this._on( this.panels, { keydown: "_panelKeydown" } );
15816
15817 this._focusable( this.tabs );
15818 this._hoverable( this.tabs );
15819 },
15820
15821 _setupHeightStyle: function( heightStyle ) {
15822 var maxHeight,
15823 parent = this.element.parent();
15824
15825 if ( heightStyle === "fill" ) {
15826 maxHeight = parent.height();
15827 maxHeight -= this.element.outerHeight() - this.element.height();
15828
15829 this.element.siblings( ":visible" ).each(function() {
15830 var elem = $( this ),
15831 position = elem.css( "position" );
15832
15833 if ( position === "absolute" || position === "fixed" ) {
15834 return;
15835 }
15836 maxHeight -= elem.outerHeight( true );
15837 });
15838
15839 this.element.children().not( this.panels ).each(function() {
15840 maxHeight -= $( this ).outerHeight( true );
15841 });
15842
15843 this.panels.each(function() {
15844 $( this ).height( Math.max( 0, maxHeight -
15845 $( this ).innerHeight() + $( this ).height() ) );
15846 })
15847 .css( "overflow", "auto" );
15848 } else if ( heightStyle === "auto" ) {
15849 maxHeight = 0;
15850 this.panels.each(function() {
15851 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
15852 }).height( maxHeight );
15853 }
15854 },
15855
15856 _eventHandler: function( event ) {
15857 var options = this.options,
15858 active = this.active,
15859 anchor = $( event.currentTarget ),
15860 tab = anchor.closest( "li" ),
15861 clickedIsActive = tab[ 0 ] === active[ 0 ],
15862 collapsing = clickedIsActive && options.collapsible,
15863 toShow = collapsing ? $() : this._getPanelForTab( tab ),
15864 toHide = !active.length ? $() : this._getPanelForTab( active ),
15865 eventData = {
15866 oldTab: active,
15867 oldPanel: toHide,
15868 newTab: collapsing ? $() : tab,
15869 newPanel: toShow
15870 };
15871
15872 event.preventDefault();
15873
15874 if ( tab.hasClass( "ui-state-disabled" ) ||
15875 // tab is already loading
15876 tab.hasClass( "ui-tabs-loading" ) ||
15877 // can't switch durning an animation
15878 this.running ||
15879 // click on active header, but not collapsible
15880 ( clickedIsActive && !options.collapsible ) ||
15881 // allow canceling activation
15882 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
15883 return;
15884 }
15885
15886 options.active = collapsing ? false : this.tabs.index( tab );
15887
15888 this.active = clickedIsActive ? $() : tab;
15889 if ( this.xhr ) {
15890 this.xhr.abort();
15891 }
15892
15893 if ( !toHide.length && !toShow.length ) {
15894 $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
15895 }
15896
15897 if ( toShow.length ) {
15898 this.load( this.tabs.index( tab ), event );
15899 }
15900 this._toggle( event, eventData );
15901 },
15902
15903 // handles show/hide for selecting tabs
15904 _toggle: function( event, eventData ) {
15905 var that = this,
15906 toShow = eventData.newPanel,
15907 toHide = eventData.oldPanel;
15908
15909 this.running = true;
15910
15911 function complete() {
15912 that.running = false;
15913 that._trigger( "activate", event, eventData );
15914 }
15915
15916 function show() {
15917 eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
15918
15919 if ( toShow.length && that.options.show ) {
15920 that._show( toShow, that.options.show, complete );
15921 } else {
15922 toShow.show();
15923 complete();
15924 }
15925 }
15926
15927 // start out by hiding, then showing, then completing
15928 if ( toHide.length && this.options.hide ) {
15929 this._hide( toHide, this.options.hide, function() {
15930 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
15931 show();
15932 });
15933 } else {
15934 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
15935 toHide.hide();
15936 show();
15937 }
15938
15939 toHide.attr( "aria-hidden", "true" );
15940 eventData.oldTab.attr({
15941 "aria-selected": "false",
15942 "aria-expanded": "false"
15943 });
15944 // If we're switching tabs, remove the old tab from the tab order.
15945 // If we're opening from collapsed state, remove the previous tab from the tab order.
15946 // If we're collapsing, then keep the collapsing tab in the tab order.
15947 if ( toShow.length && toHide.length ) {
15948 eventData.oldTab.attr( "tabIndex", -1 );
15949 } else if ( toShow.length ) {
15950 this.tabs.filter(function() {
15951 return $( this ).attr( "tabIndex" ) === 0;
15952 })
15953 .attr( "tabIndex", -1 );
15954 }
15955
15956 toShow.attr( "aria-hidden", "false" );
15957 eventData.newTab.attr({
15958 "aria-selected": "true",
15959 "aria-expanded": "true",
15960 tabIndex: 0
15961 });
15962 },
15963
15964 _activate: function( index ) {
15965 var anchor,
15966 active = this._findActive( index );
15967
15968 // trying to activate the already active panel
15969 if ( active[ 0 ] === this.active[ 0 ] ) {
15970 return;
15971 }
15972
15973 // trying to collapse, simulate a click on the current active header
15974 if ( !active.length ) {
15975 active = this.active;
15976 }
15977
15978 anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
15979 this._eventHandler({
15980 target: anchor,
15981 currentTarget: anchor,
15982 preventDefault: $.noop
15983 });
15984 },
15985
15986 _findActive: function( index ) {
15987 return index === false ? $() : this.tabs.eq( index );
15988 },
15989
15990 _getIndex: function( index ) {
15991 // meta-function to give users option to provide a href string instead of a numerical index.
15992 if ( typeof index === "string" ) {
15993 index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) );
15994 }
15995
15996 return index;
15997 },
15998
15999 _destroy: function() {
16000 if ( this.xhr ) {
16001 this.xhr.abort();
16002 }
16003
16004 this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" );
16005
16006 this.tablist
16007 .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
16008 .removeAttr( "role" );
16009
16010 this.anchors
16011 .removeClass( "ui-tabs-anchor" )
16012 .removeAttr( "role" )
16013 .removeAttr( "tabIndex" )
16014 .removeUniqueId();
16015
16016 this.tablist.unbind( this.eventNamespace );
16017
16018 this.tabs.add( this.panels ).each(function() {
16019 if ( $.data( this, "ui-tabs-destroy" ) ) {
16020 $( this ).remove();
16021 } else {
16022 $( this )
16023 .removeClass( "ui-state-default ui-state-active ui-state-disabled " +
16024 "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" )
16025 .removeAttr( "tabIndex" )
16026 .removeAttr( "aria-live" )
16027 .removeAttr( "aria-busy" )
16028 .removeAttr( "aria-selected" )
16029 .removeAttr( "aria-labelledby" )
16030 .removeAttr( "aria-hidden" )
16031 .removeAttr( "aria-expanded" )
16032 .removeAttr( "role" );
16033 }
16034 });
16035
16036 this.tabs.each(function() {
16037 var li = $( this ),
16038 prev = li.data( "ui-tabs-aria-controls" );
16039 if ( prev ) {
16040 li
16041 .attr( "aria-controls", prev )
16042 .removeData( "ui-tabs-aria-controls" );
16043 } else {
16044 li.removeAttr( "aria-controls" );
16045 }
16046 });
16047
16048 this.panels.show();
16049
16050 if ( this.options.heightStyle !== "content" ) {
16051 this.panels.css( "height", "" );
16052 }
16053 },
16054
16055 enable: function( index ) {
16056 var disabled = this.options.disabled;
16057 if ( disabled === false ) {
16058 return;
16059 }
16060
16061 if ( index === undefined ) {
16062 disabled = false;
16063 } else {
16064 index = this._getIndex( index );
16065 if ( $.isArray( disabled ) ) {
16066 disabled = $.map( disabled, function( num ) {
16067 return num !== index ? num : null;
16068 });
16069 } else {
16070 disabled = $.map( this.tabs, function( li, num ) {
16071 return num !== index ? num : null;
16072 });
16073 }
16074 }
16075 this._setupDisabled( disabled );
16076 },
16077
16078 disable: function( index ) {
16079 var disabled = this.options.disabled;
16080 if ( disabled === true ) {
16081 return;
16082 }
16083
16084 if ( index === undefined ) {
16085 disabled = true;
16086 } else {
16087 index = this._getIndex( index );
16088 if ( $.inArray( index, disabled ) !== -1 ) {
16089 return;
16090 }
16091 if ( $.isArray( disabled ) ) {
16092 disabled = $.merge( [ index ], disabled ).sort();
16093 } else {
16094 disabled = [ index ];
16095 }
16096 }
16097 this._setupDisabled( disabled );
16098 },
16099
16100 load: function( index, event ) {
16101 index = this._getIndex( index );
16102 var that = this,
16103 tab = this.tabs.eq( index ),
16104 anchor = tab.find( ".ui-tabs-anchor" ),
16105 panel = this._getPanelForTab( tab ),
16106 eventData = {
16107 tab: tab,
16108 panel: panel
16109 },
16110 complete = function( jqXHR, status ) {
16111 if ( status === "abort" ) {
16112 that.panels.stop( false, true );
16113 }
16114
16115 tab.removeClass( "ui-tabs-loading" );
16116 panel.removeAttr( "aria-busy" );
16117
16118 if ( jqXHR === that.xhr ) {
16119 delete that.xhr;
16120 }
16121 };
16122
16123 // not remote
16124 if ( this._isLocal( anchor[ 0 ] ) ) {
16125 return;
16126 }
16127
16128 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
16129
16130 // support: jQuery <1.8
16131 // jQuery <1.8 returns false if the request is canceled in beforeSend,
16132 // but as of 1.8, $.ajax() always returns a jqXHR object.
16133 if ( this.xhr && this.xhr.statusText !== "canceled" ) {
16134 tab.addClass( "ui-tabs-loading" );
16135 panel.attr( "aria-busy", "true" );
16136
16137 this.xhr
16138 .done(function( response, status, jqXHR ) {
16139 // support: jQuery <1.8
16140 // http://bugs.jquery.com/ticket/11778
16141 setTimeout(function() {
16142 panel.html( response );
16143 that._trigger( "load", event, eventData );
16144
16145 complete( jqXHR, status );
16146 }, 1 );
16147 })
16148 .fail(function( jqXHR, status ) {
16149 // support: jQuery <1.8
16150 // http://bugs.jquery.com/ticket/11778
16151 setTimeout(function() {
16152 complete( jqXHR, status );
16153 }, 1 );
16154 });
16155 }
16156 },
16157
16158 _ajaxSettings: function( anchor, event, eventData ) {
16159 var that = this;
16160 return {
16161 url: anchor.attr( "href" ),
16162 beforeSend: function( jqXHR, settings ) {
16163 return that._trigger( "beforeLoad", event,
16164 $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
16165 }
16166 };
16167 },
16168
16169 _getPanelForTab: function( tab ) {
16170 var id = $( tab ).attr( "aria-controls" );
16171 return this.element.find( this._sanitizeSelector( "#" + id ) );
16172 }
16173 });
16174
16175
16176 /*!
16177 * jQuery UI Tooltip 1.11.4
16178 * http://jqueryui.com
16179 *
16180 * Copyright jQuery Foundation and other contributors
16181 * Released under the MIT license.
16182 * http://jquery.org/license
16183 *
16184 * http://api.jqueryui.com/tooltip/
16185 */
16186
16187
16188 var tooltip = $.widget( "ui.tooltip", {
16189 version: "1.11.4",
16190 options: {
16191 content: function() {
16192 // support: IE<9, Opera in jQuery <1.7
16193 // .text() can't accept undefined, so coerce to a string
16194 var title = $( this ).attr( "title" ) || "";
16195 // Escape title, since we're going from an attribute to raw HTML
16196 //return $( "<a>" ).text( title ).html();
16197 // Christian Schoenebeck: don't escape, interpret as HTML so we can add markup in the "title" attribte
16198 var html = $.parseHTML(title);
16199 return $( "<a>" ).append( html );
16200 },
16201 hide: true,
16202 // Disabled elements have inconsistent behavior across browsers (#8661)
16203 items: "[title]:not([disabled])",
16204 position: {
16205 my: "left top+15",
16206 at: "left bottom",
16207 collision: "flipfit flip"
16208 },
16209 show: true,
16210 tooltipClass: null,
16211 track: false,
16212
16213 // callbacks
16214 close: null,
16215 open: null
16216 },
16217
16218 _addDescribedBy: function( elem, id ) {
16219 var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ );
16220 describedby.push( id );
16221 elem
16222 .data( "ui-tooltip-id", id )
16223 .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
16224 },
16225
16226 _removeDescribedBy: function( elem ) {
16227 var id = elem.data( "ui-tooltip-id" ),
16228 describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ),
16229 index = $.inArray( id, describedby );
16230
16231 if ( index !== -1 ) {
16232 describedby.splice( index, 1 );
16233 }
16234
16235 elem.removeData( "ui-tooltip-id" );
16236 describedby = $.trim( describedby.join( " " ) );
16237 if ( describedby ) {
16238 elem.attr( "aria-describedby", describedby );
16239 } else {
16240 elem.removeAttr( "aria-describedby" );
16241 }
16242 },
16243
16244 _create: function() {
16245 this._on({
16246 mouseover: "open",
16247 focusin: "open"
16248 });
16249
16250 // IDs of generated tooltips, needed for destroy
16251 this.tooltips = {};
16252
16253 // IDs of parent tooltips where we removed the title attribute
16254 this.parents = {};
16255
16256 if ( this.options.disabled ) {
16257 this._disable();
16258 }
16259
16260 // Append the aria-live region so tooltips announce correctly
16261 this.liveRegion = $( "<div>" )
16262 .attr({
16263 role: "log",
16264 "aria-live": "assertive",
16265 "aria-relevant": "additions"
16266 })
16267 .addClass( "ui-helper-hidden-accessible" )
16268 .appendTo( this.document[ 0 ].body );
16269 },
16270
16271 _setOption: function( key, value ) {
16272 var that = this;
16273
16274 if ( key === "disabled" ) {
16275 this[ value ? "_disable" : "_enable" ]();
16276 this.options[ key ] = value;
16277 // disable element style changes
16278 return;
16279 }
16280
16281 this._super( key, value );
16282
16283 if ( key === "content" ) {
16284 $.each( this.tooltips, function( id, tooltipData ) {
16285 that._updateContent( tooltipData.element );
16286 });
16287 }
16288 },
16289
16290 _disable: function() {
16291 var that = this;
16292
16293 // close open tooltips
16294 $.each( this.tooltips, function( id, tooltipData ) {
16295 var event = $.Event( "blur" );
16296 event.target = event.currentTarget = tooltipData.element[ 0 ];
16297 that.close( event, true );
16298 });
16299
16300 // remove title attributes to prevent native tooltips
16301 this.element.find( this.options.items ).addBack().each(function() {
16302 var element = $( this );
16303 if ( element.is( "[title]" ) ) {
16304 element
16305 .data( "ui-tooltip-title", element.attr( "title" ) )
16306 .removeAttr( "title" );
16307 }
16308 });
16309 },
16310
16311 _enable: function() {
16312 // restore title attributes
16313 this.element.find( this.options.items ).addBack().each(function() {
16314 var element = $( this );
16315 if ( element.data( "ui-tooltip-title" ) ) {
16316 element.attr( "title", element.data( "ui-tooltip-title" ) );
16317 }
16318 });
16319 },
16320
16321 open: function( event ) {
16322 var that = this,
16323 target = $( event ? event.target : this.element )
16324 // we need closest here due to mouseover bubbling,
16325 // but always pointing at the same event target
16326 .closest( this.options.items );
16327
16328 // No element to show a tooltip for or the tooltip is already open
16329 if ( !target.length || target.data( "ui-tooltip-id" ) ) {
16330 return;
16331 }
16332
16333 if ( target.attr( "title" ) ) {
16334 target.data( "ui-tooltip-title", target.attr( "title" ) );
16335 }
16336
16337 target.data( "ui-tooltip-open", true );
16338
16339 // kill parent tooltips, custom or native, for hover
16340 if ( event && event.type === "mouseover" ) {
16341 target.parents().each(function() {
16342 var parent = $( this ),
16343 blurEvent;
16344 if ( parent.data( "ui-tooltip-open" ) ) {
16345 blurEvent = $.Event( "blur" );
16346 blurEvent.target = blurEvent.currentTarget = this;
16347 that.close( blurEvent, true );
16348 }
16349 if ( parent.attr( "title" ) ) {
16350 parent.uniqueId();
16351 that.parents[ this.id ] = {
16352 element: this,
16353 title: parent.attr( "title" )
16354 };
16355 parent.attr( "title", "" );
16356 }
16357 });
16358 }
16359
16360 this._registerCloseHandlers( event, target );
16361 this._updateContent( target, event );
16362 },
16363
16364 _updateContent: function( target, event ) {
16365 var content,
16366 contentOption = this.options.content,
16367 that = this,
16368 eventType = event ? event.type : null;
16369
16370 if ( typeof contentOption === "string" ) {
16371 return this._open( event, target, contentOption );
16372 }
16373
16374 content = contentOption.call( target[0], function( response ) {
16375
16376 // IE may instantly serve a cached response for ajax requests
16377 // delay this call to _open so the other call to _open runs first
16378 that._delay(function() {
16379
16380 // Ignore async response if tooltip was closed already
16381 if ( !target.data( "ui-tooltip-open" ) ) {
16382 return;
16383 }
16384
16385 // jQuery creates a special event for focusin when it doesn't
16386 // exist natively. To improve performance, the native event
16387 // object is reused and the type is changed. Therefore, we can't
16388 // rely on the type being correct after the event finished
16389 // bubbling, so we set it back to the previous value. (#8740)
16390 if ( event ) {
16391 event.type = eventType;
16392 }
16393 this._open( event, target, response );
16394 });
16395 });
16396 if ( content ) {
16397 this._open( event, target, content );
16398 }
16399 },
16400
16401 _open: function( event, target, content ) {
16402 var tooltipData, tooltip, delayedShow, a11yContent,
16403 positionOption = $.extend( {}, this.options.position );
16404
16405 if ( !content ) {
16406 return;
16407 }
16408
16409 // Content can be updated multiple times. If the tooltip already
16410 // exists, then just update the content and bail.
16411 tooltipData = this._find( target );
16412 if ( tooltipData ) {
16413 tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content );
16414 return;
16415 }
16416
16417 // if we have a title, clear it to prevent the native tooltip
16418 // we have to check first to avoid defining a title if none exists
16419 // (we don't want to cause an element to start matching [title])
16420 //
16421 // We use removeAttr only for key events, to allow IE to export the correct
16422 // accessible attributes. For mouse events, set to empty string to avoid
16423 // native tooltip showing up (happens only when removing inside mouseover).
16424 if ( target.is( "[title]" ) ) {
16425 if ( event && event.type === "mouseover" ) {
16426 target.attr( "title", "" );
16427 } else {
16428 target.removeAttr( "title" );
16429 }
16430 }
16431
16432 tooltipData = this._tooltip( target );
16433 tooltip = tooltipData.tooltip;
16434 this._addDescribedBy( target, tooltip.attr( "id" ) );
16435 tooltip.find( ".ui-tooltip-content" ).html( content );
16436
16437 // Support: Voiceover on OS X, JAWS on IE <= 9
16438 // JAWS announces deletions even when aria-relevant="additions"
16439 // Voiceover will sometimes re-read the entire log region's contents from the beginning
16440 this.liveRegion.children().hide();
16441 if ( content.clone ) {
16442 a11yContent = content.clone();
16443 a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" );
16444 } else {
16445 a11yContent = content;
16446 }
16447 $( "<div>" ).html( a11yContent ).appendTo( this.liveRegion );
16448
16449 function position( event ) {
16450 positionOption.of = event;
16451 if ( tooltip.is( ":hidden" ) ) {
16452 return;
16453 }
16454 tooltip.position( positionOption );
16455 }
16456 if ( this.options.track && event && /^mouse/.test( event.type ) ) {
16457 this._on( this.document, {
16458 mousemove: position
16459 });
16460 // trigger once to override element-relative positioning
16461 position( event );
16462 } else {
16463 tooltip.position( $.extend({
16464 of: target
16465 }, this.options.position ) );
16466 }
16467
16468 tooltip.hide();
16469
16470 this._show( tooltip, this.options.show );
16471 // Handle tracking tooltips that are shown with a delay (#8644). As soon
16472 // as the tooltip is visible, position the tooltip using the most recent
16473 // event.
16474 if ( this.options.show && this.options.show.delay ) {
16475 delayedShow = this.delayedShow = setInterval(function() {
16476 if ( tooltip.is( ":visible" ) ) {
16477 position( positionOption.of );
16478 clearInterval( delayedShow );
16479 }
16480 }, $.fx.interval );
16481 }
16482
16483 this._trigger( "open", event, { tooltip: tooltip } );
16484 },
16485
16486 _registerCloseHandlers: function( event, target ) {
16487 var events = {
16488 keyup: function( event ) {
16489 if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
16490 var fakeEvent = $.Event(event);
16491 fakeEvent.currentTarget = target[0];
16492 this.close( fakeEvent, true );
16493 }
16494 }
16495 };
16496
16497 // Only bind remove handler for delegated targets. Non-delegated
16498 // tooltips will handle this in destroy.
16499 if ( target[ 0 ] !== this.element[ 0 ] ) {
16500 events.remove = function() {
16501 this._removeTooltip( this._find( target ).tooltip );
16502 };
16503 }
16504
16505 if ( !event || event.type === "mouseover" ) {
16506 events.mouseleave = "close";
16507 }
16508 if ( !event || event.type === "focusin" ) {
16509 events.focusout = "close";
16510 }
16511 this._on( true, target, events );
16512 },
16513
16514 close: function( event ) {
16515 var tooltip,
16516 that = this,
16517 target = $( event ? event.currentTarget : this.element ),
16518 tooltipData = this._find( target );
16519
16520 // The tooltip may already be closed
16521 if ( !tooltipData ) {
16522
16523 // We set ui-tooltip-open immediately upon open (in open()), but only set the
16524 // additional data once there's actually content to show (in _open()). So even if the
16525 // tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in
16526 // the period between open() and _open().
16527 target.removeData( "ui-tooltip-open" );
16528 return;
16529 }
16530
16531 tooltip = tooltipData.tooltip;
16532
16533 // disabling closes the tooltip, so we need to track when we're closing
16534 // to avoid an infinite loop in case the tooltip becomes disabled on close
16535 if ( tooltipData.closing ) {
16536 return;
16537 }
16538
16539 // Clear the interval for delayed tracking tooltips
16540 clearInterval( this.delayedShow );
16541
16542 // only set title if we had one before (see comment in _open())
16543 // If the title attribute has changed since open(), don't restore
16544 if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
16545 target.attr( "title", target.data( "ui-tooltip-title" ) );
16546 }
16547
16548 this._removeDescribedBy( target );
16549
16550 tooltipData.hiding = true;
16551 tooltip.stop( true );
16552 this._hide( tooltip, this.options.hide, function() {
16553 that._removeTooltip( $( this ) );
16554 });
16555
16556 target.removeData( "ui-tooltip-open" );
16557 this._off( target, "mouseleave focusout keyup" );
16558
16559 // Remove 'remove' binding only on delegated targets
16560 if ( target[ 0 ] !== this.element[ 0 ] ) {
16561 this._off( target, "remove" );
16562 }
16563 this._off( this.document, "mousemove" );
16564
16565 if ( event && event.type === "mouseleave" ) {
16566 $.each( this.parents, function( id, parent ) {
16567 $( parent.element ).attr( "title", parent.title );
16568 delete that.parents[ id ];
16569 });
16570 }
16571
16572 tooltipData.closing = true;
16573 this._trigger( "close", event, { tooltip: tooltip } );
16574 if ( !tooltipData.hiding ) {
16575 tooltipData.closing = false;
16576 }
16577 },
16578
16579 _tooltip: function( element ) {
16580 var tooltip = $( "<div>" )
16581 .attr( "role", "tooltip" )
16582 .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " +
16583 ( this.options.tooltipClass || "" ) ),
16584 id = tooltip.uniqueId().attr( "id" );
16585
16586 $( "<div>" )
16587 .addClass( "ui-tooltip-content" )
16588 .appendTo( tooltip );
16589
16590 tooltip.appendTo( this.document[0].body );
16591
16592 return this.tooltips[ id ] = {
16593 element: element,
16594 tooltip: tooltip
16595 };
16596 },
16597
16598 _find: function( target ) {
16599 var id = target.data( "ui-tooltip-id" );
16600 return id ? this.tooltips[ id ] : null;
16601 },
16602
16603 _removeTooltip: function( tooltip ) {
16604 tooltip.remove();
16605 delete this.tooltips[ tooltip.attr( "id" ) ];
16606 },
16607
16608 _destroy: function() {
16609 var that = this;
16610
16611 // close open tooltips
16612 $.each( this.tooltips, function( id, tooltipData ) {
16613 // Delegate to close method to handle common cleanup
16614 var event = $.Event( "blur" ),
16615 element = tooltipData.element;
16616 event.target = event.currentTarget = element[ 0 ];
16617 that.close( event, true );
16618
16619 // Remove immediately; destroying an open tooltip doesn't use the
16620 // hide animation
16621 $( "#" + id ).remove();
16622
16623 // Restore the title
16624 if ( element.data( "ui-tooltip-title" ) ) {
16625 // If the title attribute has changed since open(), don't restore
16626 if ( !element.attr( "title" ) ) {
16627 element.attr( "title", element.data( "ui-tooltip-title" ) );
16628 }
16629 element.removeData( "ui-tooltip-title" );
16630 }
16631 });
16632 this.liveRegion.remove();
16633 }
16634 });
16635
16636
16637
16638 }));

  ViewVC Help
Powered by ViewVC