comparison src/main/webapp/imageServer/resources/js/jquery-ui-1.10.4/ui/jquery-ui.js @ 7:764f47286679

(none)
author jurzua
date Wed, 29 Oct 2014 14:28:34 +0000
parents
children
comparison
equal deleted inserted replaced
6:ded3bccf2cf9 7:764f47286679
1 /*! jQuery UI - v1.10.4 - 2014-01-17
2 * http://jqueryui.com
3 * Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.effect.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js, jquery.ui.menu.js, jquery.ui.position.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js
4 * Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
5 (function( $, undefined ) {
6
7 var uuid = 0,
8 runiqueId = /^ui-id-\d+$/;
9
10 // $.ui might exist from components with no dependencies, e.g., $.ui.position
11 $.ui = $.ui || {};
12
13 $.extend( $.ui, {
14 version: "1.10.4",
15
16 keyCode: {
17 BACKSPACE: 8,
18 COMMA: 188,
19 DELETE: 46,
20 DOWN: 40,
21 END: 35,
22 ENTER: 13,
23 ESCAPE: 27,
24 HOME: 36,
25 LEFT: 37,
26 NUMPAD_ADD: 107,
27 NUMPAD_DECIMAL: 110,
28 NUMPAD_DIVIDE: 111,
29 NUMPAD_ENTER: 108,
30 NUMPAD_MULTIPLY: 106,
31 NUMPAD_SUBTRACT: 109,
32 PAGE_DOWN: 34,
33 PAGE_UP: 33,
34 PERIOD: 190,
35 RIGHT: 39,
36 SPACE: 32,
37 TAB: 9,
38 UP: 38
39 }
40 });
41
42 // plugins
43 $.fn.extend({
44 focus: (function( orig ) {
45 return function( delay, fn ) {
46 return typeof delay === "number" ?
47 this.each(function() {
48 var elem = this;
49 setTimeout(function() {
50 $( elem ).focus();
51 if ( fn ) {
52 fn.call( elem );
53 }
54 }, delay );
55 }) :
56 orig.apply( this, arguments );
57 };
58 })( $.fn.focus ),
59
60 scrollParent: function() {
61 var scrollParent;
62 if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) {
63 scrollParent = this.parents().filter(function() {
64 return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
65 }).eq(0);
66 } else {
67 scrollParent = this.parents().filter(function() {
68 return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
69 }).eq(0);
70 }
71
72 return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent;
73 },
74
75 zIndex: function( zIndex ) {
76 if ( zIndex !== undefined ) {
77 return this.css( "zIndex", zIndex );
78 }
79
80 if ( this.length ) {
81 var elem = $( this[ 0 ] ), position, value;
82 while ( elem.length && elem[ 0 ] !== document ) {
83 // Ignore z-index if position is set to a value where z-index is ignored by the browser
84 // This makes behavior of this function consistent across browsers
85 // WebKit always returns auto if the element is positioned
86 position = elem.css( "position" );
87 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
88 // IE returns 0 when zIndex is not specified
89 // other browsers return a string
90 // we ignore the case of nested elements with an explicit value of 0
91 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
92 value = parseInt( elem.css( "zIndex" ), 10 );
93 if ( !isNaN( value ) && value !== 0 ) {
94 return value;
95 }
96 }
97 elem = elem.parent();
98 }
99 }
100
101 return 0;
102 },
103
104 uniqueId: function() {
105 return this.each(function() {
106 if ( !this.id ) {
107 this.id = "ui-id-" + (++uuid);
108 }
109 });
110 },
111
112 removeUniqueId: function() {
113 return this.each(function() {
114 if ( runiqueId.test( this.id ) ) {
115 $( this ).removeAttr( "id" );
116 }
117 });
118 }
119 });
120
121 // selectors
122 function focusable( element, isTabIndexNotNaN ) {
123 var map, mapName, img,
124 nodeName = element.nodeName.toLowerCase();
125 if ( "area" === nodeName ) {
126 map = element.parentNode;
127 mapName = map.name;
128 if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
129 return false;
130 }
131 img = $( "img[usemap=#" + mapName + "]" )[0];
132 return !!img && visible( img );
133 }
134 return ( /input|select|textarea|button|object/.test( nodeName ) ?
135 !element.disabled :
136 "a" === nodeName ?
137 element.href || isTabIndexNotNaN :
138 isTabIndexNotNaN) &&
139 // the element and all of its ancestors must be visible
140 visible( element );
141 }
142
143 function visible( element ) {
144 return $.expr.filters.visible( element ) &&
145 !$( element ).parents().addBack().filter(function() {
146 return $.css( this, "visibility" ) === "hidden";
147 }).length;
148 }
149
150 $.extend( $.expr[ ":" ], {
151 data: $.expr.createPseudo ?
152 $.expr.createPseudo(function( dataName ) {
153 return function( elem ) {
154 return !!$.data( elem, dataName );
155 };
156 }) :
157 // support: jQuery <1.8
158 function( elem, i, match ) {
159 return !!$.data( elem, match[ 3 ] );
160 },
161
162 focusable: function( element ) {
163 return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
164 },
165
166 tabbable: function( element ) {
167 var tabIndex = $.attr( element, "tabindex" ),
168 isTabIndexNaN = isNaN( tabIndex );
169 return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
170 }
171 });
172
173 // support: jQuery <1.8
174 if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
175 $.each( [ "Width", "Height" ], function( i, name ) {
176 var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
177 type = name.toLowerCase(),
178 orig = {
179 innerWidth: $.fn.innerWidth,
180 innerHeight: $.fn.innerHeight,
181 outerWidth: $.fn.outerWidth,
182 outerHeight: $.fn.outerHeight
183 };
184
185 function reduce( elem, size, border, margin ) {
186 $.each( side, function() {
187 size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
188 if ( border ) {
189 size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
190 }
191 if ( margin ) {
192 size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
193 }
194 });
195 return size;
196 }
197
198 $.fn[ "inner" + name ] = function( size ) {
199 if ( size === undefined ) {
200 return orig[ "inner" + name ].call( this );
201 }
202
203 return this.each(function() {
204 $( this ).css( type, reduce( this, size ) + "px" );
205 });
206 };
207
208 $.fn[ "outer" + name] = function( size, margin ) {
209 if ( typeof size !== "number" ) {
210 return orig[ "outer" + name ].call( this, size );
211 }
212
213 return this.each(function() {
214 $( this).css( type, reduce( this, size, true, margin ) + "px" );
215 });
216 };
217 });
218 }
219
220 // support: jQuery <1.8
221 if ( !$.fn.addBack ) {
222 $.fn.addBack = function( selector ) {
223 return this.add( selector == null ?
224 this.prevObject : this.prevObject.filter( selector )
225 );
226 };
227 }
228
229 // support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
230 if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
231 $.fn.removeData = (function( removeData ) {
232 return function( key ) {
233 if ( arguments.length ) {
234 return removeData.call( this, $.camelCase( key ) );
235 } else {
236 return removeData.call( this );
237 }
238 };
239 })( $.fn.removeData );
240 }
241
242
243
244
245
246 // deprecated
247 $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
248
249 $.support.selectstart = "onselectstart" in document.createElement( "div" );
250 $.fn.extend({
251 disableSelection: function() {
252 return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
253 ".ui-disableSelection", function( event ) {
254 event.preventDefault();
255 });
256 },
257
258 enableSelection: function() {
259 return this.unbind( ".ui-disableSelection" );
260 }
261 });
262
263 $.extend( $.ui, {
264 // $.ui.plugin is deprecated. Use $.widget() extensions instead.
265 plugin: {
266 add: function( module, option, set ) {
267 var i,
268 proto = $.ui[ module ].prototype;
269 for ( i in set ) {
270 proto.plugins[ i ] = proto.plugins[ i ] || [];
271 proto.plugins[ i ].push( [ option, set[ i ] ] );
272 }
273 },
274 call: function( instance, name, args ) {
275 var i,
276 set = instance.plugins[ name ];
277 if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) {
278 return;
279 }
280
281 for ( i = 0; i < set.length; i++ ) {
282 if ( instance.options[ set[ i ][ 0 ] ] ) {
283 set[ i ][ 1 ].apply( instance.element, args );
284 }
285 }
286 }
287 },
288
289 // only used by resizable
290 hasScroll: function( el, a ) {
291
292 //If overflow is hidden, the element might have extra content, but the user wants to hide it
293 if ( $( el ).css( "overflow" ) === "hidden") {
294 return false;
295 }
296
297 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
298 has = false;
299
300 if ( el[ scroll ] > 0 ) {
301 return true;
302 }
303
304 // TODO: determine which cases actually cause this to happen
305 // if the element doesn't have the scroll set, see if it's possible to
306 // set the scroll
307 el[ scroll ] = 1;
308 has = ( el[ scroll ] > 0 );
309 el[ scroll ] = 0;
310 return has;
311 }
312 });
313
314 })( jQuery );
315
316 (function( $, undefined ) {
317
318 var uuid = 0,
319 slice = Array.prototype.slice,
320 _cleanData = $.cleanData;
321 $.cleanData = function( elems ) {
322 for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
323 try {
324 $( elem ).triggerHandler( "remove" );
325 // http://bugs.jquery.com/ticket/8235
326 } catch( e ) {}
327 }
328 _cleanData( elems );
329 };
330
331 $.widget = function( name, base, prototype ) {
332 var fullName, existingConstructor, constructor, basePrototype,
333 // proxiedPrototype allows the provided prototype to remain unmodified
334 // so that it can be used as a mixin for multiple widgets (#8876)
335 proxiedPrototype = {},
336 namespace = name.split( "." )[ 0 ];
337
338 name = name.split( "." )[ 1 ];
339 fullName = namespace + "-" + name;
340
341 if ( !prototype ) {
342 prototype = base;
343 base = $.Widget;
344 }
345
346 // create selector for plugin
347 $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
348 return !!$.data( elem, fullName );
349 };
350
351 $[ namespace ] = $[ namespace ] || {};
352 existingConstructor = $[ namespace ][ name ];
353 constructor = $[ namespace ][ name ] = function( options, element ) {
354 // allow instantiation without "new" keyword
355 if ( !this._createWidget ) {
356 return new constructor( options, element );
357 }
358
359 // allow instantiation without initializing for simple inheritance
360 // must use "new" keyword (the code above always passes args)
361 if ( arguments.length ) {
362 this._createWidget( options, element );
363 }
364 };
365 // extend with the existing constructor to carry over any static properties
366 $.extend( constructor, existingConstructor, {
367 version: prototype.version,
368 // copy the object used to create the prototype in case we need to
369 // redefine the widget later
370 _proto: $.extend( {}, prototype ),
371 // track widgets that inherit from this widget in case this widget is
372 // redefined after a widget inherits from it
373 _childConstructors: []
374 });
375
376 basePrototype = new base();
377 // we need to make the options hash a property directly on the new instance
378 // otherwise we'll modify the options hash on the prototype that we're
379 // inheriting from
380 basePrototype.options = $.widget.extend( {}, basePrototype.options );
381 $.each( prototype, function( prop, value ) {
382 if ( !$.isFunction( value ) ) {
383 proxiedPrototype[ prop ] = value;
384 return;
385 }
386 proxiedPrototype[ prop ] = (function() {
387 var _super = function() {
388 return base.prototype[ prop ].apply( this, arguments );
389 },
390 _superApply = function( args ) {
391 return base.prototype[ prop ].apply( this, args );
392 };
393 return function() {
394 var __super = this._super,
395 __superApply = this._superApply,
396 returnValue;
397
398 this._super = _super;
399 this._superApply = _superApply;
400
401 returnValue = value.apply( this, arguments );
402
403 this._super = __super;
404 this._superApply = __superApply;
405
406 return returnValue;
407 };
408 })();
409 });
410 constructor.prototype = $.widget.extend( basePrototype, {
411 // TODO: remove support for widgetEventPrefix
412 // always use the name + a colon as the prefix, e.g., draggable:start
413 // don't prefix for widgets that aren't DOM-based
414 widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name
415 }, proxiedPrototype, {
416 constructor: constructor,
417 namespace: namespace,
418 widgetName: name,
419 widgetFullName: fullName
420 });
421
422 // If this widget is being redefined then we need to find all widgets that
423 // are inheriting from it and redefine all of them so that they inherit from
424 // the new version of this widget. We're essentially trying to replace one
425 // level in the prototype chain.
426 if ( existingConstructor ) {
427 $.each( existingConstructor._childConstructors, function( i, child ) {
428 var childPrototype = child.prototype;
429
430 // redefine the child widget using the same prototype that was
431 // originally used, but inherit from the new version of the base
432 $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
433 });
434 // remove the list of existing child constructors from the old constructor
435 // so the old child constructors can be garbage collected
436 delete existingConstructor._childConstructors;
437 } else {
438 base._childConstructors.push( constructor );
439 }
440
441 $.widget.bridge( name, constructor );
442 };
443
444 $.widget.extend = function( target ) {
445 var input = slice.call( arguments, 1 ),
446 inputIndex = 0,
447 inputLength = input.length,
448 key,
449 value;
450 for ( ; inputIndex < inputLength; inputIndex++ ) {
451 for ( key in input[ inputIndex ] ) {
452 value = input[ inputIndex ][ key ];
453 if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
454 // Clone objects
455 if ( $.isPlainObject( value ) ) {
456 target[ key ] = $.isPlainObject( target[ key ] ) ?
457 $.widget.extend( {}, target[ key ], value ) :
458 // Don't extend strings, arrays, etc. with objects
459 $.widget.extend( {}, value );
460 // Copy everything else by reference
461 } else {
462 target[ key ] = value;
463 }
464 }
465 }
466 }
467 return target;
468 };
469
470 $.widget.bridge = function( name, object ) {
471 var fullName = object.prototype.widgetFullName || name;
472 $.fn[ name ] = function( options ) {
473 var isMethodCall = typeof options === "string",
474 args = slice.call( arguments, 1 ),
475 returnValue = this;
476
477 // allow multiple hashes to be passed on init
478 options = !isMethodCall && args.length ?
479 $.widget.extend.apply( null, [ options ].concat(args) ) :
480 options;
481
482 if ( isMethodCall ) {
483 this.each(function() {
484 var methodValue,
485 instance = $.data( this, fullName );
486 if ( !instance ) {
487 return $.error( "cannot call methods on " + name + " prior to initialization; " +
488 "attempted to call method '" + options + "'" );
489 }
490 if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
491 return $.error( "no such method '" + options + "' for " + name + " widget instance" );
492 }
493 methodValue = instance[ options ].apply( instance, args );
494 if ( methodValue !== instance && methodValue !== undefined ) {
495 returnValue = methodValue && methodValue.jquery ?
496 returnValue.pushStack( methodValue.get() ) :
497 methodValue;
498 return false;
499 }
500 });
501 } else {
502 this.each(function() {
503 var instance = $.data( this, fullName );
504 if ( instance ) {
505 instance.option( options || {} )._init();
506 } else {
507 $.data( this, fullName, new object( options, this ) );
508 }
509 });
510 }
511
512 return returnValue;
513 };
514 };
515
516 $.Widget = function( /* options, element */ ) {};
517 $.Widget._childConstructors = [];
518
519 $.Widget.prototype = {
520 widgetName: "widget",
521 widgetEventPrefix: "",
522 defaultElement: "<div>",
523 options: {
524 disabled: false,
525
526 // callbacks
527 create: null
528 },
529 _createWidget: function( options, element ) {
530 element = $( element || this.defaultElement || this )[ 0 ];
531 this.element = $( element );
532 this.uuid = uuid++;
533 this.eventNamespace = "." + this.widgetName + this.uuid;
534 this.options = $.widget.extend( {},
535 this.options,
536 this._getCreateOptions(),
537 options );
538
539 this.bindings = $();
540 this.hoverable = $();
541 this.focusable = $();
542
543 if ( element !== this ) {
544 $.data( element, this.widgetFullName, this );
545 this._on( true, this.element, {
546 remove: function( event ) {
547 if ( event.target === element ) {
548 this.destroy();
549 }
550 }
551 });
552 this.document = $( element.style ?
553 // element within the document
554 element.ownerDocument :
555 // element is window or document
556 element.document || element );
557 this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
558 }
559
560 this._create();
561 this._trigger( "create", null, this._getCreateEventData() );
562 this._init();
563 },
564 _getCreateOptions: $.noop,
565 _getCreateEventData: $.noop,
566 _create: $.noop,
567 _init: $.noop,
568
569 destroy: function() {
570 this._destroy();
571 // we can probably remove the unbind calls in 2.0
572 // all event bindings should go through this._on()
573 this.element
574 .unbind( this.eventNamespace )
575 // 1.9 BC for #7810
576 // TODO remove dual storage
577 .removeData( this.widgetName )
578 .removeData( this.widgetFullName )
579 // support: jquery <1.6.3
580 // http://bugs.jquery.com/ticket/9413
581 .removeData( $.camelCase( this.widgetFullName ) );
582 this.widget()
583 .unbind( this.eventNamespace )
584 .removeAttr( "aria-disabled" )
585 .removeClass(
586 this.widgetFullName + "-disabled " +
587 "ui-state-disabled" );
588
589 // clean up events and states
590 this.bindings.unbind( this.eventNamespace );
591 this.hoverable.removeClass( "ui-state-hover" );
592 this.focusable.removeClass( "ui-state-focus" );
593 },
594 _destroy: $.noop,
595
596 widget: function() {
597 return this.element;
598 },
599
600 option: function( key, value ) {
601 var options = key,
602 parts,
603 curOption,
604 i;
605
606 if ( arguments.length === 0 ) {
607 // don't return a reference to the internal hash
608 return $.widget.extend( {}, this.options );
609 }
610
611 if ( typeof key === "string" ) {
612 // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
613 options = {};
614 parts = key.split( "." );
615 key = parts.shift();
616 if ( parts.length ) {
617 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
618 for ( i = 0; i < parts.length - 1; i++ ) {
619 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
620 curOption = curOption[ parts[ i ] ];
621 }
622 key = parts.pop();
623 if ( arguments.length === 1 ) {
624 return curOption[ key ] === undefined ? null : curOption[ key ];
625 }
626 curOption[ key ] = value;
627 } else {
628 if ( arguments.length === 1 ) {
629 return this.options[ key ] === undefined ? null : this.options[ key ];
630 }
631 options[ key ] = value;
632 }
633 }
634
635 this._setOptions( options );
636
637 return this;
638 },
639 _setOptions: function( options ) {
640 var key;
641
642 for ( key in options ) {
643 this._setOption( key, options[ key ] );
644 }
645
646 return this;
647 },
648 _setOption: function( key, value ) {
649 this.options[ key ] = value;
650
651 if ( key === "disabled" ) {
652 this.widget()
653 .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value )
654 .attr( "aria-disabled", value );
655 this.hoverable.removeClass( "ui-state-hover" );
656 this.focusable.removeClass( "ui-state-focus" );
657 }
658
659 return this;
660 },
661
662 enable: function() {
663 return this._setOption( "disabled", false );
664 },
665 disable: function() {
666 return this._setOption( "disabled", true );
667 },
668
669 _on: function( suppressDisabledCheck, element, handlers ) {
670 var delegateElement,
671 instance = this;
672
673 // no suppressDisabledCheck flag, shuffle arguments
674 if ( typeof suppressDisabledCheck !== "boolean" ) {
675 handlers = element;
676 element = suppressDisabledCheck;
677 suppressDisabledCheck = false;
678 }
679
680 // no element argument, shuffle and use this.element
681 if ( !handlers ) {
682 handlers = element;
683 element = this.element;
684 delegateElement = this.widget();
685 } else {
686 // accept selectors, DOM elements
687 element = delegateElement = $( element );
688 this.bindings = this.bindings.add( element );
689 }
690
691 $.each( handlers, function( event, handler ) {
692 function handlerProxy() {
693 // allow widgets to customize the disabled handling
694 // - disabled as an array instead of boolean
695 // - disabled class as method for disabling individual parts
696 if ( !suppressDisabledCheck &&
697 ( instance.options.disabled === true ||
698 $( this ).hasClass( "ui-state-disabled" ) ) ) {
699 return;
700 }
701 return ( typeof handler === "string" ? instance[ handler ] : handler )
702 .apply( instance, arguments );
703 }
704
705 // copy the guid so direct unbinding works
706 if ( typeof handler !== "string" ) {
707 handlerProxy.guid = handler.guid =
708 handler.guid || handlerProxy.guid || $.guid++;
709 }
710
711 var match = event.match( /^(\w+)\s*(.*)$/ ),
712 eventName = match[1] + instance.eventNamespace,
713 selector = match[2];
714 if ( selector ) {
715 delegateElement.delegate( selector, eventName, handlerProxy );
716 } else {
717 element.bind( eventName, handlerProxy );
718 }
719 });
720 },
721
722 _off: function( element, eventName ) {
723 eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
724 element.unbind( eventName ).undelegate( eventName );
725 },
726
727 _delay: function( handler, delay ) {
728 function handlerProxy() {
729 return ( typeof handler === "string" ? instance[ handler ] : handler )
730 .apply( instance, arguments );
731 }
732 var instance = this;
733 return setTimeout( handlerProxy, delay || 0 );
734 },
735
736 _hoverable: function( element ) {
737 this.hoverable = this.hoverable.add( element );
738 this._on( element, {
739 mouseenter: function( event ) {
740 $( event.currentTarget ).addClass( "ui-state-hover" );
741 },
742 mouseleave: function( event ) {
743 $( event.currentTarget ).removeClass( "ui-state-hover" );
744 }
745 });
746 },
747
748 _focusable: function( element ) {
749 this.focusable = this.focusable.add( element );
750 this._on( element, {
751 focusin: function( event ) {
752 $( event.currentTarget ).addClass( "ui-state-focus" );
753 },
754 focusout: function( event ) {
755 $( event.currentTarget ).removeClass( "ui-state-focus" );
756 }
757 });
758 },
759
760 _trigger: function( type, event, data ) {
761 var prop, orig,
762 callback = this.options[ type ];
763
764 data = data || {};
765 event = $.Event( event );
766 event.type = ( type === this.widgetEventPrefix ?
767 type :
768 this.widgetEventPrefix + type ).toLowerCase();
769 // the original event may come from any element
770 // so we need to reset the target on the new event
771 event.target = this.element[ 0 ];
772
773 // copy original event properties over to the new event
774 orig = event.originalEvent;
775 if ( orig ) {
776 for ( prop in orig ) {
777 if ( !( prop in event ) ) {
778 event[ prop ] = orig[ prop ];
779 }
780 }
781 }
782
783 this.element.trigger( event, data );
784 return !( $.isFunction( callback ) &&
785 callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
786 event.isDefaultPrevented() );
787 }
788 };
789
790 $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
791 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
792 if ( typeof options === "string" ) {
793 options = { effect: options };
794 }
795 var hasOptions,
796 effectName = !options ?
797 method :
798 options === true || typeof options === "number" ?
799 defaultEffect :
800 options.effect || defaultEffect;
801 options = options || {};
802 if ( typeof options === "number" ) {
803 options = { duration: options };
804 }
805 hasOptions = !$.isEmptyObject( options );
806 options.complete = callback;
807 if ( options.delay ) {
808 element.delay( options.delay );
809 }
810 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
811 element[ method ]( options );
812 } else if ( effectName !== method && element[ effectName ] ) {
813 element[ effectName ]( options.duration, options.easing, callback );
814 } else {
815 element.queue(function( next ) {
816 $( this )[ method ]();
817 if ( callback ) {
818 callback.call( element[ 0 ] );
819 }
820 next();
821 });
822 }
823 };
824 });
825
826 })( jQuery );
827
828 (function( $, undefined ) {
829
830 var mouseHandled = false;
831 $( document ).mouseup( function() {
832 mouseHandled = false;
833 });
834
835 $.widget("ui.mouse", {
836 version: "1.10.4",
837 options: {
838 cancel: "input,textarea,button,select,option",
839 distance: 1,
840 delay: 0
841 },
842 _mouseInit: function() {
843 var that = this;
844
845 this.element
846 .bind("mousedown."+this.widgetName, function(event) {
847 return that._mouseDown(event);
848 })
849 .bind("click."+this.widgetName, function(event) {
850 if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) {
851 $.removeData(event.target, that.widgetName + ".preventClickEvent");
852 event.stopImmediatePropagation();
853 return false;
854 }
855 });
856
857 this.started = false;
858 },
859
860 // TODO: make sure destroying one instance of mouse doesn't mess with
861 // other instances of mouse
862 _mouseDestroy: function() {
863 this.element.unbind("."+this.widgetName);
864 if ( this._mouseMoveDelegate ) {
865 $(document)
866 .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate)
867 .unbind("mouseup."+this.widgetName, this._mouseUpDelegate);
868 }
869 },
870
871 _mouseDown: function(event) {
872 // don't let more than one widget handle mouseStart
873 if( mouseHandled ) { return; }
874
875 // we may have missed mouseup (out of window)
876 (this._mouseStarted && this._mouseUp(event));
877
878 this._mouseDownEvent = event;
879
880 var that = this,
881 btnIsLeft = (event.which === 1),
882 // event.target.nodeName works around a bug in IE 8 with
883 // disabled inputs (#7620)
884 elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
885 if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
886 return true;
887 }
888
889 this.mouseDelayMet = !this.options.delay;
890 if (!this.mouseDelayMet) {
891 this._mouseDelayTimer = setTimeout(function() {
892 that.mouseDelayMet = true;
893 }, this.options.delay);
894 }
895
896 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
897 this._mouseStarted = (this._mouseStart(event) !== false);
898 if (!this._mouseStarted) {
899 event.preventDefault();
900 return true;
901 }
902 }
903
904 // Click event may never have fired (Gecko & Opera)
905 if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) {
906 $.removeData(event.target, this.widgetName + ".preventClickEvent");
907 }
908
909 // these delegates are required to keep context
910 this._mouseMoveDelegate = function(event) {
911 return that._mouseMove(event);
912 };
913 this._mouseUpDelegate = function(event) {
914 return that._mouseUp(event);
915 };
916 $(document)
917 .bind("mousemove."+this.widgetName, this._mouseMoveDelegate)
918 .bind("mouseup."+this.widgetName, this._mouseUpDelegate);
919
920 event.preventDefault();
921
922 mouseHandled = true;
923 return true;
924 },
925
926 _mouseMove: function(event) {
927 // IE mouseup check - mouseup happened when mouse was out of window
928 if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) {
929 return this._mouseUp(event);
930 }
931
932 if (this._mouseStarted) {
933 this._mouseDrag(event);
934 return event.preventDefault();
935 }
936
937 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
938 this._mouseStarted =
939 (this._mouseStart(this._mouseDownEvent, event) !== false);
940 (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
941 }
942
943 return !this._mouseStarted;
944 },
945
946 _mouseUp: function(event) {
947 $(document)
948 .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate)
949 .unbind("mouseup."+this.widgetName, this._mouseUpDelegate);
950
951 if (this._mouseStarted) {
952 this._mouseStarted = false;
953
954 if (event.target === this._mouseDownEvent.target) {
955 $.data(event.target, this.widgetName + ".preventClickEvent", true);
956 }
957
958 this._mouseStop(event);
959 }
960
961 return false;
962 },
963
964 _mouseDistanceMet: function(event) {
965 return (Math.max(
966 Math.abs(this._mouseDownEvent.pageX - event.pageX),
967 Math.abs(this._mouseDownEvent.pageY - event.pageY)
968 ) >= this.options.distance
969 );
970 },
971
972 _mouseDelayMet: function(/* event */) {
973 return this.mouseDelayMet;
974 },
975
976 // These are placeholder methods, to be overriden by extending plugin
977 _mouseStart: function(/* event */) {},
978 _mouseDrag: function(/* event */) {},
979 _mouseStop: function(/* event */) {},
980 _mouseCapture: function(/* event */) { return true; }
981 });
982
983 })(jQuery);
984
985 (function( $, undefined ) {
986
987 $.widget("ui.draggable", $.ui.mouse, {
988 version: "1.10.4",
989 widgetEventPrefix: "drag",
990 options: {
991 addClasses: true,
992 appendTo: "parent",
993 axis: false,
994 connectToSortable: false,
995 containment: false,
996 cursor: "auto",
997 cursorAt: false,
998 grid: false,
999 handle: false,
1000 helper: "original",
1001 iframeFix: false,
1002 opacity: false,
1003 refreshPositions: false,
1004 revert: false,
1005 revertDuration: 500,
1006 scope: "default",
1007 scroll: true,
1008 scrollSensitivity: 20,
1009 scrollSpeed: 20,
1010 snap: false,
1011 snapMode: "both",
1012 snapTolerance: 20,
1013 stack: false,
1014 zIndex: false,
1015
1016 // callbacks
1017 drag: null,
1018 start: null,
1019 stop: null
1020 },
1021 _create: function() {
1022
1023 if (this.options.helper === "original" && !(/^(?:r|a|f)/).test(this.element.css("position"))) {
1024 this.element[0].style.position = "relative";
1025 }
1026 if (this.options.addClasses){
1027 this.element.addClass("ui-draggable");
1028 }
1029 if (this.options.disabled){
1030 this.element.addClass("ui-draggable-disabled");
1031 }
1032
1033 this._mouseInit();
1034
1035 },
1036
1037 _destroy: function() {
1038 this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
1039 this._mouseDestroy();
1040 },
1041
1042 _mouseCapture: function(event) {
1043
1044 var o = this.options;
1045
1046 // among others, prevent a drag on a resizable-handle
1047 if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) {
1048 return false;
1049 }
1050
1051 //Quit if we're not on a valid handle
1052 this.handle = this._getHandle(event);
1053 if (!this.handle) {
1054 return false;
1055 }
1056
1057 $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
1058 $("<div class='ui-draggable-iframeFix' style='background: #fff;'></div>")
1059 .css({
1060 width: this.offsetWidth+"px", height: this.offsetHeight+"px",
1061 position: "absolute", opacity: "0.001", zIndex: 1000
1062 })
1063 .css($(this).offset())
1064 .appendTo("body");
1065 });
1066
1067 return true;
1068
1069 },
1070
1071 _mouseStart: function(event) {
1072
1073 var o = this.options;
1074
1075 //Create and append the visible helper
1076 this.helper = this._createHelper(event);
1077
1078 this.helper.addClass("ui-draggable-dragging");
1079
1080 //Cache the helper size
1081 this._cacheHelperProportions();
1082
1083 //If ddmanager is used for droppables, set the global draggable
1084 if($.ui.ddmanager) {
1085 $.ui.ddmanager.current = this;
1086 }
1087
1088 /*
1089 * - Position generation -
1090 * This block generates everything position related - it's the core of draggables.
1091 */
1092
1093 //Cache the margins of the original element
1094 this._cacheMargins();
1095
1096 //Store the helper's css position
1097 this.cssPosition = this.helper.css( "position" );
1098 this.scrollParent = this.helper.scrollParent();
1099 this.offsetParent = this.helper.offsetParent();
1100 this.offsetParentCssPosition = this.offsetParent.css( "position" );
1101
1102 //The element's absolute position on the page minus margins
1103 this.offset = this.positionAbs = this.element.offset();
1104 this.offset = {
1105 top: this.offset.top - this.margins.top,
1106 left: this.offset.left - this.margins.left
1107 };
1108
1109 //Reset scroll cache
1110 this.offset.scroll = false;
1111
1112 $.extend(this.offset, {
1113 click: { //Where the click happened, relative to the element
1114 left: event.pageX - this.offset.left,
1115 top: event.pageY - this.offset.top
1116 },
1117 parent: this._getParentOffset(),
1118 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
1119 });
1120
1121 //Generate the original position
1122 this.originalPosition = this.position = this._generatePosition(event);
1123 this.originalPageX = event.pageX;
1124 this.originalPageY = event.pageY;
1125
1126 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
1127 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
1128
1129 //Set a containment if given in the options
1130 this._setContainment();
1131
1132 //Trigger event + callbacks
1133 if(this._trigger("start", event) === false) {
1134 this._clear();
1135 return false;
1136 }
1137
1138 //Recache the helper size
1139 this._cacheHelperProportions();
1140
1141 //Prepare the droppable offsets
1142 if ($.ui.ddmanager && !o.dropBehaviour) {
1143 $.ui.ddmanager.prepareOffsets(this, event);
1144 }
1145
1146
1147 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
1148
1149 //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
1150 if ( $.ui.ddmanager ) {
1151 $.ui.ddmanager.dragStart(this, event);
1152 }
1153
1154 return true;
1155 },
1156
1157 _mouseDrag: function(event, noPropagation) {
1158 // reset any necessary cached properties (see #5009)
1159 if ( this.offsetParentCssPosition === "fixed" ) {
1160 this.offset.parent = this._getParentOffset();
1161 }
1162
1163 //Compute the helpers position
1164 this.position = this._generatePosition(event);
1165 this.positionAbs = this._convertPositionTo("absolute");
1166
1167 //Call plugins and callbacks and use the resulting position if something is returned
1168 if (!noPropagation) {
1169 var ui = this._uiHash();
1170 if(this._trigger("drag", event, ui) === false) {
1171 this._mouseUp({});
1172 return false;
1173 }
1174 this.position = ui.position;
1175 }
1176
1177 if(!this.options.axis || this.options.axis !== "y") {
1178 this.helper[0].style.left = this.position.left+"px";
1179 }
1180 if(!this.options.axis || this.options.axis !== "x") {
1181 this.helper[0].style.top = this.position.top+"px";
1182 }
1183 if($.ui.ddmanager) {
1184 $.ui.ddmanager.drag(this, event);
1185 }
1186
1187 return false;
1188 },
1189
1190 _mouseStop: function(event) {
1191
1192 //If we are using droppables, inform the manager about the drop
1193 var that = this,
1194 dropped = false;
1195 if ($.ui.ddmanager && !this.options.dropBehaviour) {
1196 dropped = $.ui.ddmanager.drop(this, event);
1197 }
1198
1199 //if a drop comes from outside (a sortable)
1200 if(this.dropped) {
1201 dropped = this.dropped;
1202 this.dropped = false;
1203 }
1204
1205 //if the original element is no longer in the DOM don't bother to continue (see #8269)
1206 if ( this.options.helper === "original" && !$.contains( this.element[ 0 ].ownerDocument, this.element[ 0 ] ) ) {
1207 return false;
1208 }
1209
1210 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))) {
1211 $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
1212 if(that._trigger("stop", event) !== false) {
1213 that._clear();
1214 }
1215 });
1216 } else {
1217 if(this._trigger("stop", event) !== false) {
1218 this._clear();
1219 }
1220 }
1221
1222 return false;
1223 },
1224
1225 _mouseUp: function(event) {
1226 //Remove frame helpers
1227 $("div.ui-draggable-iframeFix").each(function() {
1228 this.parentNode.removeChild(this);
1229 });
1230
1231 //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
1232 if( $.ui.ddmanager ) {
1233 $.ui.ddmanager.dragStop(this, event);
1234 }
1235
1236 return $.ui.mouse.prototype._mouseUp.call(this, event);
1237 },
1238
1239 cancel: function() {
1240
1241 if(this.helper.is(".ui-draggable-dragging")) {
1242 this._mouseUp({});
1243 } else {
1244 this._clear();
1245 }
1246
1247 return this;
1248
1249 },
1250
1251 _getHandle: function(event) {
1252 return this.options.handle ?
1253 !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
1254 true;
1255 },
1256
1257 _createHelper: function(event) {
1258
1259 var o = this.options,
1260 helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper === "clone" ? this.element.clone().removeAttr("id") : this.element);
1261
1262 if(!helper.parents("body").length) {
1263 helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo));
1264 }
1265
1266 if(helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) {
1267 helper.css("position", "absolute");
1268 }
1269
1270 return helper;
1271
1272 },
1273
1274 _adjustOffsetFromHelper: function(obj) {
1275 if (typeof obj === "string") {
1276 obj = obj.split(" ");
1277 }
1278 if ($.isArray(obj)) {
1279 obj = {left: +obj[0], top: +obj[1] || 0};
1280 }
1281 if ("left" in obj) {
1282 this.offset.click.left = obj.left + this.margins.left;
1283 }
1284 if ("right" in obj) {
1285 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
1286 }
1287 if ("top" in obj) {
1288 this.offset.click.top = obj.top + this.margins.top;
1289 }
1290 if ("bottom" in obj) {
1291 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
1292 }
1293 },
1294
1295 _getParentOffset: function() {
1296
1297 //Get the offsetParent and cache its position
1298 var po = this.offsetParent.offset();
1299
1300 // This is a special case where we need to modify a offset calculated on start, since the following happened:
1301 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
1302 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
1303 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
1304 if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
1305 po.left += this.scrollParent.scrollLeft();
1306 po.top += this.scrollParent.scrollTop();
1307 }
1308
1309 //This needs to be actually done for all browsers, since pageX/pageY includes this information
1310 //Ugly IE fix
1311 if((this.offsetParent[0] === document.body) ||
1312 (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
1313 po = { top: 0, left: 0 };
1314 }
1315
1316 return {
1317 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
1318 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
1319 };
1320
1321 },
1322
1323 _getRelativeOffset: function() {
1324
1325 if(this.cssPosition === "relative") {
1326 var p = this.element.position();
1327 return {
1328 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
1329 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
1330 };
1331 } else {
1332 return { top: 0, left: 0 };
1333 }
1334
1335 },
1336
1337 _cacheMargins: function() {
1338 this.margins = {
1339 left: (parseInt(this.element.css("marginLeft"),10) || 0),
1340 top: (parseInt(this.element.css("marginTop"),10) || 0),
1341 right: (parseInt(this.element.css("marginRight"),10) || 0),
1342 bottom: (parseInt(this.element.css("marginBottom"),10) || 0)
1343 };
1344 },
1345
1346 _cacheHelperProportions: function() {
1347 this.helperProportions = {
1348 width: this.helper.outerWidth(),
1349 height: this.helper.outerHeight()
1350 };
1351 },
1352
1353 _setContainment: function() {
1354
1355 var over, c, ce,
1356 o = this.options;
1357
1358 if ( !o.containment ) {
1359 this.containment = null;
1360 return;
1361 }
1362
1363 if ( o.containment === "window" ) {
1364 this.containment = [
1365 $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
1366 $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
1367 $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left,
1368 $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
1369 ];
1370 return;
1371 }
1372
1373 if ( o.containment === "document") {
1374 this.containment = [
1375 0,
1376 0,
1377 $( document ).width() - this.helperProportions.width - this.margins.left,
1378 ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
1379 ];
1380 return;
1381 }
1382
1383 if ( o.containment.constructor === Array ) {
1384 this.containment = o.containment;
1385 return;
1386 }
1387
1388 if ( o.containment === "parent" ) {
1389 o.containment = this.helper[ 0 ].parentNode;
1390 }
1391
1392 c = $( o.containment );
1393 ce = c[ 0 ];
1394
1395 if( !ce ) {
1396 return;
1397 }
1398
1399 over = c.css( "overflow" ) !== "hidden";
1400
1401 this.containment = [
1402 ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
1403 ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ) ,
1404 ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) - this.helperProportions.width - this.margins.left - this.margins.right,
1405 ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) - this.helperProportions.height - this.margins.top - this.margins.bottom
1406 ];
1407 this.relative_container = c;
1408 },
1409
1410 _convertPositionTo: function(d, pos) {
1411
1412 if(!pos) {
1413 pos = this.position;
1414 }
1415
1416 var mod = d === "absolute" ? 1 : -1,
1417 scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent;
1418
1419 //Cache the scroll
1420 if (!this.offset.scroll) {
1421 this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()};
1422 }
1423
1424 return {
1425 top: (
1426 pos.top + // The absolute mouse position
1427 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
1428 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
1429 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top ) * mod )
1430 ),
1431 left: (
1432 pos.left + // The absolute mouse position
1433 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
1434 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
1435 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left ) * mod )
1436 )
1437 };
1438
1439 },
1440
1441 _generatePosition: function(event) {
1442
1443 var containment, co, top, left,
1444 o = this.options,
1445 scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent,
1446 pageX = event.pageX,
1447 pageY = event.pageY;
1448
1449 //Cache the scroll
1450 if (!this.offset.scroll) {
1451 this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()};
1452 }
1453
1454 /*
1455 * - Position constraining -
1456 * Constrain the position to a mix of grid, containment.
1457 */
1458
1459 // If we are not dragging yet, we won't check for options
1460 if ( this.originalPosition ) {
1461 if ( this.containment ) {
1462 if ( this.relative_container ){
1463 co = this.relative_container.offset();
1464 containment = [
1465 this.containment[ 0 ] + co.left,
1466 this.containment[ 1 ] + co.top,
1467 this.containment[ 2 ] + co.left,
1468 this.containment[ 3 ] + co.top
1469 ];
1470 }
1471 else {
1472 containment = this.containment;
1473 }
1474
1475 if(event.pageX - this.offset.click.left < containment[0]) {
1476 pageX = containment[0] + this.offset.click.left;
1477 }
1478 if(event.pageY - this.offset.click.top < containment[1]) {
1479 pageY = containment[1] + this.offset.click.top;
1480 }
1481 if(event.pageX - this.offset.click.left > containment[2]) {
1482 pageX = containment[2] + this.offset.click.left;
1483 }
1484 if(event.pageY - this.offset.click.top > containment[3]) {
1485 pageY = containment[3] + this.offset.click.top;
1486 }
1487 }
1488
1489 if(o.grid) {
1490 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
1491 top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
1492 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;
1493
1494 left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
1495 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;
1496 }
1497
1498 }
1499
1500 return {
1501 top: (
1502 pageY - // The absolute mouse position
1503 this.offset.click.top - // Click offset (relative to the element)
1504 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
1505 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
1506 ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top )
1507 ),
1508 left: (
1509 pageX - // The absolute mouse position
1510 this.offset.click.left - // Click offset (relative to the element)
1511 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
1512 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
1513 ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left )
1514 )
1515 };
1516
1517 },
1518
1519 _clear: function() {
1520 this.helper.removeClass("ui-draggable-dragging");
1521 if(this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) {
1522 this.helper.remove();
1523 }
1524 this.helper = null;
1525 this.cancelHelperRemoval = false;
1526 },
1527
1528 // From now on bulk stuff - mainly helpers
1529
1530 _trigger: function(type, event, ui) {
1531 ui = ui || this._uiHash();
1532 $.ui.plugin.call(this, type, [event, ui]);
1533 //The absolute position has to be recalculated after plugins
1534 if(type === "drag") {
1535 this.positionAbs = this._convertPositionTo("absolute");
1536 }
1537 return $.Widget.prototype._trigger.call(this, type, event, ui);
1538 },
1539
1540 plugins: {},
1541
1542 _uiHash: function() {
1543 return {
1544 helper: this.helper,
1545 position: this.position,
1546 originalPosition: this.originalPosition,
1547 offset: this.positionAbs
1548 };
1549 }
1550
1551 });
1552
1553 $.ui.plugin.add("draggable", "connectToSortable", {
1554 start: function(event, ui) {
1555
1556 var inst = $(this).data("ui-draggable"), o = inst.options,
1557 uiSortable = $.extend({}, ui, { item: inst.element });
1558 inst.sortables = [];
1559 $(o.connectToSortable).each(function() {
1560 var sortable = $.data(this, "ui-sortable");
1561 if (sortable && !sortable.options.disabled) {
1562 inst.sortables.push({
1563 instance: sortable,
1564 shouldRevert: sortable.options.revert
1565 });
1566 sortable.refreshPositions(); // Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page).
1567 sortable._trigger("activate", event, uiSortable);
1568 }
1569 });
1570
1571 },
1572 stop: function(event, ui) {
1573
1574 //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
1575 var inst = $(this).data("ui-draggable"),
1576 uiSortable = $.extend({}, ui, { item: inst.element });
1577
1578 $.each(inst.sortables, function() {
1579 if(this.instance.isOver) {
1580
1581 this.instance.isOver = 0;
1582
1583 inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
1584 this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
1585
1586 //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: "valid/invalid"
1587 if(this.shouldRevert) {
1588 this.instance.options.revert = this.shouldRevert;
1589 }
1590
1591 //Trigger the stop of the sortable
1592 this.instance._mouseStop(event);
1593
1594 this.instance.options.helper = this.instance.options._helper;
1595
1596 //If the helper has been the original item, restore properties in the sortable
1597 if(inst.options.helper === "original") {
1598 this.instance.currentItem.css({ top: "auto", left: "auto" });
1599 }
1600
1601 } else {
1602 this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
1603 this.instance._trigger("deactivate", event, uiSortable);
1604 }
1605
1606 });
1607
1608 },
1609 drag: function(event, ui) {
1610
1611 var inst = $(this).data("ui-draggable"), that = this;
1612
1613 $.each(inst.sortables, function() {
1614
1615 var innermostIntersecting = false,
1616 thisSortable = this;
1617
1618 //Copy over some variables to allow calling the sortable's native _intersectsWith
1619 this.instance.positionAbs = inst.positionAbs;
1620 this.instance.helperProportions = inst.helperProportions;
1621 this.instance.offset.click = inst.offset.click;
1622
1623 if(this.instance._intersectsWith(this.instance.containerCache)) {
1624 innermostIntersecting = true;
1625 $.each(inst.sortables, function () {
1626 this.instance.positionAbs = inst.positionAbs;
1627 this.instance.helperProportions = inst.helperProportions;
1628 this.instance.offset.click = inst.offset.click;
1629 if (this !== thisSortable &&
1630 this.instance._intersectsWith(this.instance.containerCache) &&
1631 $.contains(thisSortable.instance.element[0], this.instance.element[0])
1632 ) {
1633 innermostIntersecting = false;
1634 }
1635 return innermostIntersecting;
1636 });
1637 }
1638
1639
1640 if(innermostIntersecting) {
1641 //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
1642 if(!this.instance.isOver) {
1643
1644 this.instance.isOver = 1;
1645 //Now we fake the start of dragging for the sortable instance,
1646 //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
1647 //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one)
1648 this.instance.currentItem = $(that).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item", true);
1649 this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
1650 this.instance.options.helper = function() { return ui.helper[0]; };
1651
1652 event.target = this.instance.currentItem[0];
1653 this.instance._mouseCapture(event, true);
1654 this.instance._mouseStart(event, true, true);
1655
1656 //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
1657 this.instance.offset.click.top = inst.offset.click.top;
1658 this.instance.offset.click.left = inst.offset.click.left;
1659 this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
1660 this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
1661
1662 inst._trigger("toSortable", event);
1663 inst.dropped = this.instance.element; //draggable revert needs that
1664 //hack so receive/update callbacks work (mostly)
1665 inst.currentItem = inst.element;
1666 this.instance.fromOutside = inst;
1667
1668 }
1669
1670 //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable
1671 if(this.instance.currentItem) {
1672 this.instance._mouseDrag(event);
1673 }
1674
1675 } else {
1676
1677 //If it doesn't intersect with the sortable, and it intersected before,
1678 //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
1679 if(this.instance.isOver) {
1680
1681 this.instance.isOver = 0;
1682 this.instance.cancelHelperRemoval = true;
1683
1684 //Prevent reverting on this forced stop
1685 this.instance.options.revert = false;
1686
1687 // The out event needs to be triggered independently
1688 this.instance._trigger("out", event, this.instance._uiHash(this.instance));
1689
1690 this.instance._mouseStop(event, true);
1691 this.instance.options.helper = this.instance.options._helper;
1692
1693 //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
1694 this.instance.currentItem.remove();
1695 if(this.instance.placeholder) {
1696 this.instance.placeholder.remove();
1697 }
1698
1699 inst._trigger("fromSortable", event);
1700 inst.dropped = false; //draggable revert needs that
1701 }
1702
1703 }
1704
1705 });
1706
1707 }
1708 });
1709
1710 $.ui.plugin.add("draggable", "cursor", {
1711 start: function() {
1712 var t = $("body"), o = $(this).data("ui-draggable").options;
1713 if (t.css("cursor")) {
1714 o._cursor = t.css("cursor");
1715 }
1716 t.css("cursor", o.cursor);
1717 },
1718 stop: function() {
1719 var o = $(this).data("ui-draggable").options;
1720 if (o._cursor) {
1721 $("body").css("cursor", o._cursor);
1722 }
1723 }
1724 });
1725
1726 $.ui.plugin.add("draggable", "opacity", {
1727 start: function(event, ui) {
1728 var t = $(ui.helper), o = $(this).data("ui-draggable").options;
1729 if(t.css("opacity")) {
1730 o._opacity = t.css("opacity");
1731 }
1732 t.css("opacity", o.opacity);
1733 },
1734 stop: function(event, ui) {
1735 var o = $(this).data("ui-draggable").options;
1736 if(o._opacity) {
1737 $(ui.helper).css("opacity", o._opacity);
1738 }
1739 }
1740 });
1741
1742 $.ui.plugin.add("draggable", "scroll", {
1743 start: function() {
1744 var i = $(this).data("ui-draggable");
1745 if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") {
1746 i.overflowOffset = i.scrollParent.offset();
1747 }
1748 },
1749 drag: function( event ) {
1750
1751 var i = $(this).data("ui-draggable"), o = i.options, scrolled = false;
1752
1753 if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") {
1754
1755 if(!o.axis || o.axis !== "x") {
1756 if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
1757 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
1758 } else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) {
1759 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
1760 }
1761 }
1762
1763 if(!o.axis || o.axis !== "y") {
1764 if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
1765 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
1766 } else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) {
1767 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
1768 }
1769 }
1770
1771 } else {
1772
1773 if(!o.axis || o.axis !== "x") {
1774 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
1775 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
1776 } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
1777 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
1778 }
1779 }
1780
1781 if(!o.axis || o.axis !== "y") {
1782 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
1783 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
1784 } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
1785 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
1786 }
1787 }
1788
1789 }
1790
1791 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
1792 $.ui.ddmanager.prepareOffsets(i, event);
1793 }
1794
1795 }
1796 });
1797
1798 $.ui.plugin.add("draggable", "snap", {
1799 start: function() {
1800
1801 var i = $(this).data("ui-draggable"),
1802 o = i.options;
1803
1804 i.snapElements = [];
1805
1806 $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() {
1807 var $t = $(this),
1808 $o = $t.offset();
1809 if(this !== i.element[0]) {
1810 i.snapElements.push({
1811 item: this,
1812 width: $t.outerWidth(), height: $t.outerHeight(),
1813 top: $o.top, left: $o.left
1814 });
1815 }
1816 });
1817
1818 },
1819 drag: function(event, ui) {
1820
1821 var ts, bs, ls, rs, l, r, t, b, i, first,
1822 inst = $(this).data("ui-draggable"),
1823 o = inst.options,
1824 d = o.snapTolerance,
1825 x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
1826 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
1827
1828 for (i = inst.snapElements.length - 1; i >= 0; i--){
1829
1830 l = inst.snapElements[i].left;
1831 r = l + inst.snapElements[i].width;
1832 t = inst.snapElements[i].top;
1833 b = t + inst.snapElements[i].height;
1834
1835 if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) {
1836 if(inst.snapElements[i].snapping) {
1837 (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
1838 }
1839 inst.snapElements[i].snapping = false;
1840 continue;
1841 }
1842
1843 if(o.snapMode !== "inner") {
1844 ts = Math.abs(t - y2) <= d;
1845 bs = Math.abs(b - y1) <= d;
1846 ls = Math.abs(l - x2) <= d;
1847 rs = Math.abs(r - x1) <= d;
1848 if(ts) {
1849 ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
1850 }
1851 if(bs) {
1852 ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
1853 }
1854 if(ls) {
1855 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
1856 }
1857 if(rs) {
1858 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
1859 }
1860 }
1861
1862 first = (ts || bs || ls || rs);
1863
1864 if(o.snapMode !== "outer") {
1865 ts = Math.abs(t - y1) <= d;
1866 bs = Math.abs(b - y2) <= d;
1867 ls = Math.abs(l - x1) <= d;
1868 rs = Math.abs(r - x2) <= d;
1869 if(ts) {
1870 ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
1871 }
1872 if(bs) {
1873 ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
1874 }
1875 if(ls) {
1876 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
1877 }
1878 if(rs) {
1879 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
1880 }
1881 }
1882
1883 if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) {
1884 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
1885 }
1886 inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
1887
1888 }
1889
1890 }
1891 });
1892
1893 $.ui.plugin.add("draggable", "stack", {
1894 start: function() {
1895 var min,
1896 o = this.data("ui-draggable").options,
1897 group = $.makeArray($(o.stack)).sort(function(a,b) {
1898 return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0);
1899 });
1900
1901 if (!group.length) { return; }
1902
1903 min = parseInt($(group[0]).css("zIndex"), 10) || 0;
1904 $(group).each(function(i) {
1905 $(this).css("zIndex", min + i);
1906 });
1907 this.css("zIndex", (min + group.length));
1908 }
1909 });
1910
1911 $.ui.plugin.add("draggable", "zIndex", {
1912 start: function(event, ui) {
1913 var t = $(ui.helper), o = $(this).data("ui-draggable").options;
1914 if(t.css("zIndex")) {
1915 o._zIndex = t.css("zIndex");
1916 }
1917 t.css("zIndex", o.zIndex);
1918 },
1919 stop: function(event, ui) {
1920 var o = $(this).data("ui-draggable").options;
1921 if(o._zIndex) {
1922 $(ui.helper).css("zIndex", o._zIndex);
1923 }
1924 }
1925 });
1926
1927 })(jQuery);
1928
1929 (function( $, undefined ) {
1930
1931 function isOverAxis( x, reference, size ) {
1932 return ( x > reference ) && ( x < ( reference + size ) );
1933 }
1934
1935 $.widget("ui.droppable", {
1936 version: "1.10.4",
1937 widgetEventPrefix: "drop",
1938 options: {
1939 accept: "*",
1940 activeClass: false,
1941 addClasses: true,
1942 greedy: false,
1943 hoverClass: false,
1944 scope: "default",
1945 tolerance: "intersect",
1946
1947 // callbacks
1948 activate: null,
1949 deactivate: null,
1950 drop: null,
1951 out: null,
1952 over: null
1953 },
1954 _create: function() {
1955
1956 var proportions,
1957 o = this.options,
1958 accept = o.accept;
1959
1960 this.isover = false;
1961 this.isout = true;
1962
1963 this.accept = $.isFunction(accept) ? accept : function(d) {
1964 return d.is(accept);
1965 };
1966
1967 this.proportions = function( /* valueToWrite */ ) {
1968 if ( arguments.length ) {
1969 // Store the droppable's proportions
1970 proportions = arguments[ 0 ];
1971 } else {
1972 // Retrieve or derive the droppable's proportions
1973 return proportions ?
1974 proportions :
1975 proportions = {
1976 width: this.element[ 0 ].offsetWidth,
1977 height: this.element[ 0 ].offsetHeight
1978 };
1979 }
1980 };
1981
1982 // Add the reference and positions to the manager
1983 $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || [];
1984 $.ui.ddmanager.droppables[o.scope].push(this);
1985
1986 (o.addClasses && this.element.addClass("ui-droppable"));
1987
1988 },
1989
1990 _destroy: function() {
1991 var i = 0,
1992 drop = $.ui.ddmanager.droppables[this.options.scope];
1993
1994 for ( ; i < drop.length; i++ ) {
1995 if ( drop[i] === this ) {
1996 drop.splice(i, 1);
1997 }
1998 }
1999
2000 this.element.removeClass("ui-droppable ui-droppable-disabled");
2001 },
2002
2003 _setOption: function(key, value) {
2004
2005 if(key === "accept") {
2006 this.accept = $.isFunction(value) ? value : function(d) {
2007 return d.is(value);
2008 };
2009 }
2010 $.Widget.prototype._setOption.apply(this, arguments);
2011 },
2012
2013 _activate: function(event) {
2014 var draggable = $.ui.ddmanager.current;
2015 if(this.options.activeClass) {
2016 this.element.addClass(this.options.activeClass);
2017 }
2018 if(draggable){
2019 this._trigger("activate", event, this.ui(draggable));
2020 }
2021 },
2022
2023 _deactivate: function(event) {
2024 var draggable = $.ui.ddmanager.current;
2025 if(this.options.activeClass) {
2026 this.element.removeClass(this.options.activeClass);
2027 }
2028 if(draggable){
2029 this._trigger("deactivate", event, this.ui(draggable));
2030 }
2031 },
2032
2033 _over: function(event) {
2034
2035 var draggable = $.ui.ddmanager.current;
2036
2037 // Bail if draggable and droppable are same element
2038 if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
2039 return;
2040 }
2041
2042 if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
2043 if(this.options.hoverClass) {
2044 this.element.addClass(this.options.hoverClass);
2045 }
2046 this._trigger("over", event, this.ui(draggable));
2047 }
2048
2049 },
2050
2051 _out: function(event) {
2052
2053 var draggable = $.ui.ddmanager.current;
2054
2055 // Bail if draggable and droppable are same element
2056 if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
2057 return;
2058 }
2059
2060 if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
2061 if(this.options.hoverClass) {
2062 this.element.removeClass(this.options.hoverClass);
2063 }
2064 this._trigger("out", event, this.ui(draggable));
2065 }
2066
2067 },
2068
2069 _drop: function(event,custom) {
2070
2071 var draggable = custom || $.ui.ddmanager.current,
2072 childrenIntersection = false;
2073
2074 // Bail if draggable and droppable are same element
2075 if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
2076 return false;
2077 }
2078
2079 this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function() {
2080 var inst = $.data(this, "ui-droppable");
2081 if(
2082 inst.options.greedy &&
2083 !inst.options.disabled &&
2084 inst.options.scope === draggable.options.scope &&
2085 inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) &&
2086 $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)
2087 ) { childrenIntersection = true; return false; }
2088 });
2089 if(childrenIntersection) {
2090 return false;
2091 }
2092
2093 if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
2094 if(this.options.activeClass) {
2095 this.element.removeClass(this.options.activeClass);
2096 }
2097 if(this.options.hoverClass) {
2098 this.element.removeClass(this.options.hoverClass);
2099 }
2100 this._trigger("drop", event, this.ui(draggable));
2101 return this.element;
2102 }
2103
2104 return false;
2105
2106 },
2107
2108 ui: function(c) {
2109 return {
2110 draggable: (c.currentItem || c.element),
2111 helper: c.helper,
2112 position: c.position,
2113 offset: c.positionAbs
2114 };
2115 }
2116
2117 });
2118
2119 $.ui.intersect = function(draggable, droppable, toleranceMode) {
2120
2121 if (!droppable.offset) {
2122 return false;
2123 }
2124
2125 var draggableLeft, draggableTop,
2126 x1 = (draggable.positionAbs || draggable.position.absolute).left,
2127 y1 = (draggable.positionAbs || draggable.position.absolute).top,
2128 x2 = x1 + draggable.helperProportions.width,
2129 y2 = y1 + draggable.helperProportions.height,
2130 l = droppable.offset.left,
2131 t = droppable.offset.top,
2132 r = l + droppable.proportions().width,
2133 b = t + droppable.proportions().height;
2134
2135 switch (toleranceMode) {
2136 case "fit":
2137 return (l <= x1 && x2 <= r && t <= y1 && y2 <= b);
2138 case "intersect":
2139 return (l < x1 + (draggable.helperProportions.width / 2) && // Right Half
2140 x2 - (draggable.helperProportions.width / 2) < r && // Left Half
2141 t < y1 + (draggable.helperProportions.height / 2) && // Bottom Half
2142 y2 - (draggable.helperProportions.height / 2) < b ); // Top Half
2143 case "pointer":
2144 draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left);
2145 draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top);
2146 return isOverAxis( draggableTop, t, droppable.proportions().height ) && isOverAxis( draggableLeft, l, droppable.proportions().width );
2147 case "touch":
2148 return (
2149 (y1 >= t && y1 <= b) || // Top edge touching
2150 (y2 >= t && y2 <= b) || // Bottom edge touching
2151 (y1 < t && y2 > b) // Surrounded vertically
2152 ) && (
2153 (x1 >= l && x1 <= r) || // Left edge touching
2154 (x2 >= l && x2 <= r) || // Right edge touching
2155 (x1 < l && x2 > r) // Surrounded horizontally
2156 );
2157 default:
2158 return false;
2159 }
2160
2161 };
2162
2163 /*
2164 This manager tracks offsets of draggables and droppables
2165 */
2166 $.ui.ddmanager = {
2167 current: null,
2168 droppables: { "default": [] },
2169 prepareOffsets: function(t, event) {
2170
2171 var i, j,
2172 m = $.ui.ddmanager.droppables[t.options.scope] || [],
2173 type = event ? event.type : null, // workaround for #2317
2174 list = (t.currentItem || t.element).find(":data(ui-droppable)").addBack();
2175
2176 droppablesLoop: for (i = 0; i < m.length; i++) {
2177
2178 //No disabled and non-accepted
2179 if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) {
2180 continue;
2181 }
2182
2183 // Filter out elements in the current dragged item
2184 for (j=0; j < list.length; j++) {
2185 if(list[j] === m[i].element[0]) {
2186 m[i].proportions().height = 0;
2187 continue droppablesLoop;
2188 }
2189 }
2190
2191 m[i].visible = m[i].element.css("display") !== "none";
2192 if(!m[i].visible) {
2193 continue;
2194 }
2195
2196 //Activate the droppable if used directly from draggables
2197 if(type === "mousedown") {
2198 m[i]._activate.call(m[i], event);
2199 }
2200
2201 m[ i ].offset = m[ i ].element.offset();
2202 m[ i ].proportions({ width: m[ i ].element[ 0 ].offsetWidth, height: m[ i ].element[ 0 ].offsetHeight });
2203
2204 }
2205
2206 },
2207 drop: function(draggable, event) {
2208
2209 var dropped = false;
2210 // Create a copy of the droppables in case the list changes during the drop (#9116)
2211 $.each(($.ui.ddmanager.droppables[draggable.options.scope] || []).slice(), function() {
2212
2213 if(!this.options) {
2214 return;
2215 }
2216 if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) {
2217 dropped = this._drop.call(this, event) || dropped;
2218 }
2219
2220 if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
2221 this.isout = true;
2222 this.isover = false;
2223 this._deactivate.call(this, event);
2224 }
2225
2226 });
2227 return dropped;
2228
2229 },
2230 dragStart: function( draggable, event ) {
2231 //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
2232 draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
2233 if( !draggable.options.refreshPositions ) {
2234 $.ui.ddmanager.prepareOffsets( draggable, event );
2235 }
2236 });
2237 },
2238 drag: function(draggable, event) {
2239
2240 //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
2241 if(draggable.options.refreshPositions) {
2242 $.ui.ddmanager.prepareOffsets(draggable, event);
2243 }
2244
2245 //Run through all droppables and check their positions based on specific tolerance options
2246 $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
2247
2248 if(this.options.disabled || this.greedyChild || !this.visible) {
2249 return;
2250 }
2251
2252 var parentInstance, scope, parent,
2253 intersects = $.ui.intersect(draggable, this, this.options.tolerance),
2254 c = !intersects && this.isover ? "isout" : (intersects && !this.isover ? "isover" : null);
2255 if(!c) {
2256 return;
2257 }
2258
2259 if (this.options.greedy) {
2260 // find droppable parents with same scope
2261 scope = this.options.scope;
2262 parent = this.element.parents(":data(ui-droppable)").filter(function () {
2263 return $.data(this, "ui-droppable").options.scope === scope;
2264 });
2265
2266 if (parent.length) {
2267 parentInstance = $.data(parent[0], "ui-droppable");
2268 parentInstance.greedyChild = (c === "isover");
2269 }
2270 }
2271
2272 // we just moved into a greedy child
2273 if (parentInstance && c === "isover") {
2274 parentInstance.isover = false;
2275 parentInstance.isout = true;
2276 parentInstance._out.call(parentInstance, event);
2277 }
2278
2279 this[c] = true;
2280 this[c === "isout" ? "isover" : "isout"] = false;
2281 this[c === "isover" ? "_over" : "_out"].call(this, event);
2282
2283 // we just moved out of a greedy child
2284 if (parentInstance && c === "isout") {
2285 parentInstance.isout = false;
2286 parentInstance.isover = true;
2287 parentInstance._over.call(parentInstance, event);
2288 }
2289 });
2290
2291 },
2292 dragStop: function( draggable, event ) {
2293 draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
2294 //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
2295 if( !draggable.options.refreshPositions ) {
2296 $.ui.ddmanager.prepareOffsets( draggable, event );
2297 }
2298 }
2299 };
2300
2301 })(jQuery);
2302
2303 (function( $, undefined ) {
2304
2305 function num(v) {
2306 return parseInt(v, 10) || 0;
2307 }
2308
2309 function isNumber(value) {
2310 return !isNaN(parseInt(value, 10));
2311 }
2312
2313 $.widget("ui.resizable", $.ui.mouse, {
2314 version: "1.10.4",
2315 widgetEventPrefix: "resize",
2316 options: {
2317 alsoResize: false,
2318 animate: false,
2319 animateDuration: "slow",
2320 animateEasing: "swing",
2321 aspectRatio: false,
2322 autoHide: false,
2323 containment: false,
2324 ghost: false,
2325 grid: false,
2326 handles: "e,s,se",
2327 helper: false,
2328 maxHeight: null,
2329 maxWidth: null,
2330 minHeight: 10,
2331 minWidth: 10,
2332 // See #7960
2333 zIndex: 90,
2334
2335 // callbacks
2336 resize: null,
2337 start: null,
2338 stop: null
2339 },
2340 _create: function() {
2341
2342 var n, i, handle, axis, hname,
2343 that = this,
2344 o = this.options;
2345 this.element.addClass("ui-resizable");
2346
2347 $.extend(this, {
2348 _aspectRatio: !!(o.aspectRatio),
2349 aspectRatio: o.aspectRatio,
2350 originalElement: this.element,
2351 _proportionallyResizeElements: [],
2352 _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
2353 });
2354
2355 //Wrap the element if it cannot hold child nodes
2356 if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {
2357
2358 //Create a wrapper element and set the wrapper to the new current internal element
2359 this.element.wrap(
2360 $("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({
2361 position: this.element.css("position"),
2362 width: this.element.outerWidth(),
2363 height: this.element.outerHeight(),
2364 top: this.element.css("top"),
2365 left: this.element.css("left")
2366 })
2367 );
2368
2369 //Overwrite the original this.element
2370 this.element = this.element.parent().data(
2371 "ui-resizable", this.element.data("ui-resizable")
2372 );
2373
2374 this.elementIsWrapper = true;
2375
2376 //Move margins to the wrapper
2377 this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") });
2378 this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});
2379
2380 //Prevent Safari textarea resize
2381 this.originalResizeStyle = this.originalElement.css("resize");
2382 this.originalElement.css("resize", "none");
2383
2384 //Push the actual element to our proportionallyResize internal array
2385 this._proportionallyResizeElements.push(this.originalElement.css({ position: "static", zoom: 1, display: "block" }));
2386
2387 // avoid IE jump (hard set the margin)
2388 this.originalElement.css({ margin: this.originalElement.css("margin") });
2389
2390 // fix handlers offset
2391 this._proportionallyResize();
2392
2393 }
2394
2395 this.handles = o.handles || (!$(".ui-resizable-handle", this.element).length ? "e,s,se" : { n: ".ui-resizable-n", e: ".ui-resizable-e", s: ".ui-resizable-s", w: ".ui-resizable-w", se: ".ui-resizable-se", sw: ".ui-resizable-sw", ne: ".ui-resizable-ne", nw: ".ui-resizable-nw" });
2396 if(this.handles.constructor === String) {
2397
2398 if ( this.handles === "all") {
2399 this.handles = "n,e,s,w,se,sw,ne,nw";
2400 }
2401
2402 n = this.handles.split(",");
2403 this.handles = {};
2404
2405 for(i = 0; i < n.length; i++) {
2406
2407 handle = $.trim(n[i]);
2408 hname = "ui-resizable-"+handle;
2409 axis = $("<div class='ui-resizable-handle " + hname + "'></div>");
2410
2411 // Apply zIndex to all handles - see #7960
2412 axis.css({ zIndex: o.zIndex });
2413
2414 //TODO : What's going on here?
2415 if ("se" === handle) {
2416 axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se");
2417 }
2418
2419 //Insert into internal handles object and append to element
2420 this.handles[handle] = ".ui-resizable-"+handle;
2421 this.element.append(axis);
2422 }
2423
2424 }
2425
2426 this._renderAxis = function(target) {
2427
2428 var i, axis, padPos, padWrapper;
2429
2430 target = target || this.element;
2431
2432 for(i in this.handles) {
2433
2434 if(this.handles[i].constructor === String) {
2435 this.handles[i] = $(this.handles[i], this.element).show();
2436 }
2437
2438 //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)
2439 if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {
2440
2441 axis = $(this.handles[i], this.element);
2442
2443 //Checking the correct pad and border
2444 padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
2445
2446 //The padding type i have to apply...
2447 padPos = [ "padding",
2448 /ne|nw|n/.test(i) ? "Top" :
2449 /se|sw|s/.test(i) ? "Bottom" :
2450 /^e$/.test(i) ? "Right" : "Left" ].join("");
2451
2452 target.css(padPos, padWrapper);
2453
2454 this._proportionallyResize();
2455
2456 }
2457
2458 //TODO: What's that good for? There's not anything to be executed left
2459 if(!$(this.handles[i]).length) {
2460 continue;
2461 }
2462 }
2463 };
2464
2465 //TODO: make renderAxis a prototype function
2466 this._renderAxis(this.element);
2467
2468 this._handles = $(".ui-resizable-handle", this.element)
2469 .disableSelection();
2470
2471 //Matching axis name
2472 this._handles.mouseover(function() {
2473 if (!that.resizing) {
2474 if (this.className) {
2475 axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
2476 }
2477 //Axis, default = se
2478 that.axis = axis && axis[1] ? axis[1] : "se";
2479 }
2480 });
2481
2482 //If we want to auto hide the elements
2483 if (o.autoHide) {
2484 this._handles.hide();
2485 $(this.element)
2486 .addClass("ui-resizable-autohide")
2487 .mouseenter(function() {
2488 if (o.disabled) {
2489 return;
2490 }
2491 $(this).removeClass("ui-resizable-autohide");
2492 that._handles.show();
2493 })
2494 .mouseleave(function(){
2495 if (o.disabled) {
2496 return;
2497 }
2498 if (!that.resizing) {
2499 $(this).addClass("ui-resizable-autohide");
2500 that._handles.hide();
2501 }
2502 });
2503 }
2504
2505 //Initialize the mouse interaction
2506 this._mouseInit();
2507
2508 },
2509
2510 _destroy: function() {
2511
2512 this._mouseDestroy();
2513
2514 var wrapper,
2515 _destroy = function(exp) {
2516 $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
2517 .removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove();
2518 };
2519
2520 //TODO: Unwrap at same DOM position
2521 if (this.elementIsWrapper) {
2522 _destroy(this.element);
2523 wrapper = this.element;
2524 this.originalElement.css({
2525 position: wrapper.css("position"),
2526 width: wrapper.outerWidth(),
2527 height: wrapper.outerHeight(),
2528 top: wrapper.css("top"),
2529 left: wrapper.css("left")
2530 }).insertAfter( wrapper );
2531 wrapper.remove();
2532 }
2533
2534 this.originalElement.css("resize", this.originalResizeStyle);
2535 _destroy(this.originalElement);
2536
2537 return this;
2538 },
2539
2540 _mouseCapture: function(event) {
2541 var i, handle,
2542 capture = false;
2543
2544 for (i in this.handles) {
2545 handle = $(this.handles[i])[0];
2546 if (handle === event.target || $.contains(handle, event.target)) {
2547 capture = true;
2548 }
2549 }
2550
2551 return !this.options.disabled && capture;
2552 },
2553
2554 _mouseStart: function(event) {
2555
2556 var curleft, curtop, cursor,
2557 o = this.options,
2558 iniPos = this.element.position(),
2559 el = this.element;
2560
2561 this.resizing = true;
2562
2563 // bugfix for http://dev.jquery.com/ticket/1749
2564 if ( (/absolute/).test( el.css("position") ) ) {
2565 el.css({ position: "absolute", top: el.css("top"), left: el.css("left") });
2566 } else if (el.is(".ui-draggable")) {
2567 el.css({ position: "absolute", top: iniPos.top, left: iniPos.left });
2568 }
2569
2570 this._renderProxy();
2571
2572 curleft = num(this.helper.css("left"));
2573 curtop = num(this.helper.css("top"));
2574
2575 if (o.containment) {
2576 curleft += $(o.containment).scrollLeft() || 0;
2577 curtop += $(o.containment).scrollTop() || 0;
2578 }
2579
2580 //Store needed variables
2581 this.offset = this.helper.offset();
2582 this.position = { left: curleft, top: curtop };
2583 this.size = this._helper ? { width: this.helper.width(), height: this.helper.height() } : { width: el.width(), height: el.height() };
2584 this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
2585 this.originalPosition = { left: curleft, top: curtop };
2586 this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };
2587 this.originalMousePosition = { left: event.pageX, top: event.pageY };
2588
2589 //Aspect Ratio
2590 this.aspectRatio = (typeof o.aspectRatio === "number") ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1);
2591
2592 cursor = $(".ui-resizable-" + this.axis).css("cursor");
2593 $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor);
2594
2595 el.addClass("ui-resizable-resizing");
2596 this._propagate("start", event);
2597 return true;
2598 },
2599
2600 _mouseDrag: function(event) {
2601
2602 //Increase performance, avoid regex
2603 var data,
2604 el = this.helper, props = {},
2605 smp = this.originalMousePosition,
2606 a = this.axis,
2607 prevTop = this.position.top,
2608 prevLeft = this.position.left,
2609 prevWidth = this.size.width,
2610 prevHeight = this.size.height,
2611 dx = (event.pageX-smp.left)||0,
2612 dy = (event.pageY-smp.top)||0,
2613 trigger = this._change[a];
2614
2615 if (!trigger) {
2616 return false;
2617 }
2618
2619 // Calculate the attrs that will be change
2620 data = trigger.apply(this, [event, dx, dy]);
2621
2622 // Put this in the mouseDrag handler since the user can start pressing shift while resizing
2623 this._updateVirtualBoundaries(event.shiftKey);
2624 if (this._aspectRatio || event.shiftKey) {
2625 data = this._updateRatio(data, event);
2626 }
2627
2628 data = this._respectSize(data, event);
2629
2630 this._updateCache(data);
2631
2632 // plugins callbacks need to be called first
2633 this._propagate("resize", event);
2634
2635 if (this.position.top !== prevTop) {
2636 props.top = this.position.top + "px";
2637 }
2638 if (this.position.left !== prevLeft) {
2639 props.left = this.position.left + "px";
2640 }
2641 if (this.size.width !== prevWidth) {
2642 props.width = this.size.width + "px";
2643 }
2644 if (this.size.height !== prevHeight) {
2645 props.height = this.size.height + "px";
2646 }
2647 el.css(props);
2648
2649 if (!this._helper && this._proportionallyResizeElements.length) {
2650 this._proportionallyResize();
2651 }
2652
2653 // Call the user callback if the element was resized
2654 if ( ! $.isEmptyObject(props) ) {
2655 this._trigger("resize", event, this.ui());
2656 }
2657
2658 return false;
2659 },
2660
2661 _mouseStop: function(event) {
2662
2663 this.resizing = false;
2664 var pr, ista, soffseth, soffsetw, s, left, top,
2665 o = this.options, that = this;
2666
2667 if(this._helper) {
2668
2669 pr = this._proportionallyResizeElements;
2670 ista = pr.length && (/textarea/i).test(pr[0].nodeName);
2671 soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height;
2672 soffsetw = ista ? 0 : that.sizeDiff.width;
2673
2674 s = { width: (that.helper.width() - soffsetw), height: (that.helper.height() - soffseth) };
2675 left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null;
2676 top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null;
2677
2678 if (!o.animate) {
2679 this.element.css($.extend(s, { top: top, left: left }));
2680 }
2681
2682 that.helper.height(that.size.height);
2683 that.helper.width(that.size.width);
2684
2685 if (this._helper && !o.animate) {
2686 this._proportionallyResize();
2687 }
2688 }
2689
2690 $("body").css("cursor", "auto");
2691
2692 this.element.removeClass("ui-resizable-resizing");
2693
2694 this._propagate("stop", event);
2695
2696 if (this._helper) {
2697 this.helper.remove();
2698 }
2699
2700 return false;
2701
2702 },
2703
2704 _updateVirtualBoundaries: function(forceAspectRatio) {
2705 var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
2706 o = this.options;
2707
2708 b = {
2709 minWidth: isNumber(o.minWidth) ? o.minWidth : 0,
2710 maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity,
2711 minHeight: isNumber(o.minHeight) ? o.minHeight : 0,
2712 maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity
2713 };
2714
2715 if(this._aspectRatio || forceAspectRatio) {
2716 // We want to create an enclosing box whose aspect ration is the requested one
2717 // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension
2718 pMinWidth = b.minHeight * this.aspectRatio;
2719 pMinHeight = b.minWidth / this.aspectRatio;
2720 pMaxWidth = b.maxHeight * this.aspectRatio;
2721 pMaxHeight = b.maxWidth / this.aspectRatio;
2722
2723 if(pMinWidth > b.minWidth) {
2724 b.minWidth = pMinWidth;
2725 }
2726 if(pMinHeight > b.minHeight) {
2727 b.minHeight = pMinHeight;
2728 }
2729 if(pMaxWidth < b.maxWidth) {
2730 b.maxWidth = pMaxWidth;
2731 }
2732 if(pMaxHeight < b.maxHeight) {
2733 b.maxHeight = pMaxHeight;
2734 }
2735 }
2736 this._vBoundaries = b;
2737 },
2738
2739 _updateCache: function(data) {
2740 this.offset = this.helper.offset();
2741 if (isNumber(data.left)) {
2742 this.position.left = data.left;
2743 }
2744 if (isNumber(data.top)) {
2745 this.position.top = data.top;
2746 }
2747 if (isNumber(data.height)) {
2748 this.size.height = data.height;
2749 }
2750 if (isNumber(data.width)) {
2751 this.size.width = data.width;
2752 }
2753 },
2754
2755 _updateRatio: function( data ) {
2756
2757 var cpos = this.position,
2758 csize = this.size,
2759 a = this.axis;
2760
2761 if (isNumber(data.height)) {
2762 data.width = (data.height * this.aspectRatio);
2763 } else if (isNumber(data.width)) {
2764 data.height = (data.width / this.aspectRatio);
2765 }
2766
2767 if (a === "sw") {
2768 data.left = cpos.left + (csize.width - data.width);
2769 data.top = null;
2770 }
2771 if (a === "nw") {
2772 data.top = cpos.top + (csize.height - data.height);
2773 data.left = cpos.left + (csize.width - data.width);
2774 }
2775
2776 return data;
2777 },
2778
2779 _respectSize: function( data ) {
2780
2781 var o = this._vBoundaries,
2782 a = this.axis,
2783 ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
2784 isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height),
2785 dw = this.originalPosition.left + this.originalSize.width,
2786 dh = this.position.top + this.size.height,
2787 cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
2788 if (isminw) {
2789 data.width = o.minWidth;
2790 }
2791 if (isminh) {
2792 data.height = o.minHeight;
2793 }
2794 if (ismaxw) {
2795 data.width = o.maxWidth;
2796 }
2797 if (ismaxh) {
2798 data.height = o.maxHeight;
2799 }
2800
2801 if (isminw && cw) {
2802 data.left = dw - o.minWidth;
2803 }
2804 if (ismaxw && cw) {
2805 data.left = dw - o.maxWidth;
2806 }
2807 if (isminh && ch) {
2808 data.top = dh - o.minHeight;
2809 }
2810 if (ismaxh && ch) {
2811 data.top = dh - o.maxHeight;
2812 }
2813
2814 // fixing jump error on top/left - bug #2330
2815 if (!data.width && !data.height && !data.left && data.top) {
2816 data.top = null;
2817 } else if (!data.width && !data.height && !data.top && data.left) {
2818 data.left = null;
2819 }
2820
2821 return data;
2822 },
2823
2824 _proportionallyResize: function() {
2825
2826 if (!this._proportionallyResizeElements.length) {
2827 return;
2828 }
2829
2830 var i, j, borders, paddings, prel,
2831 element = this.helper || this.element;
2832
2833 for ( i=0; i < this._proportionallyResizeElements.length; i++) {
2834
2835 prel = this._proportionallyResizeElements[i];
2836
2837 if (!this.borderDif) {
2838 this.borderDif = [];
2839 borders = [prel.css("borderTopWidth"), prel.css("borderRightWidth"), prel.css("borderBottomWidth"), prel.css("borderLeftWidth")];
2840 paddings = [prel.css("paddingTop"), prel.css("paddingRight"), prel.css("paddingBottom"), prel.css("paddingLeft")];
2841
2842 for ( j = 0; j < borders.length; j++ ) {
2843 this.borderDif[ j ] = ( parseInt( borders[ j ], 10 ) || 0 ) + ( parseInt( paddings[ j ], 10 ) || 0 );
2844 }
2845 }
2846
2847 prel.css({
2848 height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0,
2849 width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0
2850 });
2851
2852 }
2853
2854 },
2855
2856 _renderProxy: function() {
2857
2858 var el = this.element, o = this.options;
2859 this.elementOffset = el.offset();
2860
2861 if(this._helper) {
2862
2863 this.helper = this.helper || $("<div style='overflow:hidden;'></div>");
2864
2865 this.helper.addClass(this._helper).css({
2866 width: this.element.outerWidth() - 1,
2867 height: this.element.outerHeight() - 1,
2868 position: "absolute",
2869 left: this.elementOffset.left +"px",
2870 top: this.elementOffset.top +"px",
2871 zIndex: ++o.zIndex //TODO: Don't modify option
2872 });
2873
2874 this.helper
2875 .appendTo("body")
2876 .disableSelection();
2877
2878 } else {
2879 this.helper = this.element;
2880 }
2881
2882 },
2883
2884 _change: {
2885 e: function(event, dx) {
2886 return { width: this.originalSize.width + dx };
2887 },
2888 w: function(event, dx) {
2889 var cs = this.originalSize, sp = this.originalPosition;
2890 return { left: sp.left + dx, width: cs.width - dx };
2891 },
2892 n: function(event, dx, dy) {
2893 var cs = this.originalSize, sp = this.originalPosition;
2894 return { top: sp.top + dy, height: cs.height - dy };
2895 },
2896 s: function(event, dx, dy) {
2897 return { height: this.originalSize.height + dy };
2898 },
2899 se: function(event, dx, dy) {
2900 return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
2901 },
2902 sw: function(event, dx, dy) {
2903 return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
2904 },
2905 ne: function(event, dx, dy) {
2906 return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
2907 },
2908 nw: function(event, dx, dy) {
2909 return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
2910 }
2911 },
2912
2913 _propagate: function(n, event) {
2914 $.ui.plugin.call(this, n, [event, this.ui()]);
2915 (n !== "resize" && this._trigger(n, event, this.ui()));
2916 },
2917
2918 plugins: {},
2919
2920 ui: function() {
2921 return {
2922 originalElement: this.originalElement,
2923 element: this.element,
2924 helper: this.helper,
2925 position: this.position,
2926 size: this.size,
2927 originalSize: this.originalSize,
2928 originalPosition: this.originalPosition
2929 };
2930 }
2931
2932 });
2933
2934 /*
2935 * Resizable Extensions
2936 */
2937
2938 $.ui.plugin.add("resizable", "animate", {
2939
2940 stop: function( event ) {
2941 var that = $(this).data("ui-resizable"),
2942 o = that.options,
2943 pr = that._proportionallyResizeElements,
2944 ista = pr.length && (/textarea/i).test(pr[0].nodeName),
2945 soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height,
2946 soffsetw = ista ? 0 : that.sizeDiff.width,
2947 style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) },
2948 left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null,
2949 top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null;
2950
2951 that.element.animate(
2952 $.extend(style, top && left ? { top: top, left: left } : {}), {
2953 duration: o.animateDuration,
2954 easing: o.animateEasing,
2955 step: function() {
2956
2957 var data = {
2958 width: parseInt(that.element.css("width"), 10),
2959 height: parseInt(that.element.css("height"), 10),
2960 top: parseInt(that.element.css("top"), 10),
2961 left: parseInt(that.element.css("left"), 10)
2962 };
2963
2964 if (pr && pr.length) {
2965 $(pr[0]).css({ width: data.width, height: data.height });
2966 }
2967
2968 // propagating resize, and updating values for each animation step
2969 that._updateCache(data);
2970 that._propagate("resize", event);
2971
2972 }
2973 }
2974 );
2975 }
2976
2977 });
2978
2979 $.ui.plugin.add("resizable", "containment", {
2980
2981 start: function() {
2982 var element, p, co, ch, cw, width, height,
2983 that = $(this).data("ui-resizable"),
2984 o = that.options,
2985 el = that.element,
2986 oc = o.containment,
2987 ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc;
2988
2989 if (!ce) {
2990 return;
2991 }
2992
2993 that.containerElement = $(ce);
2994
2995 if (/document/.test(oc) || oc === document) {
2996 that.containerOffset = { left: 0, top: 0 };
2997 that.containerPosition = { left: 0, top: 0 };
2998
2999 that.parentData = {
3000 element: $(document), left: 0, top: 0,
3001 width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight
3002 };
3003 }
3004
3005 // i'm a node, so compute top, left, right, bottom
3006 else {
3007 element = $(ce);
3008 p = [];
3009 $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); });
3010
3011 that.containerOffset = element.offset();
3012 that.containerPosition = element.position();
3013 that.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) };
3014
3015 co = that.containerOffset;
3016 ch = that.containerSize.height;
3017 cw = that.containerSize.width;
3018 width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw );
3019 height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch);
3020
3021 that.parentData = {
3022 element: ce, left: co.left, top: co.top, width: width, height: height
3023 };
3024 }
3025 },
3026
3027 resize: function( event ) {
3028 var woset, hoset, isParent, isOffsetRelative,
3029 that = $(this).data("ui-resizable"),
3030 o = that.options,
3031 co = that.containerOffset, cp = that.position,
3032 pRatio = that._aspectRatio || event.shiftKey,
3033 cop = { top:0, left:0 }, ce = that.containerElement;
3034
3035 if (ce[0] !== document && (/static/).test(ce.css("position"))) {
3036 cop = co;
3037 }
3038
3039 if (cp.left < (that._helper ? co.left : 0)) {
3040 that.size.width = that.size.width + (that._helper ? (that.position.left - co.left) : (that.position.left - cop.left));
3041 if (pRatio) {
3042 that.size.height = that.size.width / that.aspectRatio;
3043 }
3044 that.position.left = o.helper ? co.left : 0;
3045 }
3046
3047 if (cp.top < (that._helper ? co.top : 0)) {
3048 that.size.height = that.size.height + (that._helper ? (that.position.top - co.top) : that.position.top);
3049 if (pRatio) {
3050 that.size.width = that.size.height * that.aspectRatio;
3051 }
3052 that.position.top = that._helper ? co.top : 0;
3053 }
3054
3055 that.offset.left = that.parentData.left+that.position.left;
3056 that.offset.top = that.parentData.top+that.position.top;
3057
3058 woset = Math.abs( (that._helper ? that.offset.left - cop.left : (that.offset.left - cop.left)) + that.sizeDiff.width );
3059 hoset = Math.abs( (that._helper ? that.offset.top - cop.top : (that.offset.top - co.top)) + that.sizeDiff.height );
3060
3061 isParent = that.containerElement.get(0) === that.element.parent().get(0);
3062 isOffsetRelative = /relative|absolute/.test(that.containerElement.css("position"));
3063
3064 if ( isParent && isOffsetRelative ) {
3065 woset -= Math.abs( that.parentData.left );
3066 }
3067
3068 if (woset + that.size.width >= that.parentData.width) {
3069 that.size.width = that.parentData.width - woset;
3070 if (pRatio) {
3071 that.size.height = that.size.width / that.aspectRatio;
3072 }
3073 }
3074
3075 if (hoset + that.size.height >= that.parentData.height) {
3076 that.size.height = that.parentData.height - hoset;
3077 if (pRatio) {
3078 that.size.width = that.size.height * that.aspectRatio;
3079 }
3080 }
3081 },
3082
3083 stop: function(){
3084 var that = $(this).data("ui-resizable"),
3085 o = that.options,
3086 co = that.containerOffset,
3087 cop = that.containerPosition,
3088 ce = that.containerElement,
3089 helper = $(that.helper),
3090 ho = helper.offset(),
3091 w = helper.outerWidth() - that.sizeDiff.width,
3092 h = helper.outerHeight() - that.sizeDiff.height;
3093
3094 if (that._helper && !o.animate && (/relative/).test(ce.css("position"))) {
3095 $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
3096 }
3097
3098 if (that._helper && !o.animate && (/static/).test(ce.css("position"))) {
3099 $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
3100 }
3101
3102 }
3103 });
3104
3105 $.ui.plugin.add("resizable", "alsoResize", {
3106
3107 start: function () {
3108 var that = $(this).data("ui-resizable"),
3109 o = that.options,
3110 _store = function (exp) {
3111 $(exp).each(function() {
3112 var el = $(this);
3113 el.data("ui-resizable-alsoresize", {
3114 width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
3115 left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10)
3116 });
3117 });
3118 };
3119
3120 if (typeof(o.alsoResize) === "object" && !o.alsoResize.parentNode) {
3121 if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); }
3122 else { $.each(o.alsoResize, function (exp) { _store(exp); }); }
3123 }else{
3124 _store(o.alsoResize);
3125 }
3126 },
3127
3128 resize: function (event, ui) {
3129 var that = $(this).data("ui-resizable"),
3130 o = that.options,
3131 os = that.originalSize,
3132 op = that.originalPosition,
3133 delta = {
3134 height: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0,
3135 top: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0
3136 },
3137
3138 _alsoResize = function (exp, c) {
3139 $(exp).each(function() {
3140 var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {},
3141 css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ["width", "height"] : ["width", "height", "top", "left"];
3142
3143 $.each(css, function (i, prop) {
3144 var sum = (start[prop]||0) + (delta[prop]||0);
3145 if (sum && sum >= 0) {
3146 style[prop] = sum || null;
3147 }
3148 });
3149
3150 el.css(style);
3151 });
3152 };
3153
3154 if (typeof(o.alsoResize) === "object" && !o.alsoResize.nodeType) {
3155 $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); });
3156 }else{
3157 _alsoResize(o.alsoResize);
3158 }
3159 },
3160
3161 stop: function () {
3162 $(this).removeData("resizable-alsoresize");
3163 }
3164 });
3165
3166 $.ui.plugin.add("resizable", "ghost", {
3167
3168 start: function() {
3169
3170 var that = $(this).data("ui-resizable"), o = that.options, cs = that.size;
3171
3172 that.ghost = that.originalElement.clone();
3173 that.ghost
3174 .css({ opacity: 0.25, display: "block", position: "relative", height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 })
3175 .addClass("ui-resizable-ghost")
3176 .addClass(typeof o.ghost === "string" ? o.ghost : "");
3177
3178 that.ghost.appendTo(that.helper);
3179
3180 },
3181
3182 resize: function(){
3183 var that = $(this).data("ui-resizable");
3184 if (that.ghost) {
3185 that.ghost.css({ position: "relative", height: that.size.height, width: that.size.width });
3186 }
3187 },
3188
3189 stop: function() {
3190 var that = $(this).data("ui-resizable");
3191 if (that.ghost && that.helper) {
3192 that.helper.get(0).removeChild(that.ghost.get(0));
3193 }
3194 }
3195
3196 });
3197
3198 $.ui.plugin.add("resizable", "grid", {
3199
3200 resize: function() {
3201 var that = $(this).data("ui-resizable"),
3202 o = that.options,
3203 cs = that.size,
3204 os = that.originalSize,
3205 op = that.originalPosition,
3206 a = that.axis,
3207 grid = typeof o.grid === "number" ? [o.grid, o.grid] : o.grid,
3208 gridX = (grid[0]||1),
3209 gridY = (grid[1]||1),
3210 ox = Math.round((cs.width - os.width) / gridX) * gridX,
3211 oy = Math.round((cs.height - os.height) / gridY) * gridY,
3212 newWidth = os.width + ox,
3213 newHeight = os.height + oy,
3214 isMaxWidth = o.maxWidth && (o.maxWidth < newWidth),
3215 isMaxHeight = o.maxHeight && (o.maxHeight < newHeight),
3216 isMinWidth = o.minWidth && (o.minWidth > newWidth),
3217 isMinHeight = o.minHeight && (o.minHeight > newHeight);
3218
3219 o.grid = grid;
3220
3221 if (isMinWidth) {
3222 newWidth = newWidth + gridX;
3223 }
3224 if (isMinHeight) {
3225 newHeight = newHeight + gridY;
3226 }
3227 if (isMaxWidth) {
3228 newWidth = newWidth - gridX;
3229 }
3230 if (isMaxHeight) {
3231 newHeight = newHeight - gridY;
3232 }
3233
3234 if (/^(se|s|e)$/.test(a)) {
3235 that.size.width = newWidth;
3236 that.size.height = newHeight;
3237 } else if (/^(ne)$/.test(a)) {
3238 that.size.width = newWidth;
3239 that.size.height = newHeight;
3240 that.position.top = op.top - oy;
3241 } else if (/^(sw)$/.test(a)) {
3242 that.size.width = newWidth;
3243 that.size.height = newHeight;
3244 that.position.left = op.left - ox;
3245 } else {
3246 if ( newHeight - gridY > 0 ) {
3247 that.size.height = newHeight;
3248 that.position.top = op.top - oy;
3249 } else {
3250 that.size.height = gridY;
3251 that.position.top = op.top + os.height - gridY;
3252 }
3253 if ( newWidth - gridX > 0 ) {
3254 that.size.width = newWidth;
3255 that.position.left = op.left - ox;
3256 } else {
3257 that.size.width = gridX;
3258 that.position.left = op.left + os.width - gridX;
3259 }
3260 }
3261 }
3262
3263 });
3264
3265 })(jQuery);
3266
3267 (function( $, undefined ) {
3268
3269 $.widget("ui.selectable", $.ui.mouse, {
3270 version: "1.10.4",
3271 options: {
3272 appendTo: "body",
3273 autoRefresh: true,
3274 distance: 0,
3275 filter: "*",
3276 tolerance: "touch",
3277
3278 // callbacks
3279 selected: null,
3280 selecting: null,
3281 start: null,
3282 stop: null,
3283 unselected: null,
3284 unselecting: null
3285 },
3286 _create: function() {
3287 var selectees,
3288 that = this;
3289
3290 this.element.addClass("ui-selectable");
3291
3292 this.dragged = false;
3293
3294 // cache selectee children based on filter
3295 this.refresh = function() {
3296 selectees = $(that.options.filter, that.element[0]);
3297 selectees.addClass("ui-selectee");
3298 selectees.each(function() {
3299 var $this = $(this),
3300 pos = $this.offset();
3301 $.data(this, "selectable-item", {
3302 element: this,
3303 $element: $this,
3304 left: pos.left,
3305 top: pos.top,
3306 right: pos.left + $this.outerWidth(),
3307 bottom: pos.top + $this.outerHeight(),
3308 startselected: false,
3309 selected: $this.hasClass("ui-selected"),
3310 selecting: $this.hasClass("ui-selecting"),
3311 unselecting: $this.hasClass("ui-unselecting")
3312 });
3313 });
3314 };
3315 this.refresh();
3316
3317 this.selectees = selectees.addClass("ui-selectee");
3318
3319 this._mouseInit();
3320
3321 this.helper = $("<div class='ui-selectable-helper'></div>");
3322 },
3323
3324 _destroy: function() {
3325 this.selectees
3326 .removeClass("ui-selectee")
3327 .removeData("selectable-item");
3328 this.element
3329 .removeClass("ui-selectable ui-selectable-disabled");
3330 this._mouseDestroy();
3331 },
3332
3333 _mouseStart: function(event) {
3334 var that = this,
3335 options = this.options;
3336
3337 this.opos = [event.pageX, event.pageY];
3338
3339 if (this.options.disabled) {
3340 return;
3341 }
3342
3343 this.selectees = $(options.filter, this.element[0]);
3344
3345 this._trigger("start", event);
3346
3347 $(options.appendTo).append(this.helper);
3348 // position helper (lasso)
3349 this.helper.css({
3350 "left": event.pageX,
3351 "top": event.pageY,
3352 "width": 0,
3353 "height": 0
3354 });
3355
3356 if (options.autoRefresh) {
3357 this.refresh();
3358 }
3359
3360 this.selectees.filter(".ui-selected").each(function() {
3361 var selectee = $.data(this, "selectable-item");
3362 selectee.startselected = true;
3363 if (!event.metaKey && !event.ctrlKey) {
3364 selectee.$element.removeClass("ui-selected");
3365 selectee.selected = false;
3366 selectee.$element.addClass("ui-unselecting");
3367 selectee.unselecting = true;
3368 // selectable UNSELECTING callback
3369 that._trigger("unselecting", event, {
3370 unselecting: selectee.element
3371 });
3372 }
3373 });
3374
3375 $(event.target).parents().addBack().each(function() {
3376 var doSelect,
3377 selectee = $.data(this, "selectable-item");
3378 if (selectee) {
3379 doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected");
3380 selectee.$element
3381 .removeClass(doSelect ? "ui-unselecting" : "ui-selected")
3382 .addClass(doSelect ? "ui-selecting" : "ui-unselecting");
3383 selectee.unselecting = !doSelect;
3384 selectee.selecting = doSelect;
3385 selectee.selected = doSelect;
3386 // selectable (UN)SELECTING callback
3387 if (doSelect) {
3388 that._trigger("selecting", event, {
3389 selecting: selectee.element
3390 });
3391 } else {
3392 that._trigger("unselecting", event, {
3393 unselecting: selectee.element
3394 });
3395 }
3396 return false;
3397 }
3398 });
3399
3400 },
3401
3402 _mouseDrag: function(event) {
3403
3404 this.dragged = true;
3405
3406 if (this.options.disabled) {
3407 return;
3408 }
3409
3410 var tmp,
3411 that = this,
3412 options = this.options,
3413 x1 = this.opos[0],
3414 y1 = this.opos[1],
3415 x2 = event.pageX,
3416 y2 = event.pageY;
3417
3418 if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; }
3419 if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; }
3420 this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1});
3421
3422 this.selectees.each(function() {
3423 var selectee = $.data(this, "selectable-item"),
3424 hit = false;
3425
3426 //prevent helper from being selected if appendTo: selectable
3427 if (!selectee || selectee.element === that.element[0]) {
3428 return;
3429 }
3430
3431 if (options.tolerance === "touch") {
3432 hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
3433 } else if (options.tolerance === "fit") {
3434 hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
3435 }
3436
3437 if (hit) {
3438 // SELECT
3439 if (selectee.selected) {
3440 selectee.$element.removeClass("ui-selected");
3441 selectee.selected = false;
3442 }
3443 if (selectee.unselecting) {
3444 selectee.$element.removeClass("ui-unselecting");
3445 selectee.unselecting = false;
3446 }
3447 if (!selectee.selecting) {
3448 selectee.$element.addClass("ui-selecting");
3449 selectee.selecting = true;
3450 // selectable SELECTING callback
3451 that._trigger("selecting", event, {
3452 selecting: selectee.element
3453 });
3454 }
3455 } else {
3456 // UNSELECT
3457 if (selectee.selecting) {
3458 if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
3459 selectee.$element.removeClass("ui-selecting");
3460 selectee.selecting = false;
3461 selectee.$element.addClass("ui-selected");
3462 selectee.selected = true;
3463 } else {
3464 selectee.$element.removeClass("ui-selecting");
3465 selectee.selecting = false;
3466 if (selectee.startselected) {
3467 selectee.$element.addClass("ui-unselecting");
3468 selectee.unselecting = true;
3469 }
3470 // selectable UNSELECTING callback
3471 that._trigger("unselecting", event, {
3472 unselecting: selectee.element
3473 });
3474 }
3475 }
3476 if (selectee.selected) {
3477 if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
3478 selectee.$element.removeClass("ui-selected");
3479 selectee.selected = false;
3480
3481 selectee.$element.addClass("ui-unselecting");
3482 selectee.unselecting = true;
3483 // selectable UNSELECTING callback
3484 that._trigger("unselecting", event, {
3485 unselecting: selectee.element
3486 });
3487 }
3488 }
3489 }
3490 });
3491
3492 return false;
3493 },
3494
3495 _mouseStop: function(event) {
3496 var that = this;
3497
3498 this.dragged = false;
3499
3500 $(".ui-unselecting", this.element[0]).each(function() {
3501 var selectee = $.data(this, "selectable-item");
3502 selectee.$element.removeClass("ui-unselecting");
3503 selectee.unselecting = false;
3504 selectee.startselected = false;
3505 that._trigger("unselected", event, {
3506 unselected: selectee.element
3507 });
3508 });
3509 $(".ui-selecting", this.element[0]).each(function() {
3510 var selectee = $.data(this, "selectable-item");
3511 selectee.$element.removeClass("ui-selecting").addClass("ui-selected");
3512 selectee.selecting = false;
3513 selectee.selected = true;
3514 selectee.startselected = true;
3515 that._trigger("selected", event, {
3516 selected: selectee.element
3517 });
3518 });
3519 this._trigger("stop", event);
3520
3521 this.helper.remove();
3522
3523 return false;
3524 }
3525
3526 });
3527
3528 })(jQuery);
3529
3530 (function( $, undefined ) {
3531
3532 function isOverAxis( x, reference, size ) {
3533 return ( x > reference ) && ( x < ( reference + size ) );
3534 }
3535
3536 function isFloating(item) {
3537 return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display"));
3538 }
3539
3540 $.widget("ui.sortable", $.ui.mouse, {
3541 version: "1.10.4",
3542 widgetEventPrefix: "sort",
3543 ready: false,
3544 options: {
3545 appendTo: "parent",
3546 axis: false,
3547 connectWith: false,
3548 containment: false,
3549 cursor: "auto",
3550 cursorAt: false,
3551 dropOnEmpty: true,
3552 forcePlaceholderSize: false,
3553 forceHelperSize: false,
3554 grid: false,
3555 handle: false,
3556 helper: "original",
3557 items: "> *",
3558 opacity: false,
3559 placeholder: false,
3560 revert: false,
3561 scroll: true,
3562 scrollSensitivity: 20,
3563 scrollSpeed: 20,
3564 scope: "default",
3565 tolerance: "intersect",
3566 zIndex: 1000,
3567
3568 // callbacks
3569 activate: null,
3570 beforeStop: null,
3571 change: null,
3572 deactivate: null,
3573 out: null,
3574 over: null,
3575 receive: null,
3576 remove: null,
3577 sort: null,
3578 start: null,
3579 stop: null,
3580 update: null
3581 },
3582 _create: function() {
3583
3584 var o = this.options;
3585 this.containerCache = {};
3586 this.element.addClass("ui-sortable");
3587
3588 //Get the items
3589 this.refresh();
3590
3591 //Let's determine if the items are being displayed horizontally
3592 this.floating = this.items.length ? o.axis === "x" || isFloating(this.items[0].item) : false;
3593
3594 //Let's determine the parent's offset
3595 this.offset = this.element.offset();
3596
3597 //Initialize mouse events for interaction
3598 this._mouseInit();
3599
3600 //We're ready to go
3601 this.ready = true;
3602
3603 },
3604
3605 _destroy: function() {
3606 this.element
3607 .removeClass("ui-sortable ui-sortable-disabled");
3608 this._mouseDestroy();
3609
3610 for ( var i = this.items.length - 1; i >= 0; i-- ) {
3611 this.items[i].item.removeData(this.widgetName + "-item");
3612 }
3613
3614 return this;
3615 },
3616
3617 _setOption: function(key, value){
3618 if ( key === "disabled" ) {
3619 this.options[ key ] = value;
3620
3621 this.widget().toggleClass( "ui-sortable-disabled", !!value );
3622 } else {
3623 // Don't call widget base _setOption for disable as it adds ui-state-disabled class
3624 $.Widget.prototype._setOption.apply(this, arguments);
3625 }
3626 },
3627
3628 _mouseCapture: function(event, overrideHandle) {
3629 var currentItem = null,
3630 validHandle = false,
3631 that = this;
3632
3633 if (this.reverting) {
3634 return false;
3635 }
3636
3637 if(this.options.disabled || this.options.type === "static") {
3638 return false;
3639 }
3640
3641 //We have to refresh the items data once first
3642 this._refreshItems(event);
3643
3644 //Find out if the clicked node (or one of its parents) is a actual item in this.items
3645 $(event.target).parents().each(function() {
3646 if($.data(this, that.widgetName + "-item") === that) {
3647 currentItem = $(this);
3648 return false;
3649 }
3650 });
3651 if($.data(event.target, that.widgetName + "-item") === that) {
3652 currentItem = $(event.target);
3653 }
3654
3655 if(!currentItem) {
3656 return false;
3657 }
3658 if(this.options.handle && !overrideHandle) {
3659 $(this.options.handle, currentItem).find("*").addBack().each(function() {
3660 if(this === event.target) {
3661 validHandle = true;
3662 }
3663 });
3664 if(!validHandle) {
3665 return false;
3666 }
3667 }
3668
3669 this.currentItem = currentItem;
3670 this._removeCurrentsFromItems();
3671 return true;
3672
3673 },
3674
3675 _mouseStart: function(event, overrideHandle, noActivation) {
3676
3677 var i, body,
3678 o = this.options;
3679
3680 this.currentContainer = this;
3681
3682 //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
3683 this.refreshPositions();
3684
3685 //Create and append the visible helper
3686 this.helper = this._createHelper(event);
3687
3688 //Cache the helper size
3689 this._cacheHelperProportions();
3690
3691 /*
3692 * - Position generation -
3693 * This block generates everything position related - it's the core of draggables.
3694 */
3695
3696 //Cache the margins of the original element
3697 this._cacheMargins();
3698
3699 //Get the next scrolling parent
3700 this.scrollParent = this.helper.scrollParent();
3701
3702 //The element's absolute position on the page minus margins
3703 this.offset = this.currentItem.offset();
3704 this.offset = {
3705 top: this.offset.top - this.margins.top,
3706 left: this.offset.left - this.margins.left
3707 };
3708
3709 $.extend(this.offset, {
3710 click: { //Where the click happened, relative to the element
3711 left: event.pageX - this.offset.left,
3712 top: event.pageY - this.offset.top
3713 },
3714 parent: this._getParentOffset(),
3715 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
3716 });
3717
3718 // Only after we got the offset, we can change the helper's position to absolute
3719 // TODO: Still need to figure out a way to make relative sorting possible
3720 this.helper.css("position", "absolute");
3721 this.cssPosition = this.helper.css("position");
3722
3723 //Generate the original position
3724 this.originalPosition = this._generatePosition(event);
3725 this.originalPageX = event.pageX;
3726 this.originalPageY = event.pageY;
3727
3728 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
3729 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
3730
3731 //Cache the former DOM position
3732 this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
3733
3734 //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
3735 if(this.helper[0] !== this.currentItem[0]) {
3736 this.currentItem.hide();
3737 }
3738
3739 //Create the placeholder
3740 this._createPlaceholder();
3741
3742 //Set a containment if given in the options
3743 if(o.containment) {
3744 this._setContainment();
3745 }
3746
3747 if( o.cursor && o.cursor !== "auto" ) { // cursor option
3748 body = this.document.find( "body" );
3749
3750 // support: IE
3751 this.storedCursor = body.css( "cursor" );
3752 body.css( "cursor", o.cursor );
3753
3754 this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body );
3755 }
3756
3757 if(o.opacity) { // opacity option
3758 if (this.helper.css("opacity")) {
3759 this._storedOpacity = this.helper.css("opacity");
3760 }
3761 this.helper.css("opacity", o.opacity);
3762 }
3763
3764 if(o.zIndex) { // zIndex option
3765 if (this.helper.css("zIndex")) {
3766 this._storedZIndex = this.helper.css("zIndex");
3767 }
3768 this.helper.css("zIndex", o.zIndex);
3769 }
3770
3771 //Prepare scrolling
3772 if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
3773 this.overflowOffset = this.scrollParent.offset();
3774 }
3775
3776 //Call callbacks
3777 this._trigger("start", event, this._uiHash());
3778
3779 //Recache the helper size
3780 if(!this._preserveHelperProportions) {
3781 this._cacheHelperProportions();
3782 }
3783
3784
3785 //Post "activate" events to possible containers
3786 if( !noActivation ) {
3787 for ( i = this.containers.length - 1; i >= 0; i-- ) {
3788 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
3789 }
3790 }
3791
3792 //Prepare possible droppables
3793 if($.ui.ddmanager) {
3794 $.ui.ddmanager.current = this;
3795 }
3796
3797 if ($.ui.ddmanager && !o.dropBehaviour) {
3798 $.ui.ddmanager.prepareOffsets(this, event);
3799 }
3800
3801 this.dragging = true;
3802
3803 this.helper.addClass("ui-sortable-helper");
3804 this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
3805 return true;
3806
3807 },
3808
3809 _mouseDrag: function(event) {
3810 var i, item, itemElement, intersection,
3811 o = this.options,
3812 scrolled = false;
3813
3814 //Compute the helpers position
3815 this.position = this._generatePosition(event);
3816 this.positionAbs = this._convertPositionTo("absolute");
3817
3818 if (!this.lastPositionAbs) {
3819 this.lastPositionAbs = this.positionAbs;
3820 }
3821
3822 //Do scrolling
3823 if(this.options.scroll) {
3824 if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
3825
3826 if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
3827 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
3828 } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
3829 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
3830 }
3831
3832 if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
3833 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
3834 } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
3835 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
3836 }
3837
3838 } else {
3839
3840 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
3841 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
3842 } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
3843 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
3844 }
3845
3846 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
3847 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
3848 } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
3849 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
3850 }
3851
3852 }
3853
3854 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
3855 $.ui.ddmanager.prepareOffsets(this, event);
3856 }
3857 }
3858
3859 //Regenerate the absolute position used for position checks
3860 this.positionAbs = this._convertPositionTo("absolute");
3861
3862 //Set the helper position
3863 if(!this.options.axis || this.options.axis !== "y") {
3864 this.helper[0].style.left = this.position.left+"px";
3865 }
3866 if(!this.options.axis || this.options.axis !== "x") {
3867 this.helper[0].style.top = this.position.top+"px";
3868 }
3869
3870 //Rearrange
3871 for (i = this.items.length - 1; i >= 0; i--) {
3872
3873 //Cache variables and intersection, continue if no intersection
3874 item = this.items[i];
3875 itemElement = item.item[0];
3876 intersection = this._intersectsWithPointer(item);
3877 if (!intersection) {
3878 continue;
3879 }
3880
3881 // Only put the placeholder inside the current Container, skip all
3882 // items from other containers. This works because when moving
3883 // an item from one container to another the
3884 // currentContainer is switched before the placeholder is moved.
3885 //
3886 // Without this, moving items in "sub-sortables" can cause
3887 // the placeholder to jitter beetween the outer and inner container.
3888 if (item.instance !== this.currentContainer) {
3889 continue;
3890 }
3891
3892 // cannot intersect with itself
3893 // no useless actions that have been done before
3894 // no action if the item moved is the parent of the item checked
3895 if (itemElement !== this.currentItem[0] &&
3896 this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement &&
3897 !$.contains(this.placeholder[0], itemElement) &&
3898 (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true)
3899 ) {
3900
3901 this.direction = intersection === 1 ? "down" : "up";
3902
3903 if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
3904 this._rearrange(event, item);
3905 } else {
3906 break;
3907 }
3908
3909 this._trigger("change", event, this._uiHash());
3910 break;
3911 }
3912 }
3913
3914 //Post events to containers
3915 this._contactContainers(event);
3916
3917 //Interconnect with droppables
3918 if($.ui.ddmanager) {
3919 $.ui.ddmanager.drag(this, event);
3920 }
3921
3922 //Call callbacks
3923 this._trigger("sort", event, this._uiHash());
3924
3925 this.lastPositionAbs = this.positionAbs;
3926 return false;
3927
3928 },
3929
3930 _mouseStop: function(event, noPropagation) {
3931
3932 if(!event) {
3933 return;
3934 }
3935
3936 //If we are using droppables, inform the manager about the drop
3937 if ($.ui.ddmanager && !this.options.dropBehaviour) {
3938 $.ui.ddmanager.drop(this, event);
3939 }
3940
3941 if(this.options.revert) {
3942 var that = this,
3943 cur = this.placeholder.offset(),
3944 axis = this.options.axis,
3945 animation = {};
3946
3947 if ( !axis || axis === "x" ) {
3948 animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft);
3949 }
3950 if ( !axis || axis === "y" ) {
3951 animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop);
3952 }
3953 this.reverting = true;
3954 $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() {
3955 that._clear(event);
3956 });
3957 } else {
3958 this._clear(event, noPropagation);
3959 }
3960
3961 return false;
3962
3963 },
3964
3965 cancel: function() {
3966
3967 if(this.dragging) {
3968
3969 this._mouseUp({ target: null });
3970
3971 if(this.options.helper === "original") {
3972 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
3973 } else {
3974 this.currentItem.show();
3975 }
3976
3977 //Post deactivating events to containers
3978 for (var i = this.containers.length - 1; i >= 0; i--){
3979 this.containers[i]._trigger("deactivate", null, this._uiHash(this));
3980 if(this.containers[i].containerCache.over) {
3981 this.containers[i]._trigger("out", null, this._uiHash(this));
3982 this.containers[i].containerCache.over = 0;
3983 }
3984 }
3985
3986 }
3987
3988 if (this.placeholder) {
3989 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
3990 if(this.placeholder[0].parentNode) {
3991 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
3992 }
3993 if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) {
3994 this.helper.remove();
3995 }
3996
3997 $.extend(this, {
3998 helper: null,
3999 dragging: false,
4000 reverting: false,
4001 _noFinalSort: null
4002 });
4003
4004 if(this.domPosition.prev) {
4005 $(this.domPosition.prev).after(this.currentItem);
4006 } else {
4007 $(this.domPosition.parent).prepend(this.currentItem);
4008 }
4009 }
4010
4011 return this;
4012
4013 },
4014
4015 serialize: function(o) {
4016
4017 var items = this._getItemsAsjQuery(o && o.connected),
4018 str = [];
4019 o = o || {};
4020
4021 $(items).each(function() {
4022 var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/));
4023 if (res) {
4024 str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2]));
4025 }
4026 });
4027
4028 if(!str.length && o.key) {
4029 str.push(o.key + "=");
4030 }
4031
4032 return str.join("&");
4033
4034 },
4035
4036 toArray: function(o) {
4037
4038 var items = this._getItemsAsjQuery(o && o.connected),
4039 ret = [];
4040
4041 o = o || {};
4042
4043 items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); });
4044 return ret;
4045
4046 },
4047
4048 /* Be careful with the following core functions */
4049 _intersectsWith: function(item) {
4050
4051 var x1 = this.positionAbs.left,
4052 x2 = x1 + this.helperProportions.width,
4053 y1 = this.positionAbs.top,
4054 y2 = y1 + this.helperProportions.height,
4055 l = item.left,
4056 r = l + item.width,
4057 t = item.top,
4058 b = t + item.height,
4059 dyClick = this.offset.click.top,
4060 dxClick = this.offset.click.left,
4061 isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ),
4062 isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ),
4063 isOverElement = isOverElementHeight && isOverElementWidth;
4064
4065 if ( this.options.tolerance === "pointer" ||
4066 this.options.forcePointerForContainers ||
4067 (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"])
4068 ) {
4069 return isOverElement;
4070 } else {
4071
4072 return (l < x1 + (this.helperProportions.width / 2) && // Right Half
4073 x2 - (this.helperProportions.width / 2) < r && // Left Half
4074 t < y1 + (this.helperProportions.height / 2) && // Bottom Half
4075 y2 - (this.helperProportions.height / 2) < b ); // Top Half
4076
4077 }
4078 },
4079
4080 _intersectsWithPointer: function(item) {
4081
4082 var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
4083 isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
4084 isOverElement = isOverElementHeight && isOverElementWidth,
4085 verticalDirection = this._getDragVerticalDirection(),
4086 horizontalDirection = this._getDragHorizontalDirection();
4087
4088 if (!isOverElement) {
4089 return false;
4090 }
4091
4092 return this.floating ?
4093 ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 )
4094 : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) );
4095
4096 },
4097
4098 _intersectsWithSides: function(item) {
4099
4100 var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
4101 isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
4102 verticalDirection = this._getDragVerticalDirection(),
4103 horizontalDirection = this._getDragHorizontalDirection();
4104
4105 if (this.floating && horizontalDirection) {
4106 return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf));
4107 } else {
4108 return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf));
4109 }
4110
4111 },
4112
4113 _getDragVerticalDirection: function() {
4114 var delta = this.positionAbs.top - this.lastPositionAbs.top;
4115 return delta !== 0 && (delta > 0 ? "down" : "up");
4116 },
4117
4118 _getDragHorizontalDirection: function() {
4119 var delta = this.positionAbs.left - this.lastPositionAbs.left;
4120 return delta !== 0 && (delta > 0 ? "right" : "left");
4121 },
4122
4123 refresh: function(event) {
4124 this._refreshItems(event);
4125 this.refreshPositions();
4126 return this;
4127 },
4128
4129 _connectWith: function() {
4130 var options = this.options;
4131 return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith;
4132 },
4133
4134 _getItemsAsjQuery: function(connected) {
4135
4136 var i, j, cur, inst,
4137 items = [],
4138 queries = [],
4139 connectWith = this._connectWith();
4140
4141 if(connectWith && connected) {
4142 for (i = connectWith.length - 1; i >= 0; i--){
4143 cur = $(connectWith[i]);
4144 for ( j = cur.length - 1; j >= 0; j--){
4145 inst = $.data(cur[j], this.widgetFullName);
4146 if(inst && inst !== this && !inst.options.disabled) {
4147 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]);
4148 }
4149 }
4150 }
4151 }
4152
4153 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]);
4154
4155 function addItems() {
4156 items.push( this );
4157 }
4158 for (i = queries.length - 1; i >= 0; i--){
4159 queries[i][0].each( addItems );
4160 }
4161
4162 return $(items);
4163
4164 },
4165
4166 _removeCurrentsFromItems: function() {
4167
4168 var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
4169
4170 this.items = $.grep(this.items, function (item) {
4171 for (var j=0; j < list.length; j++) {
4172 if(list[j] === item.item[0]) {
4173 return false;
4174 }
4175 }
4176 return true;
4177 });
4178
4179 },
4180
4181 _refreshItems: function(event) {
4182
4183 this.items = [];
4184 this.containers = [this];
4185
4186 var i, j, cur, inst, targetData, _queries, item, queriesLength,
4187 items = this.items,
4188 queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]],
4189 connectWith = this._connectWith();
4190
4191 if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
4192 for (i = connectWith.length - 1; i >= 0; i--){
4193 cur = $(connectWith[i]);
4194 for (j = cur.length - 1; j >= 0; j--){
4195 inst = $.data(cur[j], this.widgetFullName);
4196 if(inst && inst !== this && !inst.options.disabled) {
4197 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
4198 this.containers.push(inst);
4199 }
4200 }
4201 }
4202 }
4203
4204 for (i = queries.length - 1; i >= 0; i--) {
4205 targetData = queries[i][1];
4206 _queries = queries[i][0];
4207
4208 for (j=0, queriesLength = _queries.length; j < queriesLength; j++) {
4209 item = $(_queries[j]);
4210
4211 item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager)
4212
4213 items.push({
4214 item: item,
4215 instance: targetData,
4216 width: 0, height: 0,
4217 left: 0, top: 0
4218 });
4219 }
4220 }
4221
4222 },
4223
4224 refreshPositions: function(fast) {
4225
4226 //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
4227 if(this.offsetParent && this.helper) {
4228 this.offset.parent = this._getParentOffset();
4229 }
4230
4231 var i, item, t, p;
4232
4233 for (i = this.items.length - 1; i >= 0; i--){
4234 item = this.items[i];
4235
4236 //We ignore calculating positions of all connected containers when we're not over them
4237 if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) {
4238 continue;
4239 }
4240
4241 t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
4242
4243 if (!fast) {
4244 item.width = t.outerWidth();
4245 item.height = t.outerHeight();
4246 }
4247
4248 p = t.offset();
4249 item.left = p.left;
4250 item.top = p.top;
4251 }
4252
4253 if(this.options.custom && this.options.custom.refreshContainers) {
4254 this.options.custom.refreshContainers.call(this);
4255 } else {
4256 for (i = this.containers.length - 1; i >= 0; i--){
4257 p = this.containers[i].element.offset();
4258 this.containers[i].containerCache.left = p.left;
4259 this.containers[i].containerCache.top = p.top;
4260 this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
4261 this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
4262 }
4263 }
4264
4265 return this;
4266 },
4267
4268 _createPlaceholder: function(that) {
4269 that = that || this;
4270 var className,
4271 o = that.options;
4272
4273 if(!o.placeholder || o.placeholder.constructor === String) {
4274 className = o.placeholder;
4275 o.placeholder = {
4276 element: function() {
4277
4278 var nodeName = that.currentItem[0].nodeName.toLowerCase(),
4279 element = $( "<" + nodeName + ">", that.document[0] )
4280 .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
4281 .removeClass("ui-sortable-helper");
4282
4283 if ( nodeName === "tr" ) {
4284 that.currentItem.children().each(function() {
4285 $( "<td>&#160;</td>", that.document[0] )
4286 .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
4287 .appendTo( element );
4288 });
4289 } else if ( nodeName === "img" ) {
4290 element.attr( "src", that.currentItem.attr( "src" ) );
4291 }
4292
4293 if ( !className ) {
4294 element.css( "visibility", "hidden" );
4295 }
4296
4297 return element;
4298 },
4299 update: function(container, p) {
4300
4301 // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
4302 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
4303 if(className && !o.forcePlaceholderSize) {
4304 return;
4305 }
4306
4307 //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
4308 if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); }
4309 if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); }
4310 }
4311 };
4312 }
4313
4314 //Create the placeholder
4315 that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));
4316
4317 //Append it after the actual current item
4318 that.currentItem.after(that.placeholder);
4319
4320 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
4321 o.placeholder.update(that, that.placeholder);
4322
4323 },
4324
4325 _contactContainers: function(event) {
4326 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom, floating,
4327 innermostContainer = null,
4328 innermostIndex = null;
4329
4330 // get innermost container that intersects with item
4331 for (i = this.containers.length - 1; i >= 0; i--) {
4332
4333 // never consider a container that's located within the item itself
4334 if($.contains(this.currentItem[0], this.containers[i].element[0])) {
4335 continue;
4336 }
4337
4338 if(this._intersectsWith(this.containers[i].containerCache)) {
4339
4340 // if we've already found a container and it's more "inner" than this, then continue
4341 if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) {
4342 continue;
4343 }
4344
4345 innermostContainer = this.containers[i];
4346 innermostIndex = i;
4347
4348 } else {
4349 // container doesn't intersect. trigger "out" event if necessary
4350 if(this.containers[i].containerCache.over) {
4351 this.containers[i]._trigger("out", event, this._uiHash(this));
4352 this.containers[i].containerCache.over = 0;
4353 }
4354 }
4355
4356 }
4357
4358 // if no intersecting containers found, return
4359 if(!innermostContainer) {
4360 return;
4361 }
4362
4363 // move the item into the container if it's not there already
4364 if(this.containers.length === 1) {
4365 if (!this.containers[innermostIndex].containerCache.over) {
4366 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
4367 this.containers[innermostIndex].containerCache.over = 1;
4368 }
4369 } else {
4370
4371 //When entering a new container, we will find the item with the least distance and append our item near it
4372 dist = 10000;
4373 itemWithLeastDistance = null;
4374 floating = innermostContainer.floating || isFloating(this.currentItem);
4375 posProperty = floating ? "left" : "top";
4376 sizeProperty = floating ? "width" : "height";
4377 base = this.positionAbs[posProperty] + this.offset.click[posProperty];
4378 for (j = this.items.length - 1; j >= 0; j--) {
4379 if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) {
4380 continue;
4381 }
4382 if(this.items[j].item[0] === this.currentItem[0]) {
4383 continue;
4384 }
4385 if (floating && !isOverAxis(this.positionAbs.top + this.offset.click.top, this.items[j].top, this.items[j].height)) {
4386 continue;
4387 }
4388 cur = this.items[j].item.offset()[posProperty];
4389 nearBottom = false;
4390 if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){
4391 nearBottom = true;
4392 cur += this.items[j][sizeProperty];
4393 }
4394
4395 if(Math.abs(cur - base) < dist) {
4396 dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j];
4397 this.direction = nearBottom ? "up": "down";
4398 }
4399 }
4400
4401 //Check if dropOnEmpty is enabled
4402 if(!itemWithLeastDistance && !this.options.dropOnEmpty) {
4403 return;
4404 }
4405
4406 if(this.currentContainer === this.containers[innermostIndex]) {
4407 return;
4408 }
4409
4410 itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
4411 this._trigger("change", event, this._uiHash());
4412 this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
4413 this.currentContainer = this.containers[innermostIndex];
4414
4415 //Update the placeholder
4416 this.options.placeholder.update(this.currentContainer, this.placeholder);
4417
4418 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
4419 this.containers[innermostIndex].containerCache.over = 1;
4420 }
4421
4422
4423 },
4424
4425 _createHelper: function(event) {
4426
4427 var o = this.options,
4428 helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem);
4429
4430 //Add the helper to the DOM if that didn't happen already
4431 if(!helper.parents("body").length) {
4432 $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
4433 }
4434
4435 if(helper[0] === this.currentItem[0]) {
4436 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") };
4437 }
4438
4439 if(!helper[0].style.width || o.forceHelperSize) {
4440 helper.width(this.currentItem.width());
4441 }
4442 if(!helper[0].style.height || o.forceHelperSize) {
4443 helper.height(this.currentItem.height());
4444 }
4445
4446 return helper;
4447
4448 },
4449
4450 _adjustOffsetFromHelper: function(obj) {
4451 if (typeof obj === "string") {
4452 obj = obj.split(" ");
4453 }
4454 if ($.isArray(obj)) {
4455 obj = {left: +obj[0], top: +obj[1] || 0};
4456 }
4457 if ("left" in obj) {
4458 this.offset.click.left = obj.left + this.margins.left;
4459 }
4460 if ("right" in obj) {
4461 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
4462 }
4463 if ("top" in obj) {
4464 this.offset.click.top = obj.top + this.margins.top;
4465 }
4466 if ("bottom" in obj) {
4467 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
4468 }
4469 },
4470
4471 _getParentOffset: function() {
4472
4473
4474 //Get the offsetParent and cache its position
4475 this.offsetParent = this.helper.offsetParent();
4476 var po = this.offsetParent.offset();
4477
4478 // This is a special case where we need to modify a offset calculated on start, since the following happened:
4479 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
4480 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
4481 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
4482 if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
4483 po.left += this.scrollParent.scrollLeft();
4484 po.top += this.scrollParent.scrollTop();
4485 }
4486
4487 // This needs to be actually done for all browsers, since pageX/pageY includes this information
4488 // with an ugly IE fix
4489 if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
4490 po = { top: 0, left: 0 };
4491 }
4492
4493 return {
4494 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
4495 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
4496 };
4497
4498 },
4499
4500 _getRelativeOffset: function() {
4501
4502 if(this.cssPosition === "relative") {
4503 var p = this.currentItem.position();
4504 return {
4505 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
4506 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
4507 };
4508 } else {
4509 return { top: 0, left: 0 };
4510 }
4511
4512 },
4513
4514 _cacheMargins: function() {
4515 this.margins = {
4516 left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
4517 top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
4518 };
4519 },
4520
4521 _cacheHelperProportions: function() {
4522 this.helperProportions = {
4523 width: this.helper.outerWidth(),
4524 height: this.helper.outerHeight()
4525 };
4526 },
4527
4528 _setContainment: function() {
4529
4530 var ce, co, over,
4531 o = this.options;
4532 if(o.containment === "parent") {
4533 o.containment = this.helper[0].parentNode;
4534 }
4535 if(o.containment === "document" || o.containment === "window") {
4536 this.containment = [
4537 0 - this.offset.relative.left - this.offset.parent.left,
4538 0 - this.offset.relative.top - this.offset.parent.top,
4539 $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left,
4540 ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
4541 ];
4542 }
4543
4544 if(!(/^(document|window|parent)$/).test(o.containment)) {
4545 ce = $(o.containment)[0];
4546 co = $(o.containment).offset();
4547 over = ($(ce).css("overflow") !== "hidden");
4548
4549 this.containment = [
4550 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
4551 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
4552 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,
4553 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
4554 ];
4555 }
4556
4557 },
4558
4559 _convertPositionTo: function(d, pos) {
4560
4561 if(!pos) {
4562 pos = this.position;
4563 }
4564 var mod = d === "absolute" ? 1 : -1,
4565 scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,
4566 scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
4567
4568 return {
4569 top: (
4570 pos.top + // The absolute mouse position
4571 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
4572 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
4573 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
4574 ),
4575 left: (
4576 pos.left + // The absolute mouse position
4577 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
4578 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
4579 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
4580 )
4581 };
4582
4583 },
4584
4585 _generatePosition: function(event) {
4586
4587 var top, left,
4588 o = this.options,
4589 pageX = event.pageX,
4590 pageY = event.pageY,
4591 scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
4592
4593 // This is another very weird special case that only happens for relative elements:
4594 // 1. If the css position is relative
4595 // 2. and the scroll parent is the document or similar to the offset parent
4596 // we have to refresh the relative offset during the scroll so there are no jumps
4597 if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) {
4598 this.offset.relative = this._getRelativeOffset();
4599 }
4600
4601 /*
4602 * - Position constraining -
4603 * Constrain the position to a mix of grid, containment.
4604 */
4605
4606 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
4607
4608 if(this.containment) {
4609 if(event.pageX - this.offset.click.left < this.containment[0]) {
4610 pageX = this.containment[0] + this.offset.click.left;
4611 }
4612 if(event.pageY - this.offset.click.top < this.containment[1]) {
4613 pageY = this.containment[1] + this.offset.click.top;
4614 }
4615 if(event.pageX - this.offset.click.left > this.containment[2]) {
4616 pageX = this.containment[2] + this.offset.click.left;
4617 }
4618 if(event.pageY - this.offset.click.top > this.containment[3]) {
4619 pageY = this.containment[3] + this.offset.click.top;
4620 }
4621 }
4622
4623 if(o.grid) {
4624 top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
4625 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;
4626
4627 left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
4628 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;
4629 }
4630
4631 }
4632
4633 return {
4634 top: (
4635 pageY - // The absolute mouse position
4636 this.offset.click.top - // Click offset (relative to the element)
4637 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
4638 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
4639 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
4640 ),
4641 left: (
4642 pageX - // The absolute mouse position
4643 this.offset.click.left - // Click offset (relative to the element)
4644 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
4645 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
4646 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
4647 )
4648 };
4649
4650 },
4651
4652 _rearrange: function(event, i, a, hardRefresh) {
4653
4654 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));
4655
4656 //Various things done here to improve the performance:
4657 // 1. we create a setTimeout, that calls refreshPositions
4658 // 2. on the instance, we have a counter variable, that get's higher after every append
4659 // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
4660 // 4. this lets only the last addition to the timeout stack through
4661 this.counter = this.counter ? ++this.counter : 1;
4662 var counter = this.counter;
4663
4664 this._delay(function() {
4665 if(counter === this.counter) {
4666 this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
4667 }
4668 });
4669
4670 },
4671
4672 _clear: function(event, noPropagation) {
4673
4674 this.reverting = false;
4675 // We delay all events that have to be triggered to after the point where the placeholder has been removed and
4676 // everything else normalized again
4677 var i,
4678 delayedTriggers = [];
4679
4680 // We first have to update the dom position of the actual currentItem
4681 // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
4682 if(!this._noFinalSort && this.currentItem.parent().length) {
4683 this.placeholder.before(this.currentItem);
4684 }
4685 this._noFinalSort = null;
4686
4687 if(this.helper[0] === this.currentItem[0]) {
4688 for(i in this._storedCSS) {
4689 if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") {
4690 this._storedCSS[i] = "";
4691 }
4692 }
4693 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
4694 } else {
4695 this.currentItem.show();
4696 }
4697
4698 if(this.fromOutside && !noPropagation) {
4699 delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
4700 }
4701 if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) {
4702 delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
4703 }
4704
4705 // Check if the items Container has Changed and trigger appropriate
4706 // events.
4707 if (this !== this.currentContainer) {
4708 if(!noPropagation) {
4709 delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
4710 delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
4711 delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
4712 }
4713 }
4714
4715
4716 //Post events to containers
4717 function delayEvent( type, instance, container ) {
4718 return function( event ) {
4719 container._trigger( type, event, instance._uiHash( instance ) );
4720 };
4721 }
4722 for (i = this.containers.length - 1; i >= 0; i--){
4723 if (!noPropagation) {
4724 delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
4725 }
4726 if(this.containers[i].containerCache.over) {
4727 delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
4728 this.containers[i].containerCache.over = 0;
4729 }
4730 }
4731
4732 //Do what was originally in plugins
4733 if ( this.storedCursor ) {
4734 this.document.find( "body" ).css( "cursor", this.storedCursor );
4735 this.storedStylesheet.remove();
4736 }
4737 if(this._storedOpacity) {
4738 this.helper.css("opacity", this._storedOpacity);
4739 }
4740 if(this._storedZIndex) {
4741 this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex);
4742 }
4743
4744 this.dragging = false;
4745 if(this.cancelHelperRemoval) {
4746 if(!noPropagation) {
4747 this._trigger("beforeStop", event, this._uiHash());
4748 for (i=0; i < delayedTriggers.length; i++) {
4749 delayedTriggers[i].call(this, event);
4750 } //Trigger all delayed events
4751 this._trigger("stop", event, this._uiHash());
4752 }
4753
4754 this.fromOutside = false;
4755 return false;
4756 }
4757
4758 if(!noPropagation) {
4759 this._trigger("beforeStop", event, this._uiHash());
4760 }
4761
4762 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
4763 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
4764
4765 if(this.helper[0] !== this.currentItem[0]) {
4766 this.helper.remove();
4767 }
4768 this.helper = null;
4769
4770 if(!noPropagation) {
4771 for (i=0; i < delayedTriggers.length; i++) {
4772 delayedTriggers[i].call(this, event);
4773 } //Trigger all delayed events
4774 this._trigger("stop", event, this._uiHash());
4775 }
4776
4777 this.fromOutside = false;
4778 return true;
4779
4780 },
4781
4782 _trigger: function() {
4783 if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
4784 this.cancel();
4785 }
4786 },
4787
4788 _uiHash: function(_inst) {
4789 var inst = _inst || this;
4790 return {
4791 helper: inst.helper,
4792 placeholder: inst.placeholder || $([]),
4793 position: inst.position,
4794 originalPosition: inst.originalPosition,
4795 offset: inst.positionAbs,
4796 item: inst.currentItem,
4797 sender: _inst ? _inst.element : null
4798 };
4799 }
4800
4801 });
4802
4803 })(jQuery);
4804
4805 (function($, undefined) {
4806
4807 var dataSpace = "ui-effects-";
4808
4809 $.effects = {
4810 effect: {}
4811 };
4812
4813 /*!
4814 * jQuery Color Animations v2.1.2
4815 * https://github.com/jquery/jquery-color
4816 *
4817 * Copyright 2013 jQuery Foundation and other contributors
4818 * Released under the MIT license.
4819 * http://jquery.org/license
4820 *
4821 * Date: Wed Jan 16 08:47:09 2013 -0600
4822 */
4823 (function( jQuery, undefined ) {
4824
4825 var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
4826
4827 // plusequals test for += 100 -= 100
4828 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
4829 // a set of RE's that can match strings and generate color tuples.
4830 stringParsers = [{
4831 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
4832 parse: function( execResult ) {
4833 return [
4834 execResult[ 1 ],
4835 execResult[ 2 ],
4836 execResult[ 3 ],
4837 execResult[ 4 ]
4838 ];
4839 }
4840 }, {
4841 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
4842 parse: function( execResult ) {
4843 return [
4844 execResult[ 1 ] * 2.55,
4845 execResult[ 2 ] * 2.55,
4846 execResult[ 3 ] * 2.55,
4847 execResult[ 4 ]
4848 ];
4849 }
4850 }, {
4851 // this regex ignores A-F because it's compared against an already lowercased string
4852 re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
4853 parse: function( execResult ) {
4854 return [
4855 parseInt( execResult[ 1 ], 16 ),
4856 parseInt( execResult[ 2 ], 16 ),
4857 parseInt( execResult[ 3 ], 16 )
4858 ];
4859 }
4860 }, {
4861 // this regex ignores A-F because it's compared against an already lowercased string
4862 re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
4863 parse: function( execResult ) {
4864 return [
4865 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
4866 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
4867 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
4868 ];
4869 }
4870 }, {
4871 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
4872 space: "hsla",
4873 parse: function( execResult ) {
4874 return [
4875 execResult[ 1 ],
4876 execResult[ 2 ] / 100,
4877 execResult[ 3 ] / 100,
4878 execResult[ 4 ]
4879 ];
4880 }
4881 }],
4882
4883 // jQuery.Color( )
4884 color = jQuery.Color = function( color, green, blue, alpha ) {
4885 return new jQuery.Color.fn.parse( color, green, blue, alpha );
4886 },
4887 spaces = {
4888 rgba: {
4889 props: {
4890 red: {
4891 idx: 0,
4892 type: "byte"
4893 },
4894 green: {
4895 idx: 1,
4896 type: "byte"
4897 },
4898 blue: {
4899 idx: 2,
4900 type: "byte"
4901 }
4902 }
4903 },
4904
4905 hsla: {
4906 props: {
4907 hue: {
4908 idx: 0,
4909 type: "degrees"
4910 },
4911 saturation: {
4912 idx: 1,
4913 type: "percent"
4914 },
4915 lightness: {
4916 idx: 2,
4917 type: "percent"
4918 }
4919 }
4920 }
4921 },
4922 propTypes = {
4923 "byte": {
4924 floor: true,
4925 max: 255
4926 },
4927 "percent": {
4928 max: 1
4929 },
4930 "degrees": {
4931 mod: 360,
4932 floor: true
4933 }
4934 },
4935 support = color.support = {},
4936
4937 // element for support tests
4938 supportElem = jQuery( "<p>" )[ 0 ],
4939
4940 // colors = jQuery.Color.names
4941 colors,
4942
4943 // local aliases of functions called often
4944 each = jQuery.each;
4945
4946 // determine rgba support immediately
4947 supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
4948 support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
4949
4950 // define cache name and alpha properties
4951 // for rgba and hsla spaces
4952 each( spaces, function( spaceName, space ) {
4953 space.cache = "_" + spaceName;
4954 space.props.alpha = {
4955 idx: 3,
4956 type: "percent",
4957 def: 1
4958 };
4959 });
4960
4961 function clamp( value, prop, allowEmpty ) {
4962 var type = propTypes[ prop.type ] || {};
4963
4964 if ( value == null ) {
4965 return (allowEmpty || !prop.def) ? null : prop.def;
4966 }
4967
4968 // ~~ is an short way of doing floor for positive numbers
4969 value = type.floor ? ~~value : parseFloat( value );
4970
4971 // IE will pass in empty strings as value for alpha,
4972 // which will hit this case
4973 if ( isNaN( value ) ) {
4974 return prop.def;
4975 }
4976
4977 if ( type.mod ) {
4978 // we add mod before modding to make sure that negatives values
4979 // get converted properly: -10 -> 350
4980 return (value + type.mod) % type.mod;
4981 }
4982
4983 // for now all property types without mod have min and max
4984 return 0 > value ? 0 : type.max < value ? type.max : value;
4985 }
4986
4987 function stringParse( string ) {
4988 var inst = color(),
4989 rgba = inst._rgba = [];
4990
4991 string = string.toLowerCase();
4992
4993 each( stringParsers, function( i, parser ) {
4994 var parsed,
4995 match = parser.re.exec( string ),
4996 values = match && parser.parse( match ),
4997 spaceName = parser.space || "rgba";
4998
4999 if ( values ) {
5000 parsed = inst[ spaceName ]( values );
5001
5002 // if this was an rgba parse the assignment might happen twice
5003 // oh well....
5004 inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
5005 rgba = inst._rgba = parsed._rgba;
5006
5007 // exit each( stringParsers ) here because we matched
5008 return false;
5009 }
5010 });
5011
5012 // Found a stringParser that handled it
5013 if ( rgba.length ) {
5014
5015 // if this came from a parsed string, force "transparent" when alpha is 0
5016 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
5017 if ( rgba.join() === "0,0,0,0" ) {
5018 jQuery.extend( rgba, colors.transparent );
5019 }
5020 return inst;
5021 }
5022
5023 // named colors
5024 return colors[ string ];
5025 }
5026
5027 color.fn = jQuery.extend( color.prototype, {
5028 parse: function( red, green, blue, alpha ) {
5029 if ( red === undefined ) {
5030 this._rgba = [ null, null, null, null ];
5031 return this;
5032 }
5033 if ( red.jquery || red.nodeType ) {
5034 red = jQuery( red ).css( green );
5035 green = undefined;
5036 }
5037
5038 var inst = this,
5039 type = jQuery.type( red ),
5040 rgba = this._rgba = [];
5041
5042 // more than 1 argument specified - assume ( red, green, blue, alpha )
5043 if ( green !== undefined ) {
5044 red = [ red, green, blue, alpha ];
5045 type = "array";
5046 }
5047
5048 if ( type === "string" ) {
5049 return this.parse( stringParse( red ) || colors._default );
5050 }
5051
5052 if ( type === "array" ) {
5053 each( spaces.rgba.props, function( key, prop ) {
5054 rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
5055 });
5056 return this;
5057 }
5058
5059 if ( type === "object" ) {
5060 if ( red instanceof color ) {
5061 each( spaces, function( spaceName, space ) {
5062 if ( red[ space.cache ] ) {
5063 inst[ space.cache ] = red[ space.cache ].slice();
5064 }
5065 });
5066 } else {
5067 each( spaces, function( spaceName, space ) {
5068 var cache = space.cache;
5069 each( space.props, function( key, prop ) {
5070
5071 // if the cache doesn't exist, and we know how to convert
5072 if ( !inst[ cache ] && space.to ) {
5073
5074 // if the value was null, we don't need to copy it
5075 // if the key was alpha, we don't need to copy it either
5076 if ( key === "alpha" || red[ key ] == null ) {
5077 return;
5078 }
5079 inst[ cache ] = space.to( inst._rgba );
5080 }
5081
5082 // this is the only case where we allow nulls for ALL properties.
5083 // call clamp with alwaysAllowEmpty
5084 inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
5085 });
5086
5087 // everything defined but alpha?
5088 if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
5089 // use the default of 1
5090 inst[ cache ][ 3 ] = 1;
5091 if ( space.from ) {
5092 inst._rgba = space.from( inst[ cache ] );
5093 }
5094 }
5095 });
5096 }
5097 return this;
5098 }
5099 },
5100 is: function( compare ) {
5101 var is = color( compare ),
5102 same = true,
5103 inst = this;
5104
5105 each( spaces, function( _, space ) {
5106 var localCache,
5107 isCache = is[ space.cache ];
5108 if (isCache) {
5109 localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
5110 each( space.props, function( _, prop ) {
5111 if ( isCache[ prop.idx ] != null ) {
5112 same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
5113 return same;
5114 }
5115 });
5116 }
5117 return same;
5118 });
5119 return same;
5120 },
5121 _space: function() {
5122 var used = [],
5123 inst = this;
5124 each( spaces, function( spaceName, space ) {
5125 if ( inst[ space.cache ] ) {
5126 used.push( spaceName );
5127 }
5128 });
5129 return used.pop();
5130 },
5131 transition: function( other, distance ) {
5132 var end = color( other ),
5133 spaceName = end._space(),
5134 space = spaces[ spaceName ],
5135 startColor = this.alpha() === 0 ? color( "transparent" ) : this,
5136 start = startColor[ space.cache ] || space.to( startColor._rgba ),
5137 result = start.slice();
5138
5139 end = end[ space.cache ];
5140 each( space.props, function( key, prop ) {
5141 var index = prop.idx,
5142 startValue = start[ index ],
5143 endValue = end[ index ],
5144 type = propTypes[ prop.type ] || {};
5145
5146 // if null, don't override start value
5147 if ( endValue === null ) {
5148 return;
5149 }
5150 // if null - use end
5151 if ( startValue === null ) {
5152 result[ index ] = endValue;
5153 } else {
5154 if ( type.mod ) {
5155 if ( endValue - startValue > type.mod / 2 ) {
5156 startValue += type.mod;
5157 } else if ( startValue - endValue > type.mod / 2 ) {
5158 startValue -= type.mod;
5159 }
5160 }
5161 result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
5162 }
5163 });
5164 return this[ spaceName ]( result );
5165 },
5166 blend: function( opaque ) {
5167 // if we are already opaque - return ourself
5168 if ( this._rgba[ 3 ] === 1 ) {
5169 return this;
5170 }
5171
5172 var rgb = this._rgba.slice(),
5173 a = rgb.pop(),
5174 blend = color( opaque )._rgba;
5175
5176 return color( jQuery.map( rgb, function( v, i ) {
5177 return ( 1 - a ) * blend[ i ] + a * v;
5178 }));
5179 },
5180 toRgbaString: function() {
5181 var prefix = "rgba(",
5182 rgba = jQuery.map( this._rgba, function( v, i ) {
5183 return v == null ? ( i > 2 ? 1 : 0 ) : v;
5184 });
5185
5186 if ( rgba[ 3 ] === 1 ) {
5187 rgba.pop();
5188 prefix = "rgb(";
5189 }
5190
5191 return prefix + rgba.join() + ")";
5192 },
5193 toHslaString: function() {
5194 var prefix = "hsla(",
5195 hsla = jQuery.map( this.hsla(), function( v, i ) {
5196 if ( v == null ) {
5197 v = i > 2 ? 1 : 0;
5198 }
5199
5200 // catch 1 and 2
5201 if ( i && i < 3 ) {
5202 v = Math.round( v * 100 ) + "%";
5203 }
5204 return v;
5205 });
5206
5207 if ( hsla[ 3 ] === 1 ) {
5208 hsla.pop();
5209 prefix = "hsl(";
5210 }
5211 return prefix + hsla.join() + ")";
5212 },
5213 toHexString: function( includeAlpha ) {
5214 var rgba = this._rgba.slice(),
5215 alpha = rgba.pop();
5216
5217 if ( includeAlpha ) {
5218 rgba.push( ~~( alpha * 255 ) );
5219 }
5220
5221 return "#" + jQuery.map( rgba, function( v ) {
5222
5223 // default to 0 when nulls exist
5224 v = ( v || 0 ).toString( 16 );
5225 return v.length === 1 ? "0" + v : v;
5226 }).join("");
5227 },
5228 toString: function() {
5229 return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
5230 }
5231 });
5232 color.fn.parse.prototype = color.fn;
5233
5234 // hsla conversions adapted from:
5235 // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
5236
5237 function hue2rgb( p, q, h ) {
5238 h = ( h + 1 ) % 1;
5239 if ( h * 6 < 1 ) {
5240 return p + (q - p) * h * 6;
5241 }
5242 if ( h * 2 < 1) {
5243 return q;
5244 }
5245 if ( h * 3 < 2 ) {
5246 return p + (q - p) * ((2/3) - h) * 6;
5247 }
5248 return p;
5249 }
5250
5251 spaces.hsla.to = function ( rgba ) {
5252 if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
5253 return [ null, null, null, rgba[ 3 ] ];
5254 }
5255 var r = rgba[ 0 ] / 255,
5256 g = rgba[ 1 ] / 255,
5257 b = rgba[ 2 ] / 255,
5258 a = rgba[ 3 ],
5259 max = Math.max( r, g, b ),
5260 min = Math.min( r, g, b ),
5261 diff = max - min,
5262 add = max + min,
5263 l = add * 0.5,
5264 h, s;
5265
5266 if ( min === max ) {
5267 h = 0;
5268 } else if ( r === max ) {
5269 h = ( 60 * ( g - b ) / diff ) + 360;
5270 } else if ( g === max ) {
5271 h = ( 60 * ( b - r ) / diff ) + 120;
5272 } else {
5273 h = ( 60 * ( r - g ) / diff ) + 240;
5274 }
5275
5276 // chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
5277 // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
5278 if ( diff === 0 ) {
5279 s = 0;
5280 } else if ( l <= 0.5 ) {
5281 s = diff / add;
5282 } else {
5283 s = diff / ( 2 - add );
5284 }
5285 return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
5286 };
5287
5288 spaces.hsla.from = function ( hsla ) {
5289 if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
5290 return [ null, null, null, hsla[ 3 ] ];
5291 }
5292 var h = hsla[ 0 ] / 360,
5293 s = hsla[ 1 ],
5294 l = hsla[ 2 ],
5295 a = hsla[ 3 ],
5296 q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
5297 p = 2 * l - q;
5298
5299 return [
5300 Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
5301 Math.round( hue2rgb( p, q, h ) * 255 ),
5302 Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
5303 a
5304 ];
5305 };
5306
5307
5308 each( spaces, function( spaceName, space ) {
5309 var props = space.props,
5310 cache = space.cache,
5311 to = space.to,
5312 from = space.from;
5313
5314 // makes rgba() and hsla()
5315 color.fn[ spaceName ] = function( value ) {
5316
5317 // generate a cache for this space if it doesn't exist
5318 if ( to && !this[ cache ] ) {
5319 this[ cache ] = to( this._rgba );
5320 }
5321 if ( value === undefined ) {
5322 return this[ cache ].slice();
5323 }
5324
5325 var ret,
5326 type = jQuery.type( value ),
5327 arr = ( type === "array" || type === "object" ) ? value : arguments,
5328 local = this[ cache ].slice();
5329
5330 each( props, function( key, prop ) {
5331 var val = arr[ type === "object" ? key : prop.idx ];
5332 if ( val == null ) {
5333 val = local[ prop.idx ];
5334 }
5335 local[ prop.idx ] = clamp( val, prop );
5336 });
5337
5338 if ( from ) {
5339 ret = color( from( local ) );
5340 ret[ cache ] = local;
5341 return ret;
5342 } else {
5343 return color( local );
5344 }
5345 };
5346
5347 // makes red() green() blue() alpha() hue() saturation() lightness()
5348 each( props, function( key, prop ) {
5349 // alpha is included in more than one space
5350 if ( color.fn[ key ] ) {
5351 return;
5352 }
5353 color.fn[ key ] = function( value ) {
5354 var vtype = jQuery.type( value ),
5355 fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
5356 local = this[ fn ](),
5357 cur = local[ prop.idx ],
5358 match;
5359
5360 if ( vtype === "undefined" ) {
5361 return cur;
5362 }
5363
5364 if ( vtype === "function" ) {
5365 value = value.call( this, cur );
5366 vtype = jQuery.type( value );
5367 }
5368 if ( value == null && prop.empty ) {
5369 return this;
5370 }
5371 if ( vtype === "string" ) {
5372 match = rplusequals.exec( value );
5373 if ( match ) {
5374 value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
5375 }
5376 }
5377 local[ prop.idx ] = value;
5378 return this[ fn ]( local );
5379 };
5380 });
5381 });
5382
5383 // add cssHook and .fx.step function for each named hook.
5384 // accept a space separated string of properties
5385 color.hook = function( hook ) {
5386 var hooks = hook.split( " " );
5387 each( hooks, function( i, hook ) {
5388 jQuery.cssHooks[ hook ] = {
5389 set: function( elem, value ) {
5390 var parsed, curElem,
5391 backgroundColor = "";
5392
5393 if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
5394 value = color( parsed || value );
5395 if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
5396 curElem = hook === "backgroundColor" ? elem.parentNode : elem;
5397 while (
5398 (backgroundColor === "" || backgroundColor === "transparent") &&
5399 curElem && curElem.style
5400 ) {
5401 try {
5402 backgroundColor = jQuery.css( curElem, "backgroundColor" );
5403 curElem = curElem.parentNode;
5404 } catch ( e ) {
5405 }
5406 }
5407
5408 value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
5409 backgroundColor :
5410 "_default" );
5411 }
5412
5413 value = value.toRgbaString();
5414 }
5415 try {
5416 elem.style[ hook ] = value;
5417 } catch( e ) {
5418 // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
5419 }
5420 }
5421 };
5422 jQuery.fx.step[ hook ] = function( fx ) {
5423 if ( !fx.colorInit ) {
5424 fx.start = color( fx.elem, hook );
5425 fx.end = color( fx.end );
5426 fx.colorInit = true;
5427 }
5428 jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
5429 };
5430 });
5431
5432 };
5433
5434 color.hook( stepHooks );
5435
5436 jQuery.cssHooks.borderColor = {
5437 expand: function( value ) {
5438 var expanded = {};
5439
5440 each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
5441 expanded[ "border" + part + "Color" ] = value;
5442 });
5443 return expanded;
5444 }
5445 };
5446
5447 // Basic color names only.
5448 // Usage of any of the other color names requires adding yourself or including
5449 // jquery.color.svg-names.js.
5450 colors = jQuery.Color.names = {
5451 // 4.1. Basic color keywords
5452 aqua: "#00ffff",
5453 black: "#000000",
5454 blue: "#0000ff",
5455 fuchsia: "#ff00ff",
5456 gray: "#808080",
5457 green: "#008000",
5458 lime: "#00ff00",
5459 maroon: "#800000",
5460 navy: "#000080",
5461 olive: "#808000",
5462 purple: "#800080",
5463 red: "#ff0000",
5464 silver: "#c0c0c0",
5465 teal: "#008080",
5466 white: "#ffffff",
5467 yellow: "#ffff00",
5468
5469 // 4.2.3. "transparent" color keyword
5470 transparent: [ null, null, null, 0 ],
5471
5472 _default: "#ffffff"
5473 };
5474
5475 })( jQuery );
5476
5477
5478 /******************************************************************************/
5479 /****************************** CLASS ANIMATIONS ******************************/
5480 /******************************************************************************/
5481 (function() {
5482
5483 var classAnimationActions = [ "add", "remove", "toggle" ],
5484 shorthandStyles = {
5485 border: 1,
5486 borderBottom: 1,
5487 borderColor: 1,
5488 borderLeft: 1,
5489 borderRight: 1,
5490 borderTop: 1,
5491 borderWidth: 1,
5492 margin: 1,
5493 padding: 1
5494 };
5495
5496 $.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) {
5497 $.fx.step[ prop ] = function( fx ) {
5498 if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
5499 jQuery.style( fx.elem, prop, fx.end );
5500 fx.setAttr = true;
5501 }
5502 };
5503 });
5504
5505 function getElementStyles( elem ) {
5506 var key, len,
5507 style = elem.ownerDocument.defaultView ?
5508 elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
5509 elem.currentStyle,
5510 styles = {};
5511
5512 if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
5513 len = style.length;
5514 while ( len-- ) {
5515 key = style[ len ];
5516 if ( typeof style[ key ] === "string" ) {
5517 styles[ $.camelCase( key ) ] = style[ key ];
5518 }
5519 }
5520 // support: Opera, IE <9
5521 } else {
5522 for ( key in style ) {
5523 if ( typeof style[ key ] === "string" ) {
5524 styles[ key ] = style[ key ];
5525 }
5526 }
5527 }
5528
5529 return styles;
5530 }
5531
5532
5533 function styleDifference( oldStyle, newStyle ) {
5534 var diff = {},
5535 name, value;
5536
5537 for ( name in newStyle ) {
5538 value = newStyle[ name ];
5539 if ( oldStyle[ name ] !== value ) {
5540 if ( !shorthandStyles[ name ] ) {
5541 if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
5542 diff[ name ] = value;
5543 }
5544 }
5545 }
5546 }
5547
5548 return diff;
5549 }
5550
5551 // support: jQuery <1.8
5552 if ( !$.fn.addBack ) {
5553 $.fn.addBack = function( selector ) {
5554 return this.add( selector == null ?
5555 this.prevObject : this.prevObject.filter( selector )
5556 );
5557 };
5558 }
5559
5560 $.effects.animateClass = function( value, duration, easing, callback ) {
5561 var o = $.speed( duration, easing, callback );
5562
5563 return this.queue( function() {
5564 var animated = $( this ),
5565 baseClass = animated.attr( "class" ) || "",
5566 applyClassChange,
5567 allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
5568
5569 // map the animated objects to store the original styles.
5570 allAnimations = allAnimations.map(function() {
5571 var el = $( this );
5572 return {
5573 el: el,
5574 start: getElementStyles( this )
5575 };
5576 });
5577
5578 // apply class change
5579 applyClassChange = function() {
5580 $.each( classAnimationActions, function(i, action) {
5581 if ( value[ action ] ) {
5582 animated[ action + "Class" ]( value[ action ] );
5583 }
5584 });
5585 };
5586 applyClassChange();
5587
5588 // map all animated objects again - calculate new styles and diff
5589 allAnimations = allAnimations.map(function() {
5590 this.end = getElementStyles( this.el[ 0 ] );
5591 this.diff = styleDifference( this.start, this.end );
5592 return this;
5593 });
5594
5595 // apply original class
5596 animated.attr( "class", baseClass );
5597
5598 // map all animated objects again - this time collecting a promise
5599 allAnimations = allAnimations.map(function() {
5600 var styleInfo = this,
5601 dfd = $.Deferred(),
5602 opts = $.extend({}, o, {
5603 queue: false,
5604 complete: function() {
5605 dfd.resolve( styleInfo );
5606 }
5607 });
5608
5609 this.el.animate( this.diff, opts );
5610 return dfd.promise();
5611 });
5612
5613 // once all animations have completed:
5614 $.when.apply( $, allAnimations.get() ).done(function() {
5615
5616 // set the final class
5617 applyClassChange();
5618
5619 // for each animated element,
5620 // clear all css properties that were animated
5621 $.each( arguments, function() {
5622 var el = this.el;
5623 $.each( this.diff, function(key) {
5624 el.css( key, "" );
5625 });
5626 });
5627
5628 // this is guarnteed to be there if you use jQuery.speed()
5629 // it also handles dequeuing the next anim...
5630 o.complete.call( animated[ 0 ] );
5631 });
5632 });
5633 };
5634
5635 $.fn.extend({
5636 addClass: (function( orig ) {
5637 return function( classNames, speed, easing, callback ) {
5638 return speed ?
5639 $.effects.animateClass.call( this,
5640 { add: classNames }, speed, easing, callback ) :
5641 orig.apply( this, arguments );
5642 };
5643 })( $.fn.addClass ),
5644
5645 removeClass: (function( orig ) {
5646 return function( classNames, speed, easing, callback ) {
5647 return arguments.length > 1 ?
5648 $.effects.animateClass.call( this,
5649 { remove: classNames }, speed, easing, callback ) :
5650 orig.apply( this, arguments );
5651 };
5652 })( $.fn.removeClass ),
5653
5654 toggleClass: (function( orig ) {
5655 return function( classNames, force, speed, easing, callback ) {
5656 if ( typeof force === "boolean" || force === undefined ) {
5657 if ( !speed ) {
5658 // without speed parameter
5659 return orig.apply( this, arguments );
5660 } else {
5661 return $.effects.animateClass.call( this,
5662 (force ? { add: classNames } : { remove: classNames }),
5663 speed, easing, callback );
5664 }
5665 } else {
5666 // without force parameter
5667 return $.effects.animateClass.call( this,
5668 { toggle: classNames }, force, speed, easing );
5669 }
5670 };
5671 })( $.fn.toggleClass ),
5672
5673 switchClass: function( remove, add, speed, easing, callback) {
5674 return $.effects.animateClass.call( this, {
5675 add: add,
5676 remove: remove
5677 }, speed, easing, callback );
5678 }
5679 });
5680
5681 })();
5682
5683 /******************************************************************************/
5684 /*********************************** EFFECTS **********************************/
5685 /******************************************************************************/
5686
5687 (function() {
5688
5689 $.extend( $.effects, {
5690 version: "1.10.4",
5691
5692 // Saves a set of properties in a data storage
5693 save: function( element, set ) {
5694 for( var i=0; i < set.length; i++ ) {
5695 if ( set[ i ] !== null ) {
5696 element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
5697 }
5698 }
5699 },
5700
5701 // Restores a set of previously saved properties from a data storage
5702 restore: function( element, set ) {
5703 var val, i;
5704 for( i=0; i < set.length; i++ ) {
5705 if ( set[ i ] !== null ) {
5706 val = element.data( dataSpace + set[ i ] );
5707 // support: jQuery 1.6.2
5708 // http://bugs.jquery.com/ticket/9917
5709 // jQuery 1.6.2 incorrectly returns undefined for any falsy value.
5710 // We can't differentiate between "" and 0 here, so we just assume
5711 // empty string since it's likely to be a more common value...
5712 if ( val === undefined ) {
5713 val = "";
5714 }
5715 element.css( set[ i ], val );
5716 }
5717 }
5718 },
5719
5720 setMode: function( el, mode ) {
5721 if (mode === "toggle") {
5722 mode = el.is( ":hidden" ) ? "show" : "hide";
5723 }
5724 return mode;
5725 },
5726
5727 // Translates a [top,left] array into a baseline value
5728 // this should be a little more flexible in the future to handle a string & hash
5729 getBaseline: function( origin, original ) {
5730 var y, x;
5731 switch ( origin[ 0 ] ) {
5732 case "top": y = 0; break;
5733 case "middle": y = 0.5; break;
5734 case "bottom": y = 1; break;
5735 default: y = origin[ 0 ] / original.height;
5736 }
5737 switch ( origin[ 1 ] ) {
5738 case "left": x = 0; break;
5739 case "center": x = 0.5; break;
5740 case "right": x = 1; break;
5741 default: x = origin[ 1 ] / original.width;
5742 }
5743 return {
5744 x: x,
5745 y: y
5746 };
5747 },
5748
5749 // Wraps the element around a wrapper that copies position properties
5750 createWrapper: function( element ) {
5751
5752 // if the element is already wrapped, return it
5753 if ( element.parent().is( ".ui-effects-wrapper" )) {
5754 return element.parent();
5755 }
5756
5757 // wrap the element
5758 var props = {
5759 width: element.outerWidth(true),
5760 height: element.outerHeight(true),
5761 "float": element.css( "float" )
5762 },
5763 wrapper = $( "<div></div>" )
5764 .addClass( "ui-effects-wrapper" )
5765 .css({
5766 fontSize: "100%",
5767 background: "transparent",
5768 border: "none",
5769 margin: 0,
5770 padding: 0
5771 }),
5772 // Store the size in case width/height are defined in % - Fixes #5245
5773 size = {
5774 width: element.width(),
5775 height: element.height()
5776 },
5777 active = document.activeElement;
5778
5779 // support: Firefox
5780 // Firefox incorrectly exposes anonymous content
5781 // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
5782 try {
5783 active.id;
5784 } catch( e ) {
5785 active = document.body;
5786 }
5787
5788 element.wrap( wrapper );
5789
5790 // Fixes #7595 - Elements lose focus when wrapped.
5791 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
5792 $( active ).focus();
5793 }
5794
5795 wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element
5796
5797 // transfer positioning properties to the wrapper
5798 if ( element.css( "position" ) === "static" ) {
5799 wrapper.css({ position: "relative" });
5800 element.css({ position: "relative" });
5801 } else {
5802 $.extend( props, {
5803 position: element.css( "position" ),
5804 zIndex: element.css( "z-index" )
5805 });
5806 $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
5807 props[ pos ] = element.css( pos );
5808 if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
5809 props[ pos ] = "auto";
5810 }
5811 });
5812 element.css({
5813 position: "relative",
5814 top: 0,
5815 left: 0,
5816 right: "auto",
5817 bottom: "auto"
5818 });
5819 }
5820 element.css(size);
5821
5822 return wrapper.css( props ).show();
5823 },
5824
5825 removeWrapper: function( element ) {
5826 var active = document.activeElement;
5827
5828 if ( element.parent().is( ".ui-effects-wrapper" ) ) {
5829 element.parent().replaceWith( element );
5830
5831 // Fixes #7595 - Elements lose focus when wrapped.
5832 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
5833 $( active ).focus();
5834 }
5835 }
5836
5837
5838 return element;
5839 },
5840
5841 setTransition: function( element, list, factor, value ) {
5842 value = value || {};
5843 $.each( list, function( i, x ) {
5844 var unit = element.cssUnit( x );
5845 if ( unit[ 0 ] > 0 ) {
5846 value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
5847 }
5848 });
5849 return value;
5850 }
5851 });
5852
5853 // return an effect options object for the given parameters:
5854 function _normalizeArguments( effect, options, speed, callback ) {
5855
5856 // allow passing all options as the first parameter
5857 if ( $.isPlainObject( effect ) ) {
5858 options = effect;
5859 effect = effect.effect;
5860 }
5861
5862 // convert to an object
5863 effect = { effect: effect };
5864
5865 // catch (effect, null, ...)
5866 if ( options == null ) {
5867 options = {};
5868 }
5869
5870 // catch (effect, callback)
5871 if ( $.isFunction( options ) ) {
5872 callback = options;
5873 speed = null;
5874 options = {};
5875 }
5876
5877 // catch (effect, speed, ?)
5878 if ( typeof options === "number" || $.fx.speeds[ options ] ) {
5879 callback = speed;
5880 speed = options;
5881 options = {};
5882 }
5883
5884 // catch (effect, options, callback)
5885 if ( $.isFunction( speed ) ) {
5886 callback = speed;
5887 speed = null;
5888 }
5889
5890 // add options to effect
5891 if ( options ) {
5892 $.extend( effect, options );
5893 }
5894
5895 speed = speed || options.duration;
5896 effect.duration = $.fx.off ? 0 :
5897 typeof speed === "number" ? speed :
5898 speed in $.fx.speeds ? $.fx.speeds[ speed ] :
5899 $.fx.speeds._default;
5900
5901 effect.complete = callback || options.complete;
5902
5903 return effect;
5904 }
5905
5906 function standardAnimationOption( option ) {
5907 // Valid standard speeds (nothing, number, named speed)
5908 if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
5909 return true;
5910 }
5911
5912 // Invalid strings - treat as "normal" speed
5913 if ( typeof option === "string" && !$.effects.effect[ option ] ) {
5914 return true;
5915 }
5916
5917 // Complete callback
5918 if ( $.isFunction( option ) ) {
5919 return true;
5920 }
5921
5922 // Options hash (but not naming an effect)
5923 if ( typeof option === "object" && !option.effect ) {
5924 return true;
5925 }
5926
5927 // Didn't match any standard API
5928 return false;
5929 }
5930
5931 $.fn.extend({
5932 effect: function( /* effect, options, speed, callback */ ) {
5933 var args = _normalizeArguments.apply( this, arguments ),
5934 mode = args.mode,
5935 queue = args.queue,
5936 effectMethod = $.effects.effect[ args.effect ];
5937
5938 if ( $.fx.off || !effectMethod ) {
5939 // delegate to the original method (e.g., .show()) if possible
5940 if ( mode ) {
5941 return this[ mode ]( args.duration, args.complete );
5942 } else {
5943 return this.each( function() {
5944 if ( args.complete ) {
5945 args.complete.call( this );
5946 }
5947 });
5948 }
5949 }
5950
5951 function run( next ) {
5952 var elem = $( this ),
5953 complete = args.complete,
5954 mode = args.mode;
5955
5956 function done() {
5957 if ( $.isFunction( complete ) ) {
5958 complete.call( elem[0] );
5959 }
5960 if ( $.isFunction( next ) ) {
5961 next();
5962 }
5963 }
5964
5965 // If the element already has the correct final state, delegate to
5966 // the core methods so the internal tracking of "olddisplay" works.
5967 if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
5968 elem[ mode ]();
5969 done();
5970 } else {
5971 effectMethod.call( elem[0], args, done );
5972 }
5973 }
5974
5975 return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
5976 },
5977
5978 show: (function( orig ) {
5979 return function( option ) {
5980 if ( standardAnimationOption( option ) ) {
5981 return orig.apply( this, arguments );
5982 } else {
5983 var args = _normalizeArguments.apply( this, arguments );
5984 args.mode = "show";
5985 return this.effect.call( this, args );
5986 }
5987 };
5988 })( $.fn.show ),
5989
5990 hide: (function( orig ) {
5991 return function( option ) {
5992 if ( standardAnimationOption( option ) ) {
5993 return orig.apply( this, arguments );
5994 } else {
5995 var args = _normalizeArguments.apply( this, arguments );
5996 args.mode = "hide";
5997 return this.effect.call( this, args );
5998 }
5999 };
6000 })( $.fn.hide ),
6001
6002 toggle: (function( orig ) {
6003 return function( option ) {
6004 if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
6005 return orig.apply( this, arguments );
6006 } else {
6007 var args = _normalizeArguments.apply( this, arguments );
6008 args.mode = "toggle";
6009 return this.effect.call( this, args );
6010 }
6011 };
6012 })( $.fn.toggle ),
6013
6014 // helper functions
6015 cssUnit: function(key) {
6016 var style = this.css( key ),
6017 val = [];
6018
6019 $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
6020 if ( style.indexOf( unit ) > 0 ) {
6021 val = [ parseFloat( style ), unit ];
6022 }
6023 });
6024 return val;
6025 }
6026 });
6027
6028 })();
6029
6030 /******************************************************************************/
6031 /*********************************** EASING ***********************************/
6032 /******************************************************************************/
6033
6034 (function() {
6035
6036 // based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
6037
6038 var baseEasings = {};
6039
6040 $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
6041 baseEasings[ name ] = function( p ) {
6042 return Math.pow( p, i + 2 );
6043 };
6044 });
6045
6046 $.extend( baseEasings, {
6047 Sine: function ( p ) {
6048 return 1 - Math.cos( p * Math.PI / 2 );
6049 },
6050 Circ: function ( p ) {
6051 return 1 - Math.sqrt( 1 - p * p );
6052 },
6053 Elastic: function( p ) {
6054 return p === 0 || p === 1 ? p :
6055 -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 );
6056 },
6057 Back: function( p ) {
6058 return p * p * ( 3 * p - 2 );
6059 },
6060 Bounce: function ( p ) {
6061 var pow2,
6062 bounce = 4;
6063
6064 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
6065 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
6066 }
6067 });
6068
6069 $.each( baseEasings, function( name, easeIn ) {
6070 $.easing[ "easeIn" + name ] = easeIn;
6071 $.easing[ "easeOut" + name ] = function( p ) {
6072 return 1 - easeIn( 1 - p );
6073 };
6074 $.easing[ "easeInOut" + name ] = function( p ) {
6075 return p < 0.5 ?
6076 easeIn( p * 2 ) / 2 :
6077 1 - easeIn( p * -2 + 2 ) / 2;
6078 };
6079 });
6080
6081 })();
6082
6083 })(jQuery);
6084
6085 (function( $, undefined ) {
6086
6087 var uid = 0,
6088 hideProps = {},
6089 showProps = {};
6090
6091 hideProps.height = hideProps.paddingTop = hideProps.paddingBottom =
6092 hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide";
6093 showProps.height = showProps.paddingTop = showProps.paddingBottom =
6094 showProps.borderTopWidth = showProps.borderBottomWidth = "show";
6095
6096 $.widget( "ui.accordion", {
6097 version: "1.10.4",
6098 options: {
6099 active: 0,
6100 animate: {},
6101 collapsible: false,
6102 event: "click",
6103 header: "> li > :first-child,> :not(li):even",
6104 heightStyle: "auto",
6105 icons: {
6106 activeHeader: "ui-icon-triangle-1-s",
6107 header: "ui-icon-triangle-1-e"
6108 },
6109
6110 // callbacks
6111 activate: null,
6112 beforeActivate: null
6113 },
6114
6115 _create: function() {
6116 var options = this.options;
6117 this.prevShow = this.prevHide = $();
6118 this.element.addClass( "ui-accordion ui-widget ui-helper-reset" )
6119 // ARIA
6120 .attr( "role", "tablist" );
6121
6122 // don't allow collapsible: false and active: false / null
6123 if ( !options.collapsible && (options.active === false || options.active == null) ) {
6124 options.active = 0;
6125 }
6126
6127 this._processPanels();
6128 // handle negative values
6129 if ( options.active < 0 ) {
6130 options.active += this.headers.length;
6131 }
6132 this._refresh();
6133 },
6134
6135 _getCreateEventData: function() {
6136 return {
6137 header: this.active,
6138 panel: !this.active.length ? $() : this.active.next(),
6139 content: !this.active.length ? $() : this.active.next()
6140 };
6141 },
6142
6143 _createIcons: function() {
6144 var icons = this.options.icons;
6145 if ( icons ) {
6146 $( "<span>" )
6147 .addClass( "ui-accordion-header-icon ui-icon " + icons.header )
6148 .prependTo( this.headers );
6149 this.active.children( ".ui-accordion-header-icon" )
6150 .removeClass( icons.header )
6151 .addClass( icons.activeHeader );
6152 this.headers.addClass( "ui-accordion-icons" );
6153 }
6154 },
6155
6156 _destroyIcons: function() {
6157 this.headers
6158 .removeClass( "ui-accordion-icons" )
6159 .children( ".ui-accordion-header-icon" )
6160 .remove();
6161 },
6162
6163 _destroy: function() {
6164 var contents;
6165
6166 // clean up main element
6167 this.element
6168 .removeClass( "ui-accordion ui-widget ui-helper-reset" )
6169 .removeAttr( "role" );
6170
6171 // clean up headers
6172 this.headers
6173 .removeClass( "ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" )
6174 .removeAttr( "role" )
6175 .removeAttr( "aria-expanded" )
6176 .removeAttr( "aria-selected" )
6177 .removeAttr( "aria-controls" )
6178 .removeAttr( "tabIndex" )
6179 .each(function() {
6180 if ( /^ui-accordion/.test( this.id ) ) {
6181 this.removeAttribute( "id" );
6182 }
6183 });
6184 this._destroyIcons();
6185
6186 // clean up content panels
6187 contents = this.headers.next()
6188 .css( "display", "" )
6189 .removeAttr( "role" )
6190 .removeAttr( "aria-hidden" )
6191 .removeAttr( "aria-labelledby" )
6192 .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" )
6193 .each(function() {
6194 if ( /^ui-accordion/.test( this.id ) ) {
6195 this.removeAttribute( "id" );
6196 }
6197 });
6198 if ( this.options.heightStyle !== "content" ) {
6199 contents.css( "height", "" );
6200 }
6201 },
6202
6203 _setOption: function( key, value ) {
6204 if ( key === "active" ) {
6205 // _activate() will handle invalid values and update this.options
6206 this._activate( value );
6207 return;
6208 }
6209
6210 if ( key === "event" ) {
6211 if ( this.options.event ) {
6212 this._off( this.headers, this.options.event );
6213 }
6214 this._setupEvents( value );
6215 }
6216
6217 this._super( key, value );
6218
6219 // setting collapsible: false while collapsed; open first panel
6220 if ( key === "collapsible" && !value && this.options.active === false ) {
6221 this._activate( 0 );
6222 }
6223
6224 if ( key === "icons" ) {
6225 this._destroyIcons();
6226 if ( value ) {
6227 this._createIcons();
6228 }
6229 }
6230
6231 // #5332 - opacity doesn't cascade to positioned elements in IE
6232 // so we need to add the disabled class to the headers and panels
6233 if ( key === "disabled" ) {
6234 this.headers.add( this.headers.next() )
6235 .toggleClass( "ui-state-disabled", !!value );
6236 }
6237 },
6238
6239 _keydown: function( event ) {
6240 if ( event.altKey || event.ctrlKey ) {
6241 return;
6242 }
6243
6244 var keyCode = $.ui.keyCode,
6245 length = this.headers.length,
6246 currentIndex = this.headers.index( event.target ),
6247 toFocus = false;
6248
6249 switch ( event.keyCode ) {
6250 case keyCode.RIGHT:
6251 case keyCode.DOWN:
6252 toFocus = this.headers[ ( currentIndex + 1 ) % length ];
6253 break;
6254 case keyCode.LEFT:
6255 case keyCode.UP:
6256 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
6257 break;
6258 case keyCode.SPACE:
6259 case keyCode.ENTER:
6260 this._eventHandler( event );
6261 break;
6262 case keyCode.HOME:
6263 toFocus = this.headers[ 0 ];
6264 break;
6265 case keyCode.END:
6266 toFocus = this.headers[ length - 1 ];
6267 break;
6268 }
6269
6270 if ( toFocus ) {
6271 $( event.target ).attr( "tabIndex", -1 );
6272 $( toFocus ).attr( "tabIndex", 0 );
6273 toFocus.focus();
6274 event.preventDefault();
6275 }
6276 },
6277
6278 _panelKeyDown : function( event ) {
6279 if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
6280 $( event.currentTarget ).prev().focus();
6281 }
6282 },
6283
6284 refresh: function() {
6285 var options = this.options;
6286 this._processPanels();
6287
6288 // was collapsed or no panel
6289 if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) {
6290 options.active = false;
6291 this.active = $();
6292 // active false only when collapsible is true
6293 } else if ( options.active === false ) {
6294 this._activate( 0 );
6295 // was active, but active panel is gone
6296 } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
6297 // all remaining panel are disabled
6298 if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) {
6299 options.active = false;
6300 this.active = $();
6301 // activate previous panel
6302 } else {
6303 this._activate( Math.max( 0, options.active - 1 ) );
6304 }
6305 // was active, active panel still exists
6306 } else {
6307 // make sure active index is correct
6308 options.active = this.headers.index( this.active );
6309 }
6310
6311 this._destroyIcons();
6312
6313 this._refresh();
6314 },
6315
6316 _processPanels: function() {
6317 this.headers = this.element.find( this.options.header )
6318 .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" );
6319
6320 this.headers.next()
6321 .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
6322 .filter(":not(.ui-accordion-content-active)")
6323 .hide();
6324 },
6325
6326 _refresh: function() {
6327 var maxHeight,
6328 options = this.options,
6329 heightStyle = options.heightStyle,
6330 parent = this.element.parent(),
6331 accordionId = this.accordionId = "ui-accordion-" +
6332 (this.element.attr( "id" ) || ++uid);
6333
6334 this.active = this._findActive( options.active )
6335 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" )
6336 .removeClass( "ui-corner-all" );
6337 this.active.next()
6338 .addClass( "ui-accordion-content-active" )
6339 .show();
6340
6341 this.headers
6342 .attr( "role", "tab" )
6343 .each(function( i ) {
6344 var header = $( this ),
6345 headerId = header.attr( "id" ),
6346 panel = header.next(),
6347 panelId = panel.attr( "id" );
6348 if ( !headerId ) {
6349 headerId = accordionId + "-header-" + i;
6350 header.attr( "id", headerId );
6351 }
6352 if ( !panelId ) {
6353 panelId = accordionId + "-panel-" + i;
6354 panel.attr( "id", panelId );
6355 }
6356 header.attr( "aria-controls", panelId );
6357 panel.attr( "aria-labelledby", headerId );
6358 })
6359 .next()
6360 .attr( "role", "tabpanel" );
6361
6362 this.headers
6363 .not( this.active )
6364 .attr({
6365 "aria-selected": "false",
6366 "aria-expanded": "false",
6367 tabIndex: -1
6368 })
6369 .next()
6370 .attr({
6371 "aria-hidden": "true"
6372 })
6373 .hide();
6374
6375 // make sure at least one header is in the tab order
6376 if ( !this.active.length ) {
6377 this.headers.eq( 0 ).attr( "tabIndex", 0 );
6378 } else {
6379 this.active.attr({
6380 "aria-selected": "true",
6381 "aria-expanded": "true",
6382 tabIndex: 0
6383 })
6384 .next()
6385 .attr({
6386 "aria-hidden": "false"
6387 });
6388 }
6389
6390 this._createIcons();
6391
6392 this._setupEvents( options.event );
6393
6394 if ( heightStyle === "fill" ) {
6395 maxHeight = parent.height();
6396 this.element.siblings( ":visible" ).each(function() {
6397 var elem = $( this ),
6398 position = elem.css( "position" );
6399
6400 if ( position === "absolute" || position === "fixed" ) {
6401 return;
6402 }
6403 maxHeight -= elem.outerHeight( true );
6404 });
6405
6406 this.headers.each(function() {
6407 maxHeight -= $( this ).outerHeight( true );
6408 });
6409
6410 this.headers.next()
6411 .each(function() {
6412 $( this ).height( Math.max( 0, maxHeight -
6413 $( this ).innerHeight() + $( this ).height() ) );
6414 })
6415 .css( "overflow", "auto" );
6416 } else if ( heightStyle === "auto" ) {
6417 maxHeight = 0;
6418 this.headers.next()
6419 .each(function() {
6420 maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
6421 })
6422 .height( maxHeight );
6423 }
6424 },
6425
6426 _activate: function( index ) {
6427 var active = this._findActive( index )[ 0 ];
6428
6429 // trying to activate the already active panel
6430 if ( active === this.active[ 0 ] ) {
6431 return;
6432 }
6433
6434 // trying to collapse, simulate a click on the currently active header
6435 active = active || this.active[ 0 ];
6436
6437 this._eventHandler({
6438 target: active,
6439 currentTarget: active,
6440 preventDefault: $.noop
6441 });
6442 },
6443
6444 _findActive: function( selector ) {
6445 return typeof selector === "number" ? this.headers.eq( selector ) : $();
6446 },
6447
6448 _setupEvents: function( event ) {
6449 var events = {
6450 keydown: "_keydown"
6451 };
6452 if ( event ) {
6453 $.each( event.split(" "), function( index, eventName ) {
6454 events[ eventName ] = "_eventHandler";
6455 });
6456 }
6457
6458 this._off( this.headers.add( this.headers.next() ) );
6459 this._on( this.headers, events );
6460 this._on( this.headers.next(), { keydown: "_panelKeyDown" });
6461 this._hoverable( this.headers );
6462 this._focusable( this.headers );
6463 },
6464
6465 _eventHandler: function( event ) {
6466 var options = this.options,
6467 active = this.active,
6468 clicked = $( event.currentTarget ),
6469 clickedIsActive = clicked[ 0 ] === active[ 0 ],
6470 collapsing = clickedIsActive && options.collapsible,
6471 toShow = collapsing ? $() : clicked.next(),
6472 toHide = active.next(),
6473 eventData = {
6474 oldHeader: active,
6475 oldPanel: toHide,
6476 newHeader: collapsing ? $() : clicked,
6477 newPanel: toShow
6478 };
6479
6480 event.preventDefault();
6481
6482 if (
6483 // click on active header, but not collapsible
6484 ( clickedIsActive && !options.collapsible ) ||
6485 // allow canceling activation
6486 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
6487 return;
6488 }
6489
6490 options.active = collapsing ? false : this.headers.index( clicked );
6491
6492 // when the call to ._toggle() comes after the class changes
6493 // it causes a very odd bug in IE 8 (see #6720)
6494 this.active = clickedIsActive ? $() : clicked;
6495 this._toggle( eventData );
6496
6497 // switch classes
6498 // corner classes on the previously active header stay after the animation
6499 active.removeClass( "ui-accordion-header-active ui-state-active" );
6500 if ( options.icons ) {
6501 active.children( ".ui-accordion-header-icon" )
6502 .removeClass( options.icons.activeHeader )
6503 .addClass( options.icons.header );
6504 }
6505
6506 if ( !clickedIsActive ) {
6507 clicked
6508 .removeClass( "ui-corner-all" )
6509 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" );
6510 if ( options.icons ) {
6511 clicked.children( ".ui-accordion-header-icon" )
6512 .removeClass( options.icons.header )
6513 .addClass( options.icons.activeHeader );
6514 }
6515
6516 clicked
6517 .next()
6518 .addClass( "ui-accordion-content-active" );
6519 }
6520 },
6521
6522 _toggle: function( data ) {
6523 var toShow = data.newPanel,
6524 toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
6525
6526 // handle activating a panel during the animation for another activation
6527 this.prevShow.add( this.prevHide ).stop( true, true );
6528 this.prevShow = toShow;
6529 this.prevHide = toHide;
6530
6531 if ( this.options.animate ) {
6532 this._animate( toShow, toHide, data );
6533 } else {
6534 toHide.hide();
6535 toShow.show();
6536 this._toggleComplete( data );
6537 }
6538
6539 toHide.attr({
6540 "aria-hidden": "true"
6541 });
6542 toHide.prev().attr( "aria-selected", "false" );
6543 // if we're switching panels, remove the old header from the tab order
6544 // if we're opening from collapsed state, remove the previous header from the tab order
6545 // if we're collapsing, then keep the collapsing header in the tab order
6546 if ( toShow.length && toHide.length ) {
6547 toHide.prev().attr({
6548 "tabIndex": -1,
6549 "aria-expanded": "false"
6550 });
6551 } else if ( toShow.length ) {
6552 this.headers.filter(function() {
6553 return $( this ).attr( "tabIndex" ) === 0;
6554 })
6555 .attr( "tabIndex", -1 );
6556 }
6557
6558 toShow
6559 .attr( "aria-hidden", "false" )
6560 .prev()
6561 .attr({
6562 "aria-selected": "true",
6563 tabIndex: 0,
6564 "aria-expanded": "true"
6565 });
6566 },
6567
6568 _animate: function( toShow, toHide, data ) {
6569 var total, easing, duration,
6570 that = this,
6571 adjust = 0,
6572 down = toShow.length &&
6573 ( !toHide.length || ( toShow.index() < toHide.index() ) ),
6574 animate = this.options.animate || {},
6575 options = down && animate.down || animate,
6576 complete = function() {
6577 that._toggleComplete( data );
6578 };
6579
6580 if ( typeof options === "number" ) {
6581 duration = options;
6582 }
6583 if ( typeof options === "string" ) {
6584 easing = options;
6585 }
6586 // fall back from options to animation in case of partial down settings
6587 easing = easing || options.easing || animate.easing;
6588 duration = duration || options.duration || animate.duration;
6589
6590 if ( !toHide.length ) {
6591 return toShow.animate( showProps, duration, easing, complete );
6592 }
6593 if ( !toShow.length ) {
6594 return toHide.animate( hideProps, duration, easing, complete );
6595 }
6596
6597 total = toShow.show().outerHeight();
6598 toHide.animate( hideProps, {
6599 duration: duration,
6600 easing: easing,
6601 step: function( now, fx ) {
6602 fx.now = Math.round( now );
6603 }
6604 });
6605 toShow
6606 .hide()
6607 .animate( showProps, {
6608 duration: duration,
6609 easing: easing,
6610 complete: complete,
6611 step: function( now, fx ) {
6612 fx.now = Math.round( now );
6613 if ( fx.prop !== "height" ) {
6614 adjust += fx.now;
6615 } else if ( that.options.heightStyle !== "content" ) {
6616 fx.now = Math.round( total - toHide.outerHeight() - adjust );
6617 adjust = 0;
6618 }
6619 }
6620 });
6621 },
6622
6623 _toggleComplete: function( data ) {
6624 var toHide = data.oldPanel;
6625
6626 toHide
6627 .removeClass( "ui-accordion-content-active" )
6628 .prev()
6629 .removeClass( "ui-corner-top" )
6630 .addClass( "ui-corner-all" );
6631
6632 // Work around for rendering bug in IE (#5421)
6633 if ( toHide.length ) {
6634 toHide.parent()[0].className = toHide.parent()[0].className;
6635 }
6636 this._trigger( "activate", null, data );
6637 }
6638 });
6639
6640 })( jQuery );
6641
6642 (function( $, undefined ) {
6643
6644 $.widget( "ui.autocomplete", {
6645 version: "1.10.4",
6646 defaultElement: "<input>",
6647 options: {
6648 appendTo: null,
6649 autoFocus: false,
6650 delay: 300,
6651 minLength: 1,
6652 position: {
6653 my: "left top",
6654 at: "left bottom",
6655 collision: "none"
6656 },
6657 source: null,
6658
6659 // callbacks
6660 change: null,
6661 close: null,
6662 focus: null,
6663 open: null,
6664 response: null,
6665 search: null,
6666 select: null
6667 },
6668
6669 requestIndex: 0,
6670 pending: 0,
6671
6672 _create: function() {
6673 // Some browsers only repeat keydown events, not keypress events,
6674 // so we use the suppressKeyPress flag to determine if we've already
6675 // handled the keydown event. #7269
6676 // Unfortunately the code for & in keypress is the same as the up arrow,
6677 // so we use the suppressKeyPressRepeat flag to avoid handling keypress
6678 // events when we know the keydown event was used to modify the
6679 // search term. #7799
6680 var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
6681 nodeName = this.element[0].nodeName.toLowerCase(),
6682 isTextarea = nodeName === "textarea",
6683 isInput = nodeName === "input";
6684
6685 this.isMultiLine =
6686 // Textareas are always multi-line
6687 isTextarea ? true :
6688 // Inputs are always single-line, even if inside a contentEditable element
6689 // IE also treats inputs as contentEditable
6690 isInput ? false :
6691 // All other element types are determined by whether or not they're contentEditable
6692 this.element.prop( "isContentEditable" );
6693
6694 this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
6695 this.isNewMenu = true;
6696
6697 this.element
6698 .addClass( "ui-autocomplete-input" )
6699 .attr( "autocomplete", "off" );
6700
6701 this._on( this.element, {
6702 keydown: function( event ) {
6703 if ( this.element.prop( "readOnly" ) ) {
6704 suppressKeyPress = true;
6705 suppressInput = true;
6706 suppressKeyPressRepeat = true;
6707 return;
6708 }
6709
6710 suppressKeyPress = false;
6711 suppressInput = false;
6712 suppressKeyPressRepeat = false;
6713 var keyCode = $.ui.keyCode;
6714 switch( event.keyCode ) {
6715 case keyCode.PAGE_UP:
6716 suppressKeyPress = true;
6717 this._move( "previousPage", event );
6718 break;
6719 case keyCode.PAGE_DOWN:
6720 suppressKeyPress = true;
6721 this._move( "nextPage", event );
6722 break;
6723 case keyCode.UP:
6724 suppressKeyPress = true;
6725 this._keyEvent( "previous", event );
6726 break;
6727 case keyCode.DOWN:
6728 suppressKeyPress = true;
6729 this._keyEvent( "next", event );
6730 break;
6731 case keyCode.ENTER:
6732 case keyCode.NUMPAD_ENTER:
6733 // when menu is open and has focus
6734 if ( this.menu.active ) {
6735 // #6055 - Opera still allows the keypress to occur
6736 // which causes forms to submit
6737 suppressKeyPress = true;
6738 event.preventDefault();
6739 this.menu.select( event );
6740 }
6741 break;
6742 case keyCode.TAB:
6743 if ( this.menu.active ) {
6744 this.menu.select( event );
6745 }
6746 break;
6747 case keyCode.ESCAPE:
6748 if ( this.menu.element.is( ":visible" ) ) {
6749 this._value( this.term );
6750 this.close( event );
6751 // Different browsers have different default behavior for escape
6752 // Single press can mean undo or clear
6753 // Double press in IE means clear the whole form
6754 event.preventDefault();
6755 }
6756 break;
6757 default:
6758 suppressKeyPressRepeat = true;
6759 // search timeout should be triggered before the input value is changed
6760 this._searchTimeout( event );
6761 break;
6762 }
6763 },
6764 keypress: function( event ) {
6765 if ( suppressKeyPress ) {
6766 suppressKeyPress = false;
6767 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
6768 event.preventDefault();
6769 }
6770 return;
6771 }
6772 if ( suppressKeyPressRepeat ) {
6773 return;
6774 }
6775
6776 // replicate some key handlers to allow them to repeat in Firefox and Opera
6777 var keyCode = $.ui.keyCode;
6778 switch( event.keyCode ) {
6779 case keyCode.PAGE_UP:
6780 this._move( "previousPage", event );
6781 break;
6782 case keyCode.PAGE_DOWN:
6783 this._move( "nextPage", event );
6784 break;
6785 case keyCode.UP:
6786 this._keyEvent( "previous", event );
6787 break;
6788 case keyCode.DOWN:
6789 this._keyEvent( "next", event );
6790 break;
6791 }
6792 },
6793 input: function( event ) {
6794 if ( suppressInput ) {
6795 suppressInput = false;
6796 event.preventDefault();
6797 return;
6798 }
6799 this._searchTimeout( event );
6800 },
6801 focus: function() {
6802 this.selectedItem = null;
6803 this.previous = this._value();
6804 },
6805 blur: function( event ) {
6806 if ( this.cancelBlur ) {
6807 delete this.cancelBlur;
6808 return;
6809 }
6810
6811 clearTimeout( this.searching );
6812 this.close( event );
6813 this._change( event );
6814 }
6815 });
6816
6817 this._initSource();
6818 this.menu = $( "<ul>" )
6819 .addClass( "ui-autocomplete ui-front" )
6820 .appendTo( this._appendTo() )
6821 .menu({
6822 // disable ARIA support, the live region takes care of that
6823 role: null
6824 })
6825 .hide()
6826 .data( "ui-menu" );
6827
6828 this._on( this.menu.element, {
6829 mousedown: function( event ) {
6830 // prevent moving focus out of the text field
6831 event.preventDefault();
6832
6833 // IE doesn't prevent moving focus even with event.preventDefault()
6834 // so we set a flag to know when we should ignore the blur event
6835 this.cancelBlur = true;
6836 this._delay(function() {
6837 delete this.cancelBlur;
6838 });
6839
6840 // clicking on the scrollbar causes focus to shift to the body
6841 // but we can't detect a mouseup or a click immediately afterward
6842 // so we have to track the next mousedown and close the menu if
6843 // the user clicks somewhere outside of the autocomplete
6844 var menuElement = this.menu.element[ 0 ];
6845 if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
6846 this._delay(function() {
6847 var that = this;
6848 this.document.one( "mousedown", function( event ) {
6849 if ( event.target !== that.element[ 0 ] &&
6850 event.target !== menuElement &&
6851 !$.contains( menuElement, event.target ) ) {
6852 that.close();
6853 }
6854 });
6855 });
6856 }
6857 },
6858 menufocus: function( event, ui ) {
6859 // support: Firefox
6860 // Prevent accidental activation of menu items in Firefox (#7024 #9118)
6861 if ( this.isNewMenu ) {
6862 this.isNewMenu = false;
6863 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
6864 this.menu.blur();
6865
6866 this.document.one( "mousemove", function() {
6867 $( event.target ).trigger( event.originalEvent );
6868 });
6869
6870 return;
6871 }
6872 }
6873
6874 var item = ui.item.data( "ui-autocomplete-item" );
6875 if ( false !== this._trigger( "focus", event, { item: item } ) ) {
6876 // use value to match what will end up in the input, if it was a key event
6877 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
6878 this._value( item.value );
6879 }
6880 } else {
6881 // Normally the input is populated with the item's value as the
6882 // menu is navigated, causing screen readers to notice a change and
6883 // announce the item. Since the focus event was canceled, this doesn't
6884 // happen, so we update the live region so that screen readers can
6885 // still notice the change and announce it.
6886 this.liveRegion.text( item.value );
6887 }
6888 },
6889 menuselect: function( event, ui ) {
6890 var item = ui.item.data( "ui-autocomplete-item" ),
6891 previous = this.previous;
6892
6893 // only trigger when focus was lost (click on menu)
6894 if ( this.element[0] !== this.document[0].activeElement ) {
6895 this.element.focus();
6896 this.previous = previous;
6897 // #6109 - IE triggers two focus events and the second
6898 // is asynchronous, so we need to reset the previous
6899 // term synchronously and asynchronously :-(
6900 this._delay(function() {
6901 this.previous = previous;
6902 this.selectedItem = item;
6903 });
6904 }
6905
6906 if ( false !== this._trigger( "select", event, { item: item } ) ) {
6907 this._value( item.value );
6908 }
6909 // reset the term after the select event
6910 // this allows custom select handling to work properly
6911 this.term = this._value();
6912
6913 this.close( event );
6914 this.selectedItem = item;
6915 }
6916 });
6917
6918 this.liveRegion = $( "<span>", {
6919 role: "status",
6920 "aria-live": "polite"
6921 })
6922 .addClass( "ui-helper-hidden-accessible" )
6923 .insertBefore( this.element );
6924
6925 // turning off autocomplete prevents the browser from remembering the
6926 // value when navigating through history, so we re-enable autocomplete
6927 // if the page is unloaded before the widget is destroyed. #7790
6928 this._on( this.window, {
6929 beforeunload: function() {
6930 this.element.removeAttr( "autocomplete" );
6931 }
6932 });
6933 },
6934
6935 _destroy: function() {
6936 clearTimeout( this.searching );
6937 this.element
6938 .removeClass( "ui-autocomplete-input" )
6939 .removeAttr( "autocomplete" );
6940 this.menu.element.remove();
6941 this.liveRegion.remove();
6942 },
6943
6944 _setOption: function( key, value ) {
6945 this._super( key, value );
6946 if ( key === "source" ) {
6947 this._initSource();
6948 }
6949 if ( key === "appendTo" ) {
6950 this.menu.element.appendTo( this._appendTo() );
6951 }
6952 if ( key === "disabled" && value && this.xhr ) {
6953 this.xhr.abort();
6954 }
6955 },
6956
6957 _appendTo: function() {
6958 var element = this.options.appendTo;
6959
6960 if ( element ) {
6961 element = element.jquery || element.nodeType ?
6962 $( element ) :
6963 this.document.find( element ).eq( 0 );
6964 }
6965
6966 if ( !element ) {
6967 element = this.element.closest( ".ui-front" );
6968 }
6969
6970 if ( !element.length ) {
6971 element = this.document[0].body;
6972 }
6973
6974 return element;
6975 },
6976
6977 _initSource: function() {
6978 var array, url,
6979 that = this;
6980 if ( $.isArray(this.options.source) ) {
6981 array = this.options.source;
6982 this.source = function( request, response ) {
6983 response( $.ui.autocomplete.filter( array, request.term ) );
6984 };
6985 } else if ( typeof this.options.source === "string" ) {
6986 url = this.options.source;
6987 this.source = function( request, response ) {
6988 if ( that.xhr ) {
6989 that.xhr.abort();
6990 }
6991 that.xhr = $.ajax({
6992 url: url,
6993 data: request,
6994 dataType: "json",
6995 success: function( data ) {
6996 response( data );
6997 },
6998 error: function() {
6999 response( [] );
7000 }
7001 });
7002 };
7003 } else {
7004 this.source = this.options.source;
7005 }
7006 },
7007
7008 _searchTimeout: function( event ) {
7009 clearTimeout( this.searching );
7010 this.searching = this._delay(function() {
7011 // only search if the value has changed
7012 if ( this.term !== this._value() ) {
7013 this.selectedItem = null;
7014 this.search( null, event );
7015 }
7016 }, this.options.delay );
7017 },
7018
7019 search: function( value, event ) {
7020 value = value != null ? value : this._value();
7021
7022 // always save the actual value, not the one passed as an argument
7023 this.term = this._value();
7024
7025 if ( value.length < this.options.minLength ) {
7026 return this.close( event );
7027 }
7028
7029 if ( this._trigger( "search", event ) === false ) {
7030 return;
7031 }
7032
7033 return this._search( value );
7034 },
7035
7036 _search: function( value ) {
7037 this.pending++;
7038 this.element.addClass( "ui-autocomplete-loading" );
7039 this.cancelSearch = false;
7040
7041 this.source( { term: value }, this._response() );
7042 },
7043
7044 _response: function() {
7045 var index = ++this.requestIndex;
7046
7047 return $.proxy(function( content ) {
7048 if ( index === this.requestIndex ) {
7049 this.__response( content );
7050 }
7051
7052 this.pending--;
7053 if ( !this.pending ) {
7054 this.element.removeClass( "ui-autocomplete-loading" );
7055 }
7056 }, this );
7057 },
7058
7059 __response: function( content ) {
7060 if ( content ) {
7061 content = this._normalize( content );
7062 }
7063 this._trigger( "response", null, { content: content } );
7064 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
7065 this._suggest( content );
7066 this._trigger( "open" );
7067 } else {
7068 // use ._close() instead of .close() so we don't cancel future searches
7069 this._close();
7070 }
7071 },
7072
7073 close: function( event ) {
7074 this.cancelSearch = true;
7075 this._close( event );
7076 },
7077
7078 _close: function( event ) {
7079 if ( this.menu.element.is( ":visible" ) ) {
7080 this.menu.element.hide();
7081 this.menu.blur();
7082 this.isNewMenu = true;
7083 this._trigger( "close", event );
7084 }
7085 },
7086
7087 _change: function( event ) {
7088 if ( this.previous !== this._value() ) {
7089 this._trigger( "change", event, { item: this.selectedItem } );
7090 }
7091 },
7092
7093 _normalize: function( items ) {
7094 // assume all items have the right format when the first item is complete
7095 if ( items.length && items[0].label && items[0].value ) {
7096 return items;
7097 }
7098 return $.map( items, function( item ) {
7099 if ( typeof item === "string" ) {
7100 return {
7101 label: item,
7102 value: item
7103 };
7104 }
7105 return $.extend({
7106 label: item.label || item.value,
7107 value: item.value || item.label
7108 }, item );
7109 });
7110 },
7111
7112 _suggest: function( items ) {
7113 var ul = this.menu.element.empty();
7114 this._renderMenu( ul, items );
7115 this.isNewMenu = true;
7116 this.menu.refresh();
7117
7118 // size and position menu
7119 ul.show();
7120 this._resizeMenu();
7121 ul.position( $.extend({
7122 of: this.element
7123 }, this.options.position ));
7124
7125 if ( this.options.autoFocus ) {
7126 this.menu.next();
7127 }
7128 },
7129
7130 _resizeMenu: function() {
7131 var ul = this.menu.element;
7132 ul.outerWidth( Math.max(
7133 // Firefox wraps long text (possibly a rounding bug)
7134 // so we add 1px to avoid the wrapping (#7513)
7135 ul.width( "" ).outerWidth() + 1,
7136 this.element.outerWidth()
7137 ) );
7138 },
7139
7140 _renderMenu: function( ul, items ) {
7141 var that = this;
7142 $.each( items, function( index, item ) {
7143 that._renderItemData( ul, item );
7144 });
7145 },
7146
7147 _renderItemData: function( ul, item ) {
7148 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
7149 },
7150
7151 _renderItem: function( ul, item ) {
7152 return $( "<li>" )
7153 .append( $( "<a>" ).text( item.label ) )
7154 .appendTo( ul );
7155 },
7156
7157 _move: function( direction, event ) {
7158 if ( !this.menu.element.is( ":visible" ) ) {
7159 this.search( null, event );
7160 return;
7161 }
7162 if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
7163 this.menu.isLastItem() && /^next/.test( direction ) ) {
7164 this._value( this.term );
7165 this.menu.blur();
7166 return;
7167 }
7168 this.menu[ direction ]( event );
7169 },
7170
7171 widget: function() {
7172 return this.menu.element;
7173 },
7174
7175 _value: function() {
7176 return this.valueMethod.apply( this.element, arguments );
7177 },
7178
7179 _keyEvent: function( keyEvent, event ) {
7180 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
7181 this._move( keyEvent, event );
7182
7183 // prevents moving cursor to beginning/end of the text field in some browsers
7184 event.preventDefault();
7185 }
7186 }
7187 });
7188
7189 $.extend( $.ui.autocomplete, {
7190 escapeRegex: function( value ) {
7191 return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
7192 },
7193 filter: function(array, term) {
7194 var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
7195 return $.grep( array, function(value) {
7196 return matcher.test( value.label || value.value || value );
7197 });
7198 }
7199 });
7200
7201
7202 // live region extension, adding a `messages` option
7203 // NOTE: This is an experimental API. We are still investigating
7204 // a full solution for string manipulation and internationalization.
7205 $.widget( "ui.autocomplete", $.ui.autocomplete, {
7206 options: {
7207 messages: {
7208 noResults: "No search results.",
7209 results: function( amount ) {
7210 return amount + ( amount > 1 ? " results are" : " result is" ) +
7211 " available, use up and down arrow keys to navigate.";
7212 }
7213 }
7214 },
7215
7216 __response: function( content ) {
7217 var message;
7218 this._superApply( arguments );
7219 if ( this.options.disabled || this.cancelSearch ) {
7220 return;
7221 }
7222 if ( content && content.length ) {
7223 message = this.options.messages.results( content.length );
7224 } else {
7225 message = this.options.messages.noResults;
7226 }
7227 this.liveRegion.text( message );
7228 }
7229 });
7230
7231 }( jQuery ));
7232
7233 (function( $, undefined ) {
7234
7235 var lastActive,
7236 baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
7237 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",
7238 formResetHandler = function() {
7239 var form = $( this );
7240 setTimeout(function() {
7241 form.find( ":ui-button" ).button( "refresh" );
7242 }, 1 );
7243 },
7244 radioGroup = function( radio ) {
7245 var name = radio.name,
7246 form = radio.form,
7247 radios = $( [] );
7248 if ( name ) {
7249 name = name.replace( /'/g, "\\'" );
7250 if ( form ) {
7251 radios = $( form ).find( "[name='" + name + "']" );
7252 } else {
7253 radios = $( "[name='" + name + "']", radio.ownerDocument )
7254 .filter(function() {
7255 return !this.form;
7256 });
7257 }
7258 }
7259 return radios;
7260 };
7261
7262 $.widget( "ui.button", {
7263 version: "1.10.4",
7264 defaultElement: "<button>",
7265 options: {
7266 disabled: null,
7267 text: true,
7268 label: null,
7269 icons: {
7270 primary: null,
7271 secondary: null
7272 }
7273 },
7274 _create: function() {
7275 this.element.closest( "form" )
7276 .unbind( "reset" + this.eventNamespace )
7277 .bind( "reset" + this.eventNamespace, formResetHandler );
7278
7279 if ( typeof this.options.disabled !== "boolean" ) {
7280 this.options.disabled = !!this.element.prop( "disabled" );
7281 } else {
7282 this.element.prop( "disabled", this.options.disabled );
7283 }
7284
7285 this._determineButtonType();
7286 this.hasTitle = !!this.buttonElement.attr( "title" );
7287
7288 var that = this,
7289 options = this.options,
7290 toggleButton = this.type === "checkbox" || this.type === "radio",
7291 activeClass = !toggleButton ? "ui-state-active" : "";
7292
7293 if ( options.label === null ) {
7294 options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html());
7295 }
7296
7297 this._hoverable( this.buttonElement );
7298
7299 this.buttonElement
7300 .addClass( baseClasses )
7301 .attr( "role", "button" )
7302 .bind( "mouseenter" + this.eventNamespace, function() {
7303 if ( options.disabled ) {
7304 return;
7305 }
7306 if ( this === lastActive ) {
7307 $( this ).addClass( "ui-state-active" );
7308 }
7309 })
7310 .bind( "mouseleave" + this.eventNamespace, function() {
7311 if ( options.disabled ) {
7312 return;
7313 }
7314 $( this ).removeClass( activeClass );
7315 })
7316 .bind( "click" + this.eventNamespace, function( event ) {
7317 if ( options.disabled ) {
7318 event.preventDefault();
7319 event.stopImmediatePropagation();
7320 }
7321 });
7322
7323 // Can't use _focusable() because the element that receives focus
7324 // and the element that gets the ui-state-focus class are different
7325 this._on({
7326 focus: function() {
7327 this.buttonElement.addClass( "ui-state-focus" );
7328 },
7329 blur: function() {
7330 this.buttonElement.removeClass( "ui-state-focus" );
7331 }
7332 });
7333
7334 if ( toggleButton ) {
7335 this.element.bind( "change" + this.eventNamespace, function() {
7336 that.refresh();
7337 });
7338 }
7339
7340 if ( this.type === "checkbox" ) {
7341 this.buttonElement.bind( "click" + this.eventNamespace, function() {
7342 if ( options.disabled ) {
7343 return false;
7344 }
7345 });
7346 } else if ( this.type === "radio" ) {
7347 this.buttonElement.bind( "click" + this.eventNamespace, function() {
7348 if ( options.disabled ) {
7349 return false;
7350 }
7351 $( this ).addClass( "ui-state-active" );
7352 that.buttonElement.attr( "aria-pressed", "true" );
7353
7354 var radio = that.element[ 0 ];
7355 radioGroup( radio )
7356 .not( radio )
7357 .map(function() {
7358 return $( this ).button( "widget" )[ 0 ];
7359 })
7360 .removeClass( "ui-state-active" )
7361 .attr( "aria-pressed", "false" );
7362 });
7363 } else {
7364 this.buttonElement
7365 .bind( "mousedown" + this.eventNamespace, function() {
7366 if ( options.disabled ) {
7367 return false;
7368 }
7369 $( this ).addClass( "ui-state-active" );
7370 lastActive = this;
7371 that.document.one( "mouseup", function() {
7372 lastActive = null;
7373 });
7374 })
7375 .bind( "mouseup" + this.eventNamespace, function() {
7376 if ( options.disabled ) {
7377 return false;
7378 }
7379 $( this ).removeClass( "ui-state-active" );
7380 })
7381 .bind( "keydown" + this.eventNamespace, function(event) {
7382 if ( options.disabled ) {
7383 return false;
7384 }
7385 if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) {
7386 $( this ).addClass( "ui-state-active" );
7387 }
7388 })
7389 // see #8559, we bind to blur here in case the button element loses
7390 // focus between keydown and keyup, it would be left in an "active" state
7391 .bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() {
7392 $( this ).removeClass( "ui-state-active" );
7393 });
7394
7395 if ( this.buttonElement.is("a") ) {
7396 this.buttonElement.keyup(function(event) {
7397 if ( event.keyCode === $.ui.keyCode.SPACE ) {
7398 // TODO pass through original event correctly (just as 2nd argument doesn't work)
7399 $( this ).click();
7400 }
7401 });
7402 }
7403 }
7404
7405 // TODO: pull out $.Widget's handling for the disabled option into
7406 // $.Widget.prototype._setOptionDisabled so it's easy to proxy and can
7407 // be overridden by individual plugins
7408 this._setOption( "disabled", options.disabled );
7409 this._resetButton();
7410 },
7411
7412 _determineButtonType: function() {
7413 var ancestor, labelSelector, checked;
7414
7415 if ( this.element.is("[type=checkbox]") ) {
7416 this.type = "checkbox";
7417 } else if ( this.element.is("[type=radio]") ) {
7418 this.type = "radio";
7419 } else if ( this.element.is("input") ) {
7420 this.type = "input";
7421 } else {
7422 this.type = "button";
7423 }
7424
7425 if ( this.type === "checkbox" || this.type === "radio" ) {
7426 // we don't search against the document in case the element
7427 // is disconnected from the DOM
7428 ancestor = this.element.parents().last();
7429 labelSelector = "label[for='" + this.element.attr("id") + "']";
7430 this.buttonElement = ancestor.find( labelSelector );
7431 if ( !this.buttonElement.length ) {
7432 ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
7433 this.buttonElement = ancestor.filter( labelSelector );
7434 if ( !this.buttonElement.length ) {
7435 this.buttonElement = ancestor.find( labelSelector );
7436 }
7437 }
7438 this.element.addClass( "ui-helper-hidden-accessible" );
7439
7440 checked = this.element.is( ":checked" );
7441 if ( checked ) {
7442 this.buttonElement.addClass( "ui-state-active" );
7443 }
7444 this.buttonElement.prop( "aria-pressed", checked );
7445 } else {
7446 this.buttonElement = this.element;
7447 }
7448 },
7449
7450 widget: function() {
7451 return this.buttonElement;
7452 },
7453
7454 _destroy: function() {
7455 this.element
7456 .removeClass( "ui-helper-hidden-accessible" );
7457 this.buttonElement
7458 .removeClass( baseClasses + " ui-state-active " + typeClasses )
7459 .removeAttr( "role" )
7460 .removeAttr( "aria-pressed" )
7461 .html( this.buttonElement.find(".ui-button-text").html() );
7462
7463 if ( !this.hasTitle ) {
7464 this.buttonElement.removeAttr( "title" );
7465 }
7466 },
7467
7468 _setOption: function( key, value ) {
7469 this._super( key, value );
7470 if ( key === "disabled" ) {
7471 this.element.prop( "disabled", !!value );
7472 if ( value ) {
7473 this.buttonElement.removeClass( "ui-state-focus" );
7474 }
7475 return;
7476 }
7477 this._resetButton();
7478 },
7479
7480 refresh: function() {
7481 //See #8237 & #8828
7482 var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" );
7483
7484 if ( isDisabled !== this.options.disabled ) {
7485 this._setOption( "disabled", isDisabled );
7486 }
7487 if ( this.type === "radio" ) {
7488 radioGroup( this.element[0] ).each(function() {
7489 if ( $( this ).is( ":checked" ) ) {
7490 $( this ).button( "widget" )
7491 .addClass( "ui-state-active" )
7492 .attr( "aria-pressed", "true" );
7493 } else {
7494 $( this ).button( "widget" )
7495 .removeClass( "ui-state-active" )
7496 .attr( "aria-pressed", "false" );
7497 }
7498 });
7499 } else if ( this.type === "checkbox" ) {
7500 if ( this.element.is( ":checked" ) ) {
7501 this.buttonElement
7502 .addClass( "ui-state-active" )
7503 .attr( "aria-pressed", "true" );
7504 } else {
7505 this.buttonElement
7506 .removeClass( "ui-state-active" )
7507 .attr( "aria-pressed", "false" );
7508 }
7509 }
7510 },
7511
7512 _resetButton: function() {
7513 if ( this.type === "input" ) {
7514 if ( this.options.label ) {
7515 this.element.val( this.options.label );
7516 }
7517 return;
7518 }
7519 var buttonElement = this.buttonElement.removeClass( typeClasses ),
7520 buttonText = $( "<span></span>", this.document[0] )
7521 .addClass( "ui-button-text" )
7522 .html( this.options.label )
7523 .appendTo( buttonElement.empty() )
7524 .text(),
7525 icons = this.options.icons,
7526 multipleIcons = icons.primary && icons.secondary,
7527 buttonClasses = [];
7528
7529 if ( icons.primary || icons.secondary ) {
7530 if ( this.options.text ) {
7531 buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
7532 }
7533
7534 if ( icons.primary ) {
7535 buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
7536 }
7537
7538 if ( icons.secondary ) {
7539 buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
7540 }
7541
7542 if ( !this.options.text ) {
7543 buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );
7544
7545 if ( !this.hasTitle ) {
7546 buttonElement.attr( "title", $.trim( buttonText ) );
7547 }
7548 }
7549 } else {
7550 buttonClasses.push( "ui-button-text-only" );
7551 }
7552 buttonElement.addClass( buttonClasses.join( " " ) );
7553 }
7554 });
7555
7556 $.widget( "ui.buttonset", {
7557 version: "1.10.4",
7558 options: {
7559 items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"
7560 },
7561
7562 _create: function() {
7563 this.element.addClass( "ui-buttonset" );
7564 },
7565
7566 _init: function() {
7567 this.refresh();
7568 },
7569
7570 _setOption: function( key, value ) {
7571 if ( key === "disabled" ) {
7572 this.buttons.button( "option", key, value );
7573 }
7574
7575 this._super( key, value );
7576 },
7577
7578 refresh: function() {
7579 var rtl = this.element.css( "direction" ) === "rtl";
7580
7581 this.buttons = this.element.find( this.options.items )
7582 .filter( ":ui-button" )
7583 .button( "refresh" )
7584 .end()
7585 .not( ":ui-button" )
7586 .button()
7587 .end()
7588 .map(function() {
7589 return $( this ).button( "widget" )[ 0 ];
7590 })
7591 .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
7592 .filter( ":first" )
7593 .addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
7594 .end()
7595 .filter( ":last" )
7596 .addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
7597 .end()
7598 .end();
7599 },
7600
7601 _destroy: function() {
7602 this.element.removeClass( "ui-buttonset" );
7603 this.buttons
7604 .map(function() {
7605 return $( this ).button( "widget" )[ 0 ];
7606 })
7607 .removeClass( "ui-corner-left ui-corner-right" )
7608 .end()
7609 .button( "destroy" );
7610 }
7611 });
7612
7613 }( jQuery ) );
7614
7615 (function( $, undefined ) {
7616
7617 $.extend($.ui, { datepicker: { version: "1.10.4" } });
7618
7619 var PROP_NAME = "datepicker",
7620 instActive;
7621
7622 /* Date picker manager.
7623 Use the singleton instance of this class, $.datepicker, to interact with the date picker.
7624 Settings for (groups of) date pickers are maintained in an instance object,
7625 allowing multiple different settings on the same page. */
7626
7627 function Datepicker() {
7628 this._curInst = null; // The current instance in use
7629 this._keyEvent = false; // If the last event was a key event
7630 this._disabledInputs = []; // List of date picker inputs that have been disabled
7631 this._datepickerShowing = false; // True if the popup picker is showing , false if not
7632 this._inDialog = false; // True if showing within a "dialog", false if not
7633 this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
7634 this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
7635 this._appendClass = "ui-datepicker-append"; // The name of the append marker class
7636 this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
7637 this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
7638 this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
7639 this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
7640 this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
7641 this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
7642 this.regional = []; // Available regional settings, indexed by language code
7643 this.regional[""] = { // Default regional settings
7644 closeText: "Done", // Display text for close link
7645 prevText: "Prev", // Display text for previous month link
7646 nextText: "Next", // Display text for next month link
7647 currentText: "Today", // Display text for current month link
7648 monthNames: ["January","February","March","April","May","June",
7649 "July","August","September","October","November","December"], // Names of months for drop-down and formatting
7650 monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
7651 dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
7652 dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
7653 dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
7654 weekHeader: "Wk", // Column header for week of the year
7655 dateFormat: "mm/dd/yy", // See format options on parseDate
7656 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
7657 isRTL: false, // True if right-to-left language, false if left-to-right
7658 showMonthAfterYear: false, // True if the year select precedes month, false for month then year
7659 yearSuffix: "" // Additional text to append to the year in the month headers
7660 };
7661 this._defaults = { // Global defaults for all the date picker instances
7662 showOn: "focus", // "focus" for popup on focus,
7663 // "button" for trigger button, or "both" for either
7664 showAnim: "fadeIn", // Name of jQuery animation for popup
7665 showOptions: {}, // Options for enhanced animations
7666 defaultDate: null, // Used when field is blank: actual date,
7667 // +/-number for offset from today, null for today
7668 appendText: "", // Display text following the input box, e.g. showing the format
7669 buttonText: "...", // Text for trigger button
7670 buttonImage: "", // URL for trigger button image
7671 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
7672 hideIfNoPrevNext: false, // True to hide next/previous month links
7673 // if not applicable, false to just disable them
7674 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
7675 gotoCurrent: false, // True if today link goes back to current selection instead
7676 changeMonth: false, // True if month can be selected directly, false if only prev/next
7677 changeYear: false, // True if year can be selected directly, false if only prev/next
7678 yearRange: "c-10:c+10", // Range of years to display in drop-down,
7679 // either relative to today's year (-nn:+nn), relative to currently displayed year
7680 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
7681 showOtherMonths: false, // True to show dates in other months, false to leave blank
7682 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
7683 showWeek: false, // True to show week of the year, false to not show it
7684 calculateWeek: this.iso8601Week, // How to calculate the week of the year,
7685 // takes a Date and returns the number of the week for it
7686 shortYearCutoff: "+10", // Short year values < this are in the current century,
7687 // > this are in the previous century,
7688 // string value starting with "+" for current year + value
7689 minDate: null, // The earliest selectable date, or null for no limit
7690 maxDate: null, // The latest selectable date, or null for no limit
7691 duration: "fast", // Duration of display/closure
7692 beforeShowDay: null, // Function that takes a date and returns an array with
7693 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
7694 // [2] = cell title (optional), e.g. $.datepicker.noWeekends
7695 beforeShow: null, // Function that takes an input field and
7696 // returns a set of custom settings for the date picker
7697 onSelect: null, // Define a callback function when a date is selected
7698 onChangeMonthYear: null, // Define a callback function when the month or year is changed
7699 onClose: null, // Define a callback function when the datepicker is closed
7700 numberOfMonths: 1, // Number of months to show at a time
7701 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
7702 stepMonths: 1, // Number of months to step back/forward
7703 stepBigMonths: 12, // Number of months to step back/forward for the big links
7704 altField: "", // Selector for an alternate field to store selected dates into
7705 altFormat: "", // The date format to use for the alternate field
7706 constrainInput: true, // The input is constrained by the current date format
7707 showButtonPanel: false, // True to show button panel, false to not show it
7708 autoSize: false, // True to size the input for the date format, false to leave as is
7709 disabled: false // The initial disabled state
7710 };
7711 $.extend(this._defaults, this.regional[""]);
7712 this.dpDiv = bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
7713 }
7714
7715 $.extend(Datepicker.prototype, {
7716 /* Class name added to elements to indicate already configured with a date picker. */
7717 markerClassName: "hasDatepicker",
7718
7719 //Keep track of the maximum number of rows displayed (see #7043)
7720 maxRows: 4,
7721
7722 // TODO rename to "widget" when switching to widget factory
7723 _widgetDatepicker: function() {
7724 return this.dpDiv;
7725 },
7726
7727 /* Override the default settings for all instances of the date picker.
7728 * @param settings object - the new settings to use as defaults (anonymous object)
7729 * @return the manager object
7730 */
7731 setDefaults: function(settings) {
7732 extendRemove(this._defaults, settings || {});
7733 return this;
7734 },
7735
7736 /* Attach the date picker to a jQuery selection.
7737 * @param target element - the target input field or division or span
7738 * @param settings object - the new settings to use for this date picker instance (anonymous)
7739 */
7740 _attachDatepicker: function(target, settings) {
7741 var nodeName, inline, inst;
7742 nodeName = target.nodeName.toLowerCase();
7743 inline = (nodeName === "div" || nodeName === "span");
7744 if (!target.id) {
7745 this.uuid += 1;
7746 target.id = "dp" + this.uuid;
7747 }
7748 inst = this._newInst($(target), inline);
7749 inst.settings = $.extend({}, settings || {});
7750 if (nodeName === "input") {
7751 this._connectDatepicker(target, inst);
7752 } else if (inline) {
7753 this._inlineDatepicker(target, inst);
7754 }
7755 },
7756
7757 /* Create a new instance object. */
7758 _newInst: function(target, inline) {
7759 var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
7760 return {id: id, input: target, // associated target
7761 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
7762 drawMonth: 0, drawYear: 0, // month being drawn
7763 inline: inline, // is datepicker inline or not
7764 dpDiv: (!inline ? this.dpDiv : // presentation div
7765 bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
7766 },
7767
7768 /* Attach the date picker to an input field. */
7769 _connectDatepicker: function(target, inst) {
7770 var input = $(target);
7771 inst.append = $([]);
7772 inst.trigger = $([]);
7773 if (input.hasClass(this.markerClassName)) {
7774 return;
7775 }
7776 this._attachments(input, inst);
7777 input.addClass(this.markerClassName).keydown(this._doKeyDown).
7778 keypress(this._doKeyPress).keyup(this._doKeyUp);
7779 this._autoSize(inst);
7780 $.data(target, PROP_NAME, inst);
7781 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
7782 if( inst.settings.disabled ) {
7783 this._disableDatepicker( target );
7784 }
7785 },
7786
7787 /* Make attachments based on settings. */
7788 _attachments: function(input, inst) {
7789 var showOn, buttonText, buttonImage,
7790 appendText = this._get(inst, "appendText"),
7791 isRTL = this._get(inst, "isRTL");
7792
7793 if (inst.append) {
7794 inst.append.remove();
7795 }
7796 if (appendText) {
7797 inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
7798 input[isRTL ? "before" : "after"](inst.append);
7799 }
7800
7801 input.unbind("focus", this._showDatepicker);
7802
7803 if (inst.trigger) {
7804 inst.trigger.remove();
7805 }
7806
7807 showOn = this._get(inst, "showOn");
7808 if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
7809 input.focus(this._showDatepicker);
7810 }
7811 if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
7812 buttonText = this._get(inst, "buttonText");
7813 buttonImage = this._get(inst, "buttonImage");
7814 inst.trigger = $(this._get(inst, "buttonImageOnly") ?
7815 $("<img/>").addClass(this._triggerClass).
7816 attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
7817 $("<button type='button'></button>").addClass(this._triggerClass).
7818 html(!buttonImage ? buttonText : $("<img/>").attr(
7819 { src:buttonImage, alt:buttonText, title:buttonText })));
7820 input[isRTL ? "before" : "after"](inst.trigger);
7821 inst.trigger.click(function() {
7822 if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
7823 $.datepicker._hideDatepicker();
7824 } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
7825 $.datepicker._hideDatepicker();
7826 $.datepicker._showDatepicker(input[0]);
7827 } else {
7828 $.datepicker._showDatepicker(input[0]);
7829 }
7830 return false;
7831 });
7832 }
7833 },
7834
7835 /* Apply the maximum length for the date format. */
7836 _autoSize: function(inst) {
7837 if (this._get(inst, "autoSize") && !inst.inline) {
7838 var findMax, max, maxI, i,
7839 date = new Date(2009, 12 - 1, 20), // Ensure double digits
7840 dateFormat = this._get(inst, "dateFormat");
7841
7842 if (dateFormat.match(/[DM]/)) {
7843 findMax = function(names) {
7844 max = 0;
7845 maxI = 0;
7846 for (i = 0; i < names.length; i++) {
7847 if (names[i].length > max) {
7848 max = names[i].length;
7849 maxI = i;
7850 }
7851 }
7852 return maxI;
7853 };
7854 date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
7855 "monthNames" : "monthNamesShort"))));
7856 date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
7857 "dayNames" : "dayNamesShort"))) + 20 - date.getDay());
7858 }
7859 inst.input.attr("size", this._formatDate(inst, date).length);
7860 }
7861 },
7862
7863 /* Attach an inline date picker to a div. */
7864 _inlineDatepicker: function(target, inst) {
7865 var divSpan = $(target);
7866 if (divSpan.hasClass(this.markerClassName)) {
7867 return;
7868 }
7869 divSpan.addClass(this.markerClassName).append(inst.dpDiv);
7870 $.data(target, PROP_NAME, inst);
7871 this._setDate(inst, this._getDefaultDate(inst), true);
7872 this._updateDatepicker(inst);
7873 this._updateAlternate(inst);
7874 //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
7875 if( inst.settings.disabled ) {
7876 this._disableDatepicker( target );
7877 }
7878 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
7879 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
7880 inst.dpDiv.css( "display", "block" );
7881 },
7882
7883 /* Pop-up the date picker in a "dialog" box.
7884 * @param input element - ignored
7885 * @param date string or Date - the initial date to display
7886 * @param onSelect function - the function to call when a date is selected
7887 * @param settings object - update the dialog date picker instance's settings (anonymous object)
7888 * @param pos int[2] - coordinates for the dialog's position within the screen or
7889 * event - with x/y coordinates or
7890 * leave empty for default (screen centre)
7891 * @return the manager object
7892 */
7893 _dialogDatepicker: function(input, date, onSelect, settings, pos) {
7894 var id, browserWidth, browserHeight, scrollX, scrollY,
7895 inst = this._dialogInst; // internal instance
7896
7897 if (!inst) {
7898 this.uuid += 1;
7899 id = "dp" + this.uuid;
7900 this._dialogInput = $("<input type='text' id='" + id +
7901 "' style='position: absolute; top: -100px; width: 0px;'/>");
7902 this._dialogInput.keydown(this._doKeyDown);
7903 $("body").append(this._dialogInput);
7904 inst = this._dialogInst = this._newInst(this._dialogInput, false);
7905 inst.settings = {};
7906 $.data(this._dialogInput[0], PROP_NAME, inst);
7907 }
7908 extendRemove(inst.settings, settings || {});
7909 date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
7910 this._dialogInput.val(date);
7911
7912 this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
7913 if (!this._pos) {
7914 browserWidth = document.documentElement.clientWidth;
7915 browserHeight = document.documentElement.clientHeight;
7916 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
7917 scrollY = document.documentElement.scrollTop || document.body.scrollTop;
7918 this._pos = // should use actual width/height below
7919 [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
7920 }
7921
7922 // move input on screen for focus, but hidden behind dialog
7923 this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
7924 inst.settings.onSelect = onSelect;
7925 this._inDialog = true;
7926 this.dpDiv.addClass(this._dialogClass);
7927 this._showDatepicker(this._dialogInput[0]);
7928 if ($.blockUI) {
7929 $.blockUI(this.dpDiv);
7930 }
7931 $.data(this._dialogInput[0], PROP_NAME, inst);
7932 return this;
7933 },
7934
7935 /* Detach a datepicker from its control.
7936 * @param target element - the target input field or division or span
7937 */
7938 _destroyDatepicker: function(target) {
7939 var nodeName,
7940 $target = $(target),
7941 inst = $.data(target, PROP_NAME);
7942
7943 if (!$target.hasClass(this.markerClassName)) {
7944 return;
7945 }
7946
7947 nodeName = target.nodeName.toLowerCase();
7948 $.removeData(target, PROP_NAME);
7949 if (nodeName === "input") {
7950 inst.append.remove();
7951 inst.trigger.remove();
7952 $target.removeClass(this.markerClassName).
7953 unbind("focus", this._showDatepicker).
7954 unbind("keydown", this._doKeyDown).
7955 unbind("keypress", this._doKeyPress).
7956 unbind("keyup", this._doKeyUp);
7957 } else if (nodeName === "div" || nodeName === "span") {
7958 $target.removeClass(this.markerClassName).empty();
7959 }
7960 },
7961
7962 /* Enable the date picker to a jQuery selection.
7963 * @param target element - the target input field or division or span
7964 */
7965 _enableDatepicker: function(target) {
7966 var nodeName, inline,
7967 $target = $(target),
7968 inst = $.data(target, PROP_NAME);
7969
7970 if (!$target.hasClass(this.markerClassName)) {
7971 return;
7972 }
7973
7974 nodeName = target.nodeName.toLowerCase();
7975 if (nodeName === "input") {
7976 target.disabled = false;
7977 inst.trigger.filter("button").
7978 each(function() { this.disabled = false; }).end().
7979 filter("img").css({opacity: "1.0", cursor: ""});
7980 } else if (nodeName === "div" || nodeName === "span") {
7981 inline = $target.children("." + this._inlineClass);
7982 inline.children().removeClass("ui-state-disabled");
7983 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
7984 prop("disabled", false);
7985 }
7986 this._disabledInputs = $.map(this._disabledInputs,
7987 function(value) { return (value === target ? null : value); }); // delete entry
7988 },
7989
7990 /* Disable the date picker to a jQuery selection.
7991 * @param target element - the target input field or division or span
7992 */
7993 _disableDatepicker: function(target) {
7994 var nodeName, inline,
7995 $target = $(target),
7996 inst = $.data(target, PROP_NAME);
7997
7998 if (!$target.hasClass(this.markerClassName)) {
7999 return;
8000 }
8001
8002 nodeName = target.nodeName.toLowerCase();
8003 if (nodeName === "input") {
8004 target.disabled = true;
8005 inst.trigger.filter("button").
8006 each(function() { this.disabled = true; }).end().
8007 filter("img").css({opacity: "0.5", cursor: "default"});
8008 } else if (nodeName === "div" || nodeName === "span") {
8009 inline = $target.children("." + this._inlineClass);
8010 inline.children().addClass("ui-state-disabled");
8011 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
8012 prop("disabled", true);
8013 }
8014 this._disabledInputs = $.map(this._disabledInputs,
8015 function(value) { return (value === target ? null : value); }); // delete entry
8016 this._disabledInputs[this._disabledInputs.length] = target;
8017 },
8018
8019 /* Is the first field in a jQuery collection disabled as a datepicker?
8020 * @param target element - the target input field or division or span
8021 * @return boolean - true if disabled, false if enabled
8022 */
8023 _isDisabledDatepicker: function(target) {
8024 if (!target) {
8025 return false;
8026 }
8027 for (var i = 0; i < this._disabledInputs.length; i++) {
8028 if (this._disabledInputs[i] === target) {
8029 return true;
8030 }
8031 }
8032 return false;
8033 },
8034
8035 /* Retrieve the instance data for the target control.
8036 * @param target element - the target input field or division or span
8037 * @return object - the associated instance data
8038 * @throws error if a jQuery problem getting data
8039 */
8040 _getInst: function(target) {
8041 try {
8042 return $.data(target, PROP_NAME);
8043 }
8044 catch (err) {
8045 throw "Missing instance data for this datepicker";
8046 }
8047 },
8048
8049 /* Update or retrieve the settings for a date picker attached to an input field or division.
8050 * @param target element - the target input field or division or span
8051 * @param name object - the new settings to update or
8052 * string - the name of the setting to change or retrieve,
8053 * when retrieving also "all" for all instance settings or
8054 * "defaults" for all global defaults
8055 * @param value any - the new value for the setting
8056 * (omit if above is an object or to retrieve a value)
8057 */
8058 _optionDatepicker: function(target, name, value) {
8059 var settings, date, minDate, maxDate,
8060 inst = this._getInst(target);
8061
8062 if (arguments.length === 2 && typeof name === "string") {
8063 return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
8064 (inst ? (name === "all" ? $.extend({}, inst.settings) :
8065 this._get(inst, name)) : null));
8066 }
8067
8068 settings = name || {};
8069 if (typeof name === "string") {
8070 settings = {};
8071 settings[name] = value;
8072 }
8073
8074 if (inst) {
8075 if (this._curInst === inst) {
8076 this._hideDatepicker();
8077 }
8078
8079 date = this._getDateDatepicker(target, true);
8080 minDate = this._getMinMaxDate(inst, "min");
8081 maxDate = this._getMinMaxDate(inst, "max");
8082 extendRemove(inst.settings, settings);
8083 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
8084 if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
8085 inst.settings.minDate = this._formatDate(inst, minDate);
8086 }
8087 if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
8088 inst.settings.maxDate = this._formatDate(inst, maxDate);
8089 }
8090 if ( "disabled" in settings ) {
8091 if ( settings.disabled ) {
8092 this._disableDatepicker(target);
8093 } else {
8094 this._enableDatepicker(target);
8095 }
8096 }
8097 this._attachments($(target), inst);
8098 this._autoSize(inst);
8099 this._setDate(inst, date);
8100 this._updateAlternate(inst);
8101 this._updateDatepicker(inst);
8102 }
8103 },
8104
8105 // change method deprecated
8106 _changeDatepicker: function(target, name, value) {
8107 this._optionDatepicker(target, name, value);
8108 },
8109
8110 /* Redraw the date picker attached to an input field or division.
8111 * @param target element - the target input field or division or span
8112 */
8113 _refreshDatepicker: function(target) {
8114 var inst = this._getInst(target);
8115 if (inst) {
8116 this._updateDatepicker(inst);
8117 }
8118 },
8119
8120 /* Set the dates for a jQuery selection.
8121 * @param target element - the target input field or division or span
8122 * @param date Date - the new date
8123 */
8124 _setDateDatepicker: function(target, date) {
8125 var inst = this._getInst(target);
8126 if (inst) {
8127 this._setDate(inst, date);
8128 this._updateDatepicker(inst);
8129 this._updateAlternate(inst);
8130 }
8131 },
8132
8133 /* Get the date(s) for the first entry in a jQuery selection.
8134 * @param target element - the target input field or division or span
8135 * @param noDefault boolean - true if no default date is to be used
8136 * @return Date - the current date
8137 */
8138 _getDateDatepicker: function(target, noDefault) {
8139 var inst = this._getInst(target);
8140 if (inst && !inst.inline) {
8141 this._setDateFromField(inst, noDefault);
8142 }
8143 return (inst ? this._getDate(inst) : null);
8144 },
8145
8146 /* Handle keystrokes. */
8147 _doKeyDown: function(event) {
8148 var onSelect, dateStr, sel,
8149 inst = $.datepicker._getInst(event.target),
8150 handled = true,
8151 isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
8152
8153 inst._keyEvent = true;
8154 if ($.datepicker._datepickerShowing) {
8155 switch (event.keyCode) {
8156 case 9: $.datepicker._hideDatepicker();
8157 handled = false;
8158 break; // hide on tab out
8159 case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
8160 $.datepicker._currentClass + ")", inst.dpDiv);
8161 if (sel[0]) {
8162 $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
8163 }
8164
8165 onSelect = $.datepicker._get(inst, "onSelect");
8166 if (onSelect) {
8167 dateStr = $.datepicker._formatDate(inst);
8168
8169 // trigger custom callback
8170 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
8171 } else {
8172 $.datepicker._hideDatepicker();
8173 }
8174
8175 return false; // don't submit the form
8176 case 27: $.datepicker._hideDatepicker();
8177 break; // hide on escape
8178 case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
8179 -$.datepicker._get(inst, "stepBigMonths") :
8180 -$.datepicker._get(inst, "stepMonths")), "M");
8181 break; // previous month/year on page up/+ ctrl
8182 case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
8183 +$.datepicker._get(inst, "stepBigMonths") :
8184 +$.datepicker._get(inst, "stepMonths")), "M");
8185 break; // next month/year on page down/+ ctrl
8186 case 35: if (event.ctrlKey || event.metaKey) {
8187 $.datepicker._clearDate(event.target);
8188 }
8189 handled = event.ctrlKey || event.metaKey;
8190 break; // clear on ctrl or command +end
8191 case 36: if (event.ctrlKey || event.metaKey) {
8192 $.datepicker._gotoToday(event.target);
8193 }
8194 handled = event.ctrlKey || event.metaKey;
8195 break; // current on ctrl or command +home
8196 case 37: if (event.ctrlKey || event.metaKey) {
8197 $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
8198 }
8199 handled = event.ctrlKey || event.metaKey;
8200 // -1 day on ctrl or command +left
8201 if (event.originalEvent.altKey) {
8202 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
8203 -$.datepicker._get(inst, "stepBigMonths") :
8204 -$.datepicker._get(inst, "stepMonths")), "M");
8205 }
8206 // next month/year on alt +left on Mac
8207 break;
8208 case 38: if (event.ctrlKey || event.metaKey) {
8209 $.datepicker._adjustDate(event.target, -7, "D");
8210 }
8211 handled = event.ctrlKey || event.metaKey;
8212 break; // -1 week on ctrl or command +up
8213 case 39: if (event.ctrlKey || event.metaKey) {
8214 $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
8215 }
8216 handled = event.ctrlKey || event.metaKey;
8217 // +1 day on ctrl or command +right
8218 if (event.originalEvent.altKey) {
8219 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
8220 +$.datepicker._get(inst, "stepBigMonths") :
8221 +$.datepicker._get(inst, "stepMonths")), "M");
8222 }
8223 // next month/year on alt +right
8224 break;
8225 case 40: if (event.ctrlKey || event.metaKey) {
8226 $.datepicker._adjustDate(event.target, +7, "D");
8227 }
8228 handled = event.ctrlKey || event.metaKey;
8229 break; // +1 week on ctrl or command +down
8230 default: handled = false;
8231 }
8232 } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
8233 $.datepicker._showDatepicker(this);
8234 } else {
8235 handled = false;
8236 }
8237
8238 if (handled) {
8239 event.preventDefault();
8240 event.stopPropagation();
8241 }
8242 },
8243
8244 /* Filter entered characters - based on date format. */
8245 _doKeyPress: function(event) {
8246 var chars, chr,
8247 inst = $.datepicker._getInst(event.target);
8248
8249 if ($.datepicker._get(inst, "constrainInput")) {
8250 chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
8251 chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
8252 return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
8253 }
8254 },
8255
8256 /* Synchronise manual entry and field/alternate field. */
8257 _doKeyUp: function(event) {
8258 var date,
8259 inst = $.datepicker._getInst(event.target);
8260
8261 if (inst.input.val() !== inst.lastVal) {
8262 try {
8263 date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
8264 (inst.input ? inst.input.val() : null),
8265 $.datepicker._getFormatConfig(inst));
8266
8267 if (date) { // only if valid
8268 $.datepicker._setDateFromField(inst);
8269 $.datepicker._updateAlternate(inst);
8270 $.datepicker._updateDatepicker(inst);
8271 }
8272 }
8273 catch (err) {
8274 }
8275 }
8276 return true;
8277 },
8278
8279 /* Pop-up the date picker for a given input field.
8280 * If false returned from beforeShow event handler do not show.
8281 * @param input element - the input field attached to the date picker or
8282 * event - if triggered by focus
8283 */
8284 _showDatepicker: function(input) {
8285 input = input.target || input;
8286 if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
8287 input = $("input", input.parentNode)[0];
8288 }
8289
8290 if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
8291 return;
8292 }
8293
8294 var inst, beforeShow, beforeShowSettings, isFixed,
8295 offset, showAnim, duration;
8296
8297 inst = $.datepicker._getInst(input);
8298 if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
8299 $.datepicker._curInst.dpDiv.stop(true, true);
8300 if ( inst && $.datepicker._datepickerShowing ) {
8301 $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
8302 }
8303 }
8304
8305 beforeShow = $.datepicker._get(inst, "beforeShow");
8306 beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
8307 if(beforeShowSettings === false){
8308 return;
8309 }
8310 extendRemove(inst.settings, beforeShowSettings);
8311
8312 inst.lastVal = null;
8313 $.datepicker._lastInput = input;
8314 $.datepicker._setDateFromField(inst);
8315
8316 if ($.datepicker._inDialog) { // hide cursor
8317 input.value = "";
8318 }
8319 if (!$.datepicker._pos) { // position below input
8320 $.datepicker._pos = $.datepicker._findPos(input);
8321 $.datepicker._pos[1] += input.offsetHeight; // add the height
8322 }
8323
8324 isFixed = false;
8325 $(input).parents().each(function() {
8326 isFixed |= $(this).css("position") === "fixed";
8327 return !isFixed;
8328 });
8329
8330 offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
8331 $.datepicker._pos = null;
8332 //to avoid flashes on Firefox
8333 inst.dpDiv.empty();
8334 // determine sizing offscreen
8335 inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
8336 $.datepicker._updateDatepicker(inst);
8337 // fix width for dynamic number of date pickers
8338 // and adjust position before showing
8339 offset = $.datepicker._checkOffset(inst, offset, isFixed);
8340 inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
8341 "static" : (isFixed ? "fixed" : "absolute")), display: "none",
8342 left: offset.left + "px", top: offset.top + "px"});
8343
8344 if (!inst.inline) {
8345 showAnim = $.datepicker._get(inst, "showAnim");
8346 duration = $.datepicker._get(inst, "duration");
8347 inst.dpDiv.zIndex($(input).zIndex()+1);
8348 $.datepicker._datepickerShowing = true;
8349
8350 if ( $.effects && $.effects.effect[ showAnim ] ) {
8351 inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
8352 } else {
8353 inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
8354 }
8355
8356 if ( $.datepicker._shouldFocusInput( inst ) ) {
8357 inst.input.focus();
8358 }
8359
8360 $.datepicker._curInst = inst;
8361 }
8362 },
8363
8364 /* Generate the date picker content. */
8365 _updateDatepicker: function(inst) {
8366 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
8367 instActive = inst; // for delegate hover events
8368 inst.dpDiv.empty().append(this._generateHTML(inst));
8369 this._attachHandlers(inst);
8370 inst.dpDiv.find("." + this._dayOverClass + " a").mouseover();
8371
8372 var origyearshtml,
8373 numMonths = this._getNumberOfMonths(inst),
8374 cols = numMonths[1],
8375 width = 17;
8376
8377 inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
8378 if (cols > 1) {
8379 inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
8380 }
8381 inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
8382 "Class"]("ui-datepicker-multi");
8383 inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
8384 "Class"]("ui-datepicker-rtl");
8385
8386 if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
8387 inst.input.focus();
8388 }
8389
8390 // deffered render of the years select (to avoid flashes on Firefox)
8391 if( inst.yearshtml ){
8392 origyearshtml = inst.yearshtml;
8393 setTimeout(function(){
8394 //assure that inst.yearshtml didn't change.
8395 if( origyearshtml === inst.yearshtml && inst.yearshtml ){
8396 inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
8397 }
8398 origyearshtml = inst.yearshtml = null;
8399 }, 0);
8400 }
8401 },
8402
8403 // #6694 - don't focus the input if it's already focused
8404 // this breaks the change event in IE
8405 // Support: IE and jQuery <1.9
8406 _shouldFocusInput: function( inst ) {
8407 return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
8408 },
8409
8410 /* Check positioning to remain on screen. */
8411 _checkOffset: function(inst, offset, isFixed) {
8412 var dpWidth = inst.dpDiv.outerWidth(),
8413 dpHeight = inst.dpDiv.outerHeight(),
8414 inputWidth = inst.input ? inst.input.outerWidth() : 0,
8415 inputHeight = inst.input ? inst.input.outerHeight() : 0,
8416 viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
8417 viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
8418
8419 offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
8420 offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
8421 offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
8422
8423 // now check if datepicker is showing outside window viewport - move to a better place if so.
8424 offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
8425 Math.abs(offset.left + dpWidth - viewWidth) : 0);
8426 offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
8427 Math.abs(dpHeight + inputHeight) : 0);
8428
8429 return offset;
8430 },
8431
8432 /* Find an object's position on the screen. */
8433 _findPos: function(obj) {
8434 var position,
8435 inst = this._getInst(obj),
8436 isRTL = this._get(inst, "isRTL");
8437
8438 while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
8439 obj = obj[isRTL ? "previousSibling" : "nextSibling"];
8440 }
8441
8442 position = $(obj).offset();
8443 return [position.left, position.top];
8444 },
8445
8446 /* Hide the date picker from view.
8447 * @param input element - the input field attached to the date picker
8448 */
8449 _hideDatepicker: function(input) {
8450 var showAnim, duration, postProcess, onClose,
8451 inst = this._curInst;
8452
8453 if (!inst || (input && inst !== $.data(input, PROP_NAME))) {
8454 return;
8455 }
8456
8457 if (this._datepickerShowing) {
8458 showAnim = this._get(inst, "showAnim");
8459 duration = this._get(inst, "duration");
8460 postProcess = function() {
8461 $.datepicker._tidyDialog(inst);
8462 };
8463
8464 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
8465 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
8466 inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
8467 } else {
8468 inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
8469 (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
8470 }
8471
8472 if (!showAnim) {
8473 postProcess();
8474 }
8475 this._datepickerShowing = false;
8476
8477 onClose = this._get(inst, "onClose");
8478 if (onClose) {
8479 onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
8480 }
8481
8482 this._lastInput = null;
8483 if (this._inDialog) {
8484 this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
8485 if ($.blockUI) {
8486 $.unblockUI();
8487 $("body").append(this.dpDiv);
8488 }
8489 }
8490 this._inDialog = false;
8491 }
8492 },
8493
8494 /* Tidy up after a dialog display. */
8495 _tidyDialog: function(inst) {
8496 inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");
8497 },
8498
8499 /* Close date picker if clicked elsewhere. */
8500 _checkExternalClick: function(event) {
8501 if (!$.datepicker._curInst) {
8502 return;
8503 }
8504
8505 var $target = $(event.target),
8506 inst = $.datepicker._getInst($target[0]);
8507
8508 if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
8509 $target.parents("#" + $.datepicker._mainDivId).length === 0 &&
8510 !$target.hasClass($.datepicker.markerClassName) &&
8511 !$target.closest("." + $.datepicker._triggerClass).length &&
8512 $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
8513 ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
8514 $.datepicker._hideDatepicker();
8515 }
8516 },
8517
8518 /* Adjust one of the date sub-fields. */
8519 _adjustDate: function(id, offset, period) {
8520 var target = $(id),
8521 inst = this._getInst(target[0]);
8522
8523 if (this._isDisabledDatepicker(target[0])) {
8524 return;
8525 }
8526 this._adjustInstDate(inst, offset +
8527 (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
8528 period);
8529 this._updateDatepicker(inst);
8530 },
8531
8532 /* Action for current link. */
8533 _gotoToday: function(id) {
8534 var date,
8535 target = $(id),
8536 inst = this._getInst(target[0]);
8537
8538 if (this._get(inst, "gotoCurrent") && inst.currentDay) {
8539 inst.selectedDay = inst.currentDay;
8540 inst.drawMonth = inst.selectedMonth = inst.currentMonth;
8541 inst.drawYear = inst.selectedYear = inst.currentYear;
8542 } else {
8543 date = new Date();
8544 inst.selectedDay = date.getDate();
8545 inst.drawMonth = inst.selectedMonth = date.getMonth();
8546 inst.drawYear = inst.selectedYear = date.getFullYear();
8547 }
8548 this._notifyChange(inst);
8549 this._adjustDate(target);
8550 },
8551
8552 /* Action for selecting a new month/year. */
8553 _selectMonthYear: function(id, select, period) {
8554 var target = $(id),
8555 inst = this._getInst(target[0]);
8556
8557 inst["selected" + (period === "M" ? "Month" : "Year")] =
8558 inst["draw" + (period === "M" ? "Month" : "Year")] =
8559 parseInt(select.options[select.selectedIndex].value,10);
8560
8561 this._notifyChange(inst);
8562 this._adjustDate(target);
8563 },
8564
8565 /* Action for selecting a day. */
8566 _selectDay: function(id, month, year, td) {
8567 var inst,
8568 target = $(id);
8569
8570 if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
8571 return;
8572 }
8573
8574 inst = this._getInst(target[0]);
8575 inst.selectedDay = inst.currentDay = $("a", td).html();
8576 inst.selectedMonth = inst.currentMonth = month;
8577 inst.selectedYear = inst.currentYear = year;
8578 this._selectDate(id, this._formatDate(inst,
8579 inst.currentDay, inst.currentMonth, inst.currentYear));
8580 },
8581
8582 /* Erase the input field and hide the date picker. */
8583 _clearDate: function(id) {
8584 var target = $(id);
8585 this._selectDate(target, "");
8586 },
8587
8588 /* Update the input field with the selected date. */
8589 _selectDate: function(id, dateStr) {
8590 var onSelect,
8591 target = $(id),
8592 inst = this._getInst(target[0]);
8593
8594 dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
8595 if (inst.input) {
8596 inst.input.val(dateStr);
8597 }
8598 this._updateAlternate(inst);
8599
8600 onSelect = this._get(inst, "onSelect");
8601 if (onSelect) {
8602 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
8603 } else if (inst.input) {
8604 inst.input.trigger("change"); // fire the change event
8605 }
8606
8607 if (inst.inline){
8608 this._updateDatepicker(inst);
8609 } else {
8610 this._hideDatepicker();
8611 this._lastInput = inst.input[0];
8612 if (typeof(inst.input[0]) !== "object") {
8613 inst.input.focus(); // restore focus
8614 }
8615 this._lastInput = null;
8616 }
8617 },
8618
8619 /* Update any alternate field to synchronise with the main field. */
8620 _updateAlternate: function(inst) {
8621 var altFormat, date, dateStr,
8622 altField = this._get(inst, "altField");
8623
8624 if (altField) { // update alternate field too
8625 altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
8626 date = this._getDate(inst);
8627 dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
8628 $(altField).each(function() { $(this).val(dateStr); });
8629 }
8630 },
8631
8632 /* Set as beforeShowDay function to prevent selection of weekends.
8633 * @param date Date - the date to customise
8634 * @return [boolean, string] - is this date selectable?, what is its CSS class?
8635 */
8636 noWeekends: function(date) {
8637 var day = date.getDay();
8638 return [(day > 0 && day < 6), ""];
8639 },
8640
8641 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
8642 * @param date Date - the date to get the week for
8643 * @return number - the number of the week within the year that contains this date
8644 */
8645 iso8601Week: function(date) {
8646 var time,
8647 checkDate = new Date(date.getTime());
8648
8649 // Find Thursday of this week starting on Monday
8650 checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
8651
8652 time = checkDate.getTime();
8653 checkDate.setMonth(0); // Compare with Jan 1
8654 checkDate.setDate(1);
8655 return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
8656 },
8657
8658 /* Parse a string value into a date object.
8659 * See formatDate below for the possible formats.
8660 *
8661 * @param format string - the expected format of the date
8662 * @param value string - the date in the above format
8663 * @param settings Object - attributes include:
8664 * shortYearCutoff number - the cutoff year for determining the century (optional)
8665 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
8666 * dayNames string[7] - names of the days from Sunday (optional)
8667 * monthNamesShort string[12] - abbreviated names of the months (optional)
8668 * monthNames string[12] - names of the months (optional)
8669 * @return Date - the extracted date value or null if value is blank
8670 */
8671 parseDate: function (format, value, settings) {
8672 if (format == null || value == null) {
8673 throw "Invalid arguments";
8674 }
8675
8676 value = (typeof value === "object" ? value.toString() : value + "");
8677 if (value === "") {
8678 return null;
8679 }
8680
8681 var iFormat, dim, extra,
8682 iValue = 0,
8683 shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
8684 shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
8685 new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
8686 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
8687 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
8688 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
8689 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
8690 year = -1,
8691 month = -1,
8692 day = -1,
8693 doy = -1,
8694 literal = false,
8695 date,
8696 // Check whether a format character is doubled
8697 lookAhead = function(match) {
8698 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
8699 if (matches) {
8700 iFormat++;
8701 }
8702 return matches;
8703 },
8704 // Extract a number from the string value
8705 getNumber = function(match) {
8706 var isDoubled = lookAhead(match),
8707 size = (match === "@" ? 14 : (match === "!" ? 20 :
8708 (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
8709 digits = new RegExp("^\\d{1," + size + "}"),
8710 num = value.substring(iValue).match(digits);
8711 if (!num) {
8712 throw "Missing number at position " + iValue;
8713 }
8714 iValue += num[0].length;
8715 return parseInt(num[0], 10);
8716 },
8717 // Extract a name from the string value and convert to an index
8718 getName = function(match, shortNames, longNames) {
8719 var index = -1,
8720 names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
8721 return [ [k, v] ];
8722 }).sort(function (a, b) {
8723 return -(a[1].length - b[1].length);
8724 });
8725
8726 $.each(names, function (i, pair) {
8727 var name = pair[1];
8728 if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
8729 index = pair[0];
8730 iValue += name.length;
8731 return false;
8732 }
8733 });
8734 if (index !== -1) {
8735 return index + 1;
8736 } else {
8737 throw "Unknown name at position " + iValue;
8738 }
8739 },
8740 // Confirm that a literal character matches the string value
8741 checkLiteral = function() {
8742 if (value.charAt(iValue) !== format.charAt(iFormat)) {
8743 throw "Unexpected literal at position " + iValue;
8744 }
8745 iValue++;
8746 };
8747
8748 for (iFormat = 0; iFormat < format.length; iFormat++) {
8749 if (literal) {
8750 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
8751 literal = false;
8752 } else {
8753 checkLiteral();
8754 }
8755 } else {
8756 switch (format.charAt(iFormat)) {
8757 case "d":
8758 day = getNumber("d");
8759 break;
8760 case "D":
8761 getName("D", dayNamesShort, dayNames);
8762 break;
8763 case "o":
8764 doy = getNumber("o");
8765 break;
8766 case "m":
8767 month = getNumber("m");
8768 break;
8769 case "M":
8770 month = getName("M", monthNamesShort, monthNames);
8771 break;
8772 case "y":
8773 year = getNumber("y");
8774 break;
8775 case "@":
8776 date = new Date(getNumber("@"));
8777 year = date.getFullYear();
8778 month = date.getMonth() + 1;
8779 day = date.getDate();
8780 break;
8781 case "!":
8782 date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
8783 year = date.getFullYear();
8784 month = date.getMonth() + 1;
8785 day = date.getDate();
8786 break;
8787 case "'":
8788 if (lookAhead("'")){
8789 checkLiteral();
8790 } else {
8791 literal = true;
8792 }
8793 break;
8794 default:
8795 checkLiteral();
8796 }
8797 }
8798 }
8799
8800 if (iValue < value.length){
8801 extra = value.substr(iValue);
8802 if (!/^\s+/.test(extra)) {
8803 throw "Extra/unparsed characters found in date: " + extra;
8804 }
8805 }
8806
8807 if (year === -1) {
8808 year = new Date().getFullYear();
8809 } else if (year < 100) {
8810 year += new Date().getFullYear() - new Date().getFullYear() % 100 +
8811 (year <= shortYearCutoff ? 0 : -100);
8812 }
8813
8814 if (doy > -1) {
8815 month = 1;
8816 day = doy;
8817 do {
8818 dim = this._getDaysInMonth(year, month - 1);
8819 if (day <= dim) {
8820 break;
8821 }
8822 month++;
8823 day -= dim;
8824 } while (true);
8825 }
8826
8827 date = this._daylightSavingAdjust(new Date(year, month - 1, day));
8828 if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
8829 throw "Invalid date"; // E.g. 31/02/00
8830 }
8831 return date;
8832 },
8833
8834 /* Standard date formats. */
8835 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
8836 COOKIE: "D, dd M yy",
8837 ISO_8601: "yy-mm-dd",
8838 RFC_822: "D, d M y",
8839 RFC_850: "DD, dd-M-y",
8840 RFC_1036: "D, d M y",
8841 RFC_1123: "D, d M yy",
8842 RFC_2822: "D, d M yy",
8843 RSS: "D, d M y", // RFC 822
8844 TICKS: "!",
8845 TIMESTAMP: "@",
8846 W3C: "yy-mm-dd", // ISO 8601
8847
8848 _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
8849 Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
8850
8851 /* Format a date object into a string value.
8852 * The format can be combinations of the following:
8853 * d - day of month (no leading zero)
8854 * dd - day of month (two digit)
8855 * o - day of year (no leading zeros)
8856 * oo - day of year (three digit)
8857 * D - day name short
8858 * DD - day name long
8859 * m - month of year (no leading zero)
8860 * mm - month of year (two digit)
8861 * M - month name short
8862 * MM - month name long
8863 * y - year (two digit)
8864 * yy - year (four digit)
8865 * @ - Unix timestamp (ms since 01/01/1970)
8866 * ! - Windows ticks (100ns since 01/01/0001)
8867 * "..." - literal text
8868 * '' - single quote
8869 *
8870 * @param format string - the desired format of the date
8871 * @param date Date - the date value to format
8872 * @param settings Object - attributes include:
8873 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
8874 * dayNames string[7] - names of the days from Sunday (optional)
8875 * monthNamesShort string[12] - abbreviated names of the months (optional)
8876 * monthNames string[12] - names of the months (optional)
8877 * @return string - the date in the above format
8878 */
8879 formatDate: function (format, date, settings) {
8880 if (!date) {
8881 return "";
8882 }
8883
8884 var iFormat,
8885 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
8886 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
8887 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
8888 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
8889 // Check whether a format character is doubled
8890 lookAhead = function(match) {
8891 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
8892 if (matches) {
8893 iFormat++;
8894 }
8895 return matches;
8896 },
8897 // Format a number, with leading zero if necessary
8898 formatNumber = function(match, value, len) {
8899 var num = "" + value;
8900 if (lookAhead(match)) {
8901 while (num.length < len) {
8902 num = "0" + num;
8903 }
8904 }
8905 return num;
8906 },
8907 // Format a name, short or long as requested
8908 formatName = function(match, value, shortNames, longNames) {
8909 return (lookAhead(match) ? longNames[value] : shortNames[value]);
8910 },
8911 output = "",
8912 literal = false;
8913
8914 if (date) {
8915 for (iFormat = 0; iFormat < format.length; iFormat++) {
8916 if (literal) {
8917 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
8918 literal = false;
8919 } else {
8920 output += format.charAt(iFormat);
8921 }
8922 } else {
8923 switch (format.charAt(iFormat)) {
8924 case "d":
8925 output += formatNumber("d", date.getDate(), 2);
8926 break;
8927 case "D":
8928 output += formatName("D", date.getDay(), dayNamesShort, dayNames);
8929 break;
8930 case "o":
8931 output += formatNumber("o",
8932 Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
8933 break;
8934 case "m":
8935 output += formatNumber("m", date.getMonth() + 1, 2);
8936 break;
8937 case "M":
8938 output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
8939 break;
8940 case "y":
8941 output += (lookAhead("y") ? date.getFullYear() :
8942 (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
8943 break;
8944 case "@":
8945 output += date.getTime();
8946 break;
8947 case "!":
8948 output += date.getTime() * 10000 + this._ticksTo1970;
8949 break;
8950 case "'":
8951 if (lookAhead("'")) {
8952 output += "'";
8953 } else {
8954 literal = true;
8955 }
8956 break;
8957 default:
8958 output += format.charAt(iFormat);
8959 }
8960 }
8961 }
8962 }
8963 return output;
8964 },
8965
8966 /* Extract all possible characters from the date format. */
8967 _possibleChars: function (format) {
8968 var iFormat,
8969 chars = "",
8970 literal = false,
8971 // Check whether a format character is doubled
8972 lookAhead = function(match) {
8973 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
8974 if (matches) {
8975 iFormat++;
8976 }
8977 return matches;
8978 };
8979
8980 for (iFormat = 0; iFormat < format.length; iFormat++) {
8981 if (literal) {
8982 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
8983 literal = false;
8984 } else {
8985 chars += format.charAt(iFormat);
8986 }
8987 } else {
8988 switch (format.charAt(iFormat)) {
8989 case "d": case "m": case "y": case "@":
8990 chars += "0123456789";
8991 break;
8992 case "D": case "M":
8993 return null; // Accept anything
8994 case "'":
8995 if (lookAhead("'")) {
8996 chars += "'";
8997 } else {
8998 literal = true;
8999 }
9000 break;
9001 default:
9002 chars += format.charAt(iFormat);
9003 }
9004 }
9005 }
9006 return chars;
9007 },
9008
9009 /* Get a setting value, defaulting if necessary. */
9010 _get: function(inst, name) {
9011 return inst.settings[name] !== undefined ?
9012 inst.settings[name] : this._defaults[name];
9013 },
9014
9015 /* Parse existing date and initialise date picker. */
9016 _setDateFromField: function(inst, noDefault) {
9017 if (inst.input.val() === inst.lastVal) {
9018 return;
9019 }
9020
9021 var dateFormat = this._get(inst, "dateFormat"),
9022 dates = inst.lastVal = inst.input ? inst.input.val() : null,
9023 defaultDate = this._getDefaultDate(inst),
9024 date = defaultDate,
9025 settings = this._getFormatConfig(inst);
9026
9027 try {
9028 date = this.parseDate(dateFormat, dates, settings) || defaultDate;
9029 } catch (event) {
9030 dates = (noDefault ? "" : dates);
9031 }
9032 inst.selectedDay = date.getDate();
9033 inst.drawMonth = inst.selectedMonth = date.getMonth();
9034 inst.drawYear = inst.selectedYear = date.getFullYear();
9035 inst.currentDay = (dates ? date.getDate() : 0);
9036 inst.currentMonth = (dates ? date.getMonth() : 0);
9037 inst.currentYear = (dates ? date.getFullYear() : 0);
9038 this._adjustInstDate(inst);
9039 },
9040
9041 /* Retrieve the default date shown on opening. */
9042 _getDefaultDate: function(inst) {
9043 return this._restrictMinMax(inst,
9044 this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
9045 },
9046
9047 /* A date may be specified as an exact value or a relative one. */
9048 _determineDate: function(inst, date, defaultDate) {
9049 var offsetNumeric = function(offset) {
9050 var date = new Date();
9051 date.setDate(date.getDate() + offset);
9052 return date;
9053 },
9054 offsetString = function(offset) {
9055 try {
9056 return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
9057 offset, $.datepicker._getFormatConfig(inst));
9058 }
9059 catch (e) {
9060 // Ignore
9061 }
9062
9063 var date = (offset.toLowerCase().match(/^c/) ?
9064 $.datepicker._getDate(inst) : null) || new Date(),
9065 year = date.getFullYear(),
9066 month = date.getMonth(),
9067 day = date.getDate(),
9068 pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
9069 matches = pattern.exec(offset);
9070
9071 while (matches) {
9072 switch (matches[2] || "d") {
9073 case "d" : case "D" :
9074 day += parseInt(matches[1],10); break;
9075 case "w" : case "W" :
9076 day += parseInt(matches[1],10) * 7; break;
9077 case "m" : case "M" :
9078 month += parseInt(matches[1],10);
9079 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
9080 break;
9081 case "y": case "Y" :
9082 year += parseInt(matches[1],10);
9083 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
9084 break;
9085 }
9086 matches = pattern.exec(offset);
9087 }
9088 return new Date(year, month, day);
9089 },
9090 newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
9091 (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
9092
9093 newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
9094 if (newDate) {
9095 newDate.setHours(0);
9096 newDate.setMinutes(0);
9097 newDate.setSeconds(0);
9098 newDate.setMilliseconds(0);
9099 }
9100 return this._daylightSavingAdjust(newDate);
9101 },
9102
9103 /* Handle switch to/from daylight saving.
9104 * Hours may be non-zero on daylight saving cut-over:
9105 * > 12 when midnight changeover, but then cannot generate
9106 * midnight datetime, so jump to 1AM, otherwise reset.
9107 * @param date (Date) the date to check
9108 * @return (Date) the corrected date
9109 */
9110 _daylightSavingAdjust: function(date) {
9111 if (!date) {
9112 return null;
9113 }
9114 date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
9115 return date;
9116 },
9117
9118 /* Set the date(s) directly. */
9119 _setDate: function(inst, date, noChange) {
9120 var clear = !date,
9121 origMonth = inst.selectedMonth,
9122 origYear = inst.selectedYear,
9123 newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
9124
9125 inst.selectedDay = inst.currentDay = newDate.getDate();
9126 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
9127 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
9128 if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
9129 this._notifyChange(inst);
9130 }
9131 this._adjustInstDate(inst);
9132 if (inst.input) {
9133 inst.input.val(clear ? "" : this._formatDate(inst));
9134 }
9135 },
9136
9137 /* Retrieve the date(s) directly. */
9138 _getDate: function(inst) {
9139 var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
9140 this._daylightSavingAdjust(new Date(
9141 inst.currentYear, inst.currentMonth, inst.currentDay)));
9142 return startDate;
9143 },
9144
9145 /* Attach the onxxx handlers. These are declared statically so
9146 * they work with static code transformers like Caja.
9147 */
9148 _attachHandlers: function(inst) {
9149 var stepMonths = this._get(inst, "stepMonths"),
9150 id = "#" + inst.id.replace( /\\\\/g, "\\" );
9151 inst.dpDiv.find("[data-handler]").map(function () {
9152 var handler = {
9153 prev: function () {
9154 $.datepicker._adjustDate(id, -stepMonths, "M");
9155 },
9156 next: function () {
9157 $.datepicker._adjustDate(id, +stepMonths, "M");
9158 },
9159 hide: function () {
9160 $.datepicker._hideDatepicker();
9161 },
9162 today: function () {
9163 $.datepicker._gotoToday(id);
9164 },
9165 selectDay: function () {
9166 $.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
9167 return false;
9168 },
9169 selectMonth: function () {
9170 $.datepicker._selectMonthYear(id, this, "M");
9171 return false;
9172 },
9173 selectYear: function () {
9174 $.datepicker._selectMonthYear(id, this, "Y");
9175 return false;
9176 }
9177 };
9178 $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
9179 });
9180 },
9181
9182 /* Generate the HTML for the current state of the date picker. */
9183 _generateHTML: function(inst) {
9184 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
9185 controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
9186 monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
9187 selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
9188 cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
9189 printDate, dRow, tbody, daySettings, otherMonth, unselectable,
9190 tempDate = new Date(),
9191 today = this._daylightSavingAdjust(
9192 new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
9193 isRTL = this._get(inst, "isRTL"),
9194 showButtonPanel = this._get(inst, "showButtonPanel"),
9195 hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
9196 navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
9197 numMonths = this._getNumberOfMonths(inst),
9198 showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
9199 stepMonths = this._get(inst, "stepMonths"),
9200 isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
9201 currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
9202 new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
9203 minDate = this._getMinMaxDate(inst, "min"),
9204 maxDate = this._getMinMaxDate(inst, "max"),
9205 drawMonth = inst.drawMonth - showCurrentAtPos,
9206 drawYear = inst.drawYear;
9207
9208 if (drawMonth < 0) {
9209 drawMonth += 12;
9210 drawYear--;
9211 }
9212 if (maxDate) {
9213 maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
9214 maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
9215 maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
9216 while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
9217 drawMonth--;
9218 if (drawMonth < 0) {
9219 drawMonth = 11;
9220 drawYear--;
9221 }
9222 }
9223 }
9224 inst.drawMonth = drawMonth;
9225 inst.drawYear = drawYear;
9226
9227 prevText = this._get(inst, "prevText");
9228 prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
9229 this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
9230 this._getFormatConfig(inst)));
9231
9232 prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
9233 "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
9234 " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
9235 (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>"));
9236
9237 nextText = this._get(inst, "nextText");
9238 nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
9239 this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
9240 this._getFormatConfig(inst)));
9241
9242 next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
9243 "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
9244 " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
9245 (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>"));
9246
9247 currentText = this._get(inst, "currentText");
9248 gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
9249 currentText = (!navigationAsDateFormat ? currentText :
9250 this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
9251
9252 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'>" +
9253 this._get(inst, "closeText") + "</button>" : "");
9254
9255 buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
9256 (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'" +
9257 ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";
9258
9259 firstDay = parseInt(this._get(inst, "firstDay"),10);
9260 firstDay = (isNaN(firstDay) ? 0 : firstDay);
9261
9262 showWeek = this._get(inst, "showWeek");
9263 dayNames = this._get(inst, "dayNames");
9264 dayNamesMin = this._get(inst, "dayNamesMin");
9265 monthNames = this._get(inst, "monthNames");
9266 monthNamesShort = this._get(inst, "monthNamesShort");
9267 beforeShowDay = this._get(inst, "beforeShowDay");
9268 showOtherMonths = this._get(inst, "showOtherMonths");
9269 selectOtherMonths = this._get(inst, "selectOtherMonths");
9270 defaultDate = this._getDefaultDate(inst);
9271 html = "";
9272 dow;
9273 for (row = 0; row < numMonths[0]; row++) {
9274 group = "";
9275 this.maxRows = 4;
9276 for (col = 0; col < numMonths[1]; col++) {
9277 selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
9278 cornerClass = " ui-corner-all";
9279 calender = "";
9280 if (isMultiMonth) {
9281 calender += "<div class='ui-datepicker-group";
9282 if (numMonths[1] > 1) {
9283 switch (col) {
9284 case 0: calender += " ui-datepicker-group-first";
9285 cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
9286 case numMonths[1]-1: calender += " ui-datepicker-group-last";
9287 cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
9288 default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
9289 }
9290 }
9291 calender += "'>";
9292 }
9293 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
9294 (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
9295 (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
9296 this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
9297 row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
9298 "</div><table class='ui-datepicker-calendar'><thead>" +
9299 "<tr>";
9300 thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
9301 for (dow = 0; dow < 7; dow++) { // days of the week
9302 day = (dow + firstDay) % 7;
9303 thead += "<th" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
9304 "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
9305 }
9306 calender += thead + "</tr></thead><tbody>";
9307 daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
9308 if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
9309 inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
9310 }
9311 leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
9312 curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
9313 numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
9314 this.maxRows = numRows;
9315 printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
9316 for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
9317 calender += "<tr>";
9318 tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
9319 this._get(inst, "calculateWeek")(printDate) + "</td>");
9320 for (dow = 0; dow < 7; dow++) { // create date picker days
9321 daySettings = (beforeShowDay ?
9322 beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
9323 otherMonth = (printDate.getMonth() !== drawMonth);
9324 unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
9325 (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
9326 tbody += "<td class='" +
9327 ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
9328 (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
9329 ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
9330 (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
9331 // or defaultDate is current printedDate and defaultDate is selectedDate
9332 " " + this._dayOverClass : "") + // highlight selected day
9333 (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days
9334 (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
9335 (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
9336 (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
9337 ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "&#39;") + "'" : "") + // cell title
9338 (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
9339 (otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
9340 (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
9341 (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
9342 (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
9343 (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
9344 "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
9345 printDate.setDate(printDate.getDate() + 1);
9346 printDate = this._daylightSavingAdjust(printDate);
9347 }
9348 calender += tbody + "</tr>";
9349 }
9350 drawMonth++;
9351 if (drawMonth > 11) {
9352 drawMonth = 0;
9353 drawYear++;
9354 }
9355 calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
9356 ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
9357 group += calender;
9358 }
9359 html += group;
9360 }
9361 html += buttonPanel;
9362 inst._keyEvent = false;
9363 return html;
9364 },
9365
9366 /* Generate the month and year header. */
9367 _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
9368 secondary, monthNames, monthNamesShort) {
9369
9370 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
9371 changeMonth = this._get(inst, "changeMonth"),
9372 changeYear = this._get(inst, "changeYear"),
9373 showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
9374 html = "<div class='ui-datepicker-title'>",
9375 monthHtml = "";
9376
9377 // month selection
9378 if (secondary || !changeMonth) {
9379 monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
9380 } else {
9381 inMinYear = (minDate && minDate.getFullYear() === drawYear);
9382 inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
9383 monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
9384 for ( month = 0; month < 12; month++) {
9385 if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
9386 monthHtml += "<option value='" + month + "'" +
9387 (month === drawMonth ? " selected='selected'" : "") +
9388 ">" + monthNamesShort[month] + "</option>";
9389 }
9390 }
9391 monthHtml += "</select>";
9392 }
9393
9394 if (!showMonthAfterYear) {
9395 html += monthHtml + (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "");
9396 }
9397
9398 // year selection
9399 if ( !inst.yearshtml ) {
9400 inst.yearshtml = "";
9401 if (secondary || !changeYear) {
9402 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
9403 } else {
9404 // determine range of years to display
9405 years = this._get(inst, "yearRange").split(":");
9406 thisYear = new Date().getFullYear();
9407 determineYear = function(value) {
9408 var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
9409 (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
9410 parseInt(value, 10)));
9411 return (isNaN(year) ? thisYear : year);
9412 };
9413 year = determineYear(years[0]);
9414 endYear = Math.max(year, determineYear(years[1] || ""));
9415 year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
9416 endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
9417 inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
9418 for (; year <= endYear; year++) {
9419 inst.yearshtml += "<option value='" + year + "'" +
9420 (year === drawYear ? " selected='selected'" : "") +
9421 ">" + year + "</option>";
9422 }
9423 inst.yearshtml += "</select>";
9424
9425 html += inst.yearshtml;
9426 inst.yearshtml = null;
9427 }
9428 }
9429
9430 html += this._get(inst, "yearSuffix");
9431 if (showMonthAfterYear) {
9432 html += (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "") + monthHtml;
9433 }
9434 html += "</div>"; // Close datepicker_header
9435 return html;
9436 },
9437
9438 /* Adjust one of the date sub-fields. */
9439 _adjustInstDate: function(inst, offset, period) {
9440 var year = inst.drawYear + (period === "Y" ? offset : 0),
9441 month = inst.drawMonth + (period === "M" ? offset : 0),
9442 day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
9443 date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));
9444
9445 inst.selectedDay = date.getDate();
9446 inst.drawMonth = inst.selectedMonth = date.getMonth();
9447 inst.drawYear = inst.selectedYear = date.getFullYear();
9448 if (period === "M" || period === "Y") {
9449 this._notifyChange(inst);
9450 }
9451 },
9452
9453 /* Ensure a date is within any min/max bounds. */
9454 _restrictMinMax: function(inst, date) {
9455 var minDate = this._getMinMaxDate(inst, "min"),
9456 maxDate = this._getMinMaxDate(inst, "max"),
9457 newDate = (minDate && date < minDate ? minDate : date);
9458 return (maxDate && newDate > maxDate ? maxDate : newDate);
9459 },
9460
9461 /* Notify change of month/year. */
9462 _notifyChange: function(inst) {
9463 var onChange = this._get(inst, "onChangeMonthYear");
9464 if (onChange) {
9465 onChange.apply((inst.input ? inst.input[0] : null),
9466 [inst.selectedYear, inst.selectedMonth + 1, inst]);
9467 }
9468 },
9469
9470 /* Determine the number of months to show. */
9471 _getNumberOfMonths: function(inst) {
9472 var numMonths = this._get(inst, "numberOfMonths");
9473 return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
9474 },
9475
9476 /* Determine the current maximum date - ensure no time components are set. */
9477 _getMinMaxDate: function(inst, minMax) {
9478 return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
9479 },
9480
9481 /* Find the number of days in a given month. */
9482 _getDaysInMonth: function(year, month) {
9483 return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
9484 },
9485
9486 /* Find the day of the week of the first of a month. */
9487 _getFirstDayOfMonth: function(year, month) {
9488 return new Date(year, month, 1).getDay();
9489 },
9490
9491 /* Determines if we should allow a "next/prev" month display change. */
9492 _canAdjustMonth: function(inst, offset, curYear, curMonth) {
9493 var numMonths = this._getNumberOfMonths(inst),
9494 date = this._daylightSavingAdjust(new Date(curYear,
9495 curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
9496
9497 if (offset < 0) {
9498 date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
9499 }
9500 return this._isInRange(inst, date);
9501 },
9502
9503 /* Is the given date in the accepted range? */
9504 _isInRange: function(inst, date) {
9505 var yearSplit, currentYear,
9506 minDate = this._getMinMaxDate(inst, "min"),
9507 maxDate = this._getMinMaxDate(inst, "max"),
9508 minYear = null,
9509 maxYear = null,
9510 years = this._get(inst, "yearRange");
9511 if (years){
9512 yearSplit = years.split(":");
9513 currentYear = new Date().getFullYear();
9514 minYear = parseInt(yearSplit[0], 10);
9515 maxYear = parseInt(yearSplit[1], 10);
9516 if ( yearSplit[0].match(/[+\-].*/) ) {
9517 minYear += currentYear;
9518 }
9519 if ( yearSplit[1].match(/[+\-].*/) ) {
9520 maxYear += currentYear;
9521 }
9522 }
9523
9524 return ((!minDate || date.getTime() >= minDate.getTime()) &&
9525 (!maxDate || date.getTime() <= maxDate.getTime()) &&
9526 (!minYear || date.getFullYear() >= minYear) &&
9527 (!maxYear || date.getFullYear() <= maxYear));
9528 },
9529
9530 /* Provide the configuration settings for formatting/parsing. */
9531 _getFormatConfig: function(inst) {
9532 var shortYearCutoff = this._get(inst, "shortYearCutoff");
9533 shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
9534 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
9535 return {shortYearCutoff: shortYearCutoff,
9536 dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
9537 monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
9538 },
9539
9540 /* Format the given date for display. */
9541 _formatDate: function(inst, day, month, year) {
9542 if (!day) {
9543 inst.currentDay = inst.selectedDay;
9544 inst.currentMonth = inst.selectedMonth;
9545 inst.currentYear = inst.selectedYear;
9546 }
9547 var date = (day ? (typeof day === "object" ? day :
9548 this._daylightSavingAdjust(new Date(year, month, day))) :
9549 this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
9550 return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
9551 }
9552 });
9553
9554 /*
9555 * Bind hover events for datepicker elements.
9556 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
9557 * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
9558 */
9559 function bindHover(dpDiv) {
9560 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
9561 return dpDiv.delegate(selector, "mouseout", function() {
9562 $(this).removeClass("ui-state-hover");
9563 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
9564 $(this).removeClass("ui-datepicker-prev-hover");
9565 }
9566 if (this.className.indexOf("ui-datepicker-next") !== -1) {
9567 $(this).removeClass("ui-datepicker-next-hover");
9568 }
9569 })
9570 .delegate(selector, "mouseover", function(){
9571 if (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) {
9572 $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
9573 $(this).addClass("ui-state-hover");
9574 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
9575 $(this).addClass("ui-datepicker-prev-hover");
9576 }
9577 if (this.className.indexOf("ui-datepicker-next") !== -1) {
9578 $(this).addClass("ui-datepicker-next-hover");
9579 }
9580 }
9581 });
9582 }
9583
9584 /* jQuery extend now ignores nulls! */
9585 function extendRemove(target, props) {
9586 $.extend(target, props);
9587 for (var name in props) {
9588 if (props[name] == null) {
9589 target[name] = props[name];
9590 }
9591 }
9592 return target;
9593 }
9594
9595 /* Invoke the datepicker functionality.
9596 @param options string - a command, optionally followed by additional parameters or
9597 Object - settings for attaching new datepicker functionality
9598 @return jQuery object */
9599 $.fn.datepicker = function(options){
9600
9601 /* Verify an empty collection wasn't passed - Fixes #6976 */
9602 if ( !this.length ) {
9603 return this;
9604 }
9605
9606 /* Initialise the date picker. */
9607 if (!$.datepicker.initialized) {
9608 $(document).mousedown($.datepicker._checkExternalClick);
9609 $.datepicker.initialized = true;
9610 }
9611
9612 /* Append datepicker main container to body if not exist. */
9613 if ($("#"+$.datepicker._mainDivId).length === 0) {
9614 $("body").append($.datepicker.dpDiv);
9615 }
9616
9617 var otherArgs = Array.prototype.slice.call(arguments, 1);
9618 if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
9619 return $.datepicker["_" + options + "Datepicker"].
9620 apply($.datepicker, [this[0]].concat(otherArgs));
9621 }
9622 if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
9623 return $.datepicker["_" + options + "Datepicker"].
9624 apply($.datepicker, [this[0]].concat(otherArgs));
9625 }
9626 return this.each(function() {
9627 typeof options === "string" ?
9628 $.datepicker["_" + options + "Datepicker"].
9629 apply($.datepicker, [this].concat(otherArgs)) :
9630 $.datepicker._attachDatepicker(this, options);
9631 });
9632 };
9633
9634 $.datepicker = new Datepicker(); // singleton instance
9635 $.datepicker.initialized = false;
9636 $.datepicker.uuid = new Date().getTime();
9637 $.datepicker.version = "1.10.4";
9638
9639 })(jQuery);
9640
9641 (function( $, undefined ) {
9642
9643 var sizeRelatedOptions = {
9644 buttons: true,
9645 height: true,
9646 maxHeight: true,
9647 maxWidth: true,
9648 minHeight: true,
9649 minWidth: true,
9650 width: true
9651 },
9652 resizableRelatedOptions = {
9653 maxHeight: true,
9654 maxWidth: true,
9655 minHeight: true,
9656 minWidth: true
9657 };
9658
9659 $.widget( "ui.dialog", {
9660 version: "1.10.4",
9661 options: {
9662 appendTo: "body",
9663 autoOpen: true,
9664 buttons: [],
9665 closeOnEscape: true,
9666 closeText: "close",
9667 dialogClass: "",
9668 draggable: true,
9669 hide: null,
9670 height: "auto",
9671 maxHeight: null,
9672 maxWidth: null,
9673 minHeight: 150,
9674 minWidth: 150,
9675 modal: false,
9676 position: {
9677 my: "center",
9678 at: "center",
9679 of: window,
9680 collision: "fit",
9681 // Ensure the titlebar is always visible
9682 using: function( pos ) {
9683 var topOffset = $( this ).css( pos ).offset().top;
9684 if ( topOffset < 0 ) {
9685 $( this ).css( "top", pos.top - topOffset );
9686 }
9687 }
9688 },
9689 resizable: true,
9690 show: null,
9691 title: null,
9692 width: 300,
9693
9694 // callbacks
9695 beforeClose: null,
9696 close: null,
9697 drag: null,
9698 dragStart: null,
9699 dragStop: null,
9700 focus: null,
9701 open: null,
9702 resize: null,
9703 resizeStart: null,
9704 resizeStop: null
9705 },
9706
9707 _create: function() {
9708 this.originalCss = {
9709 display: this.element[0].style.display,
9710 width: this.element[0].style.width,
9711 minHeight: this.element[0].style.minHeight,
9712 maxHeight: this.element[0].style.maxHeight,
9713 height: this.element[0].style.height
9714 };
9715 this.originalPosition = {
9716 parent: this.element.parent(),
9717 index: this.element.parent().children().index( this.element )
9718 };
9719 this.originalTitle = this.element.attr("title");
9720 this.options.title = this.options.title || this.originalTitle;
9721
9722 this._createWrapper();
9723
9724 this.element
9725 .show()
9726 .removeAttr("title")
9727 .addClass("ui-dialog-content ui-widget-content")
9728 .appendTo( this.uiDialog );
9729
9730 this._createTitlebar();
9731 this._createButtonPane();
9732
9733 if ( this.options.draggable && $.fn.draggable ) {
9734 this._makeDraggable();
9735 }
9736 if ( this.options.resizable && $.fn.resizable ) {
9737 this._makeResizable();
9738 }
9739
9740 this._isOpen = false;
9741 },
9742
9743 _init: function() {
9744 if ( this.options.autoOpen ) {
9745 this.open();
9746 }
9747 },
9748
9749 _appendTo: function() {
9750 var element = this.options.appendTo;
9751 if ( element && (element.jquery || element.nodeType) ) {
9752 return $( element );
9753 }
9754 return this.document.find( element || "body" ).eq( 0 );
9755 },
9756
9757 _destroy: function() {
9758 var next,
9759 originalPosition = this.originalPosition;
9760
9761 this._destroyOverlay();
9762
9763 this.element
9764 .removeUniqueId()
9765 .removeClass("ui-dialog-content ui-widget-content")
9766 .css( this.originalCss )
9767 // Without detaching first, the following becomes really slow
9768 .detach();
9769
9770 this.uiDialog.stop( true, true ).remove();
9771
9772 if ( this.originalTitle ) {
9773 this.element.attr( "title", this.originalTitle );
9774 }
9775
9776 next = originalPosition.parent.children().eq( originalPosition.index );
9777 // Don't try to place the dialog next to itself (#8613)
9778 if ( next.length && next[0] !== this.element[0] ) {
9779 next.before( this.element );
9780 } else {
9781 originalPosition.parent.append( this.element );
9782 }
9783 },
9784
9785 widget: function() {
9786 return this.uiDialog;
9787 },
9788
9789 disable: $.noop,
9790 enable: $.noop,
9791
9792 close: function( event ) {
9793 var activeElement,
9794 that = this;
9795
9796 if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
9797 return;
9798 }
9799
9800 this._isOpen = false;
9801 this._destroyOverlay();
9802
9803 if ( !this.opener.filter(":focusable").focus().length ) {
9804
9805 // support: IE9
9806 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
9807 try {
9808 activeElement = this.document[ 0 ].activeElement;
9809
9810 // Support: IE9, IE10
9811 // If the <body> is blurred, IE will switch windows, see #4520
9812 if ( activeElement && activeElement.nodeName.toLowerCase() !== "body" ) {
9813
9814 // Hiding a focused element doesn't trigger blur in WebKit
9815 // so in case we have nothing to focus on, explicitly blur the active element
9816 // https://bugs.webkit.org/show_bug.cgi?id=47182
9817 $( activeElement ).blur();
9818 }
9819 } catch ( error ) {}
9820 }
9821
9822 this._hide( this.uiDialog, this.options.hide, function() {
9823 that._trigger( "close", event );
9824 });
9825 },
9826
9827 isOpen: function() {
9828 return this._isOpen;
9829 },
9830
9831 moveToTop: function() {
9832 this._moveToTop();
9833 },
9834
9835 _moveToTop: function( event, silent ) {
9836 var moved = !!this.uiDialog.nextAll(":visible").insertBefore( this.uiDialog ).length;
9837 if ( moved && !silent ) {
9838 this._trigger( "focus", event );
9839 }
9840 return moved;
9841 },
9842
9843 open: function() {
9844 var that = this;
9845 if ( this._isOpen ) {
9846 if ( this._moveToTop() ) {
9847 this._focusTabbable();
9848 }
9849 return;
9850 }
9851
9852 this._isOpen = true;
9853 this.opener = $( this.document[0].activeElement );
9854
9855 this._size();
9856 this._position();
9857 this._createOverlay();
9858 this._moveToTop( null, true );
9859 this._show( this.uiDialog, this.options.show, function() {
9860 that._focusTabbable();
9861 that._trigger("focus");
9862 });
9863
9864 this._trigger("open");
9865 },
9866
9867 _focusTabbable: function() {
9868 // Set focus to the first match:
9869 // 1. First element inside the dialog matching [autofocus]
9870 // 2. Tabbable element inside the content element
9871 // 3. Tabbable element inside the buttonpane
9872 // 4. The close button
9873 // 5. The dialog itself
9874 var hasFocus = this.element.find("[autofocus]");
9875 if ( !hasFocus.length ) {
9876 hasFocus = this.element.find(":tabbable");
9877 }
9878 if ( !hasFocus.length ) {
9879 hasFocus = this.uiDialogButtonPane.find(":tabbable");
9880 }
9881 if ( !hasFocus.length ) {
9882 hasFocus = this.uiDialogTitlebarClose.filter(":tabbable");
9883 }
9884 if ( !hasFocus.length ) {
9885 hasFocus = this.uiDialog;
9886 }
9887 hasFocus.eq( 0 ).focus();
9888 },
9889
9890 _keepFocus: function( event ) {
9891 function checkFocus() {
9892 var activeElement = this.document[0].activeElement,
9893 isActive = this.uiDialog[0] === activeElement ||
9894 $.contains( this.uiDialog[0], activeElement );
9895 if ( !isActive ) {
9896 this._focusTabbable();
9897 }
9898 }
9899 event.preventDefault();
9900 checkFocus.call( this );
9901 // support: IE
9902 // IE <= 8 doesn't prevent moving focus even with event.preventDefault()
9903 // so we check again later
9904 this._delay( checkFocus );
9905 },
9906
9907 _createWrapper: function() {
9908 this.uiDialog = $("<div>")
9909 .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " +
9910 this.options.dialogClass )
9911 .hide()
9912 .attr({
9913 // Setting tabIndex makes the div focusable
9914 tabIndex: -1,
9915 role: "dialog"
9916 })
9917 .appendTo( this._appendTo() );
9918
9919 this._on( this.uiDialog, {
9920 keydown: function( event ) {
9921 if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
9922 event.keyCode === $.ui.keyCode.ESCAPE ) {
9923 event.preventDefault();
9924 this.close( event );
9925 return;
9926 }
9927
9928 // prevent tabbing out of dialogs
9929 if ( event.keyCode !== $.ui.keyCode.TAB ) {
9930 return;
9931 }
9932 var tabbables = this.uiDialog.find(":tabbable"),
9933 first = tabbables.filter(":first"),
9934 last = tabbables.filter(":last");
9935
9936 if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) {
9937 first.focus( 1 );
9938 event.preventDefault();
9939 } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) {
9940 last.focus( 1 );
9941 event.preventDefault();
9942 }
9943 },
9944 mousedown: function( event ) {
9945 if ( this._moveToTop( event ) ) {
9946 this._focusTabbable();
9947 }
9948 }
9949 });
9950
9951 // We assume that any existing aria-describedby attribute means
9952 // that the dialog content is marked up properly
9953 // otherwise we brute force the content as the description
9954 if ( !this.element.find("[aria-describedby]").length ) {
9955 this.uiDialog.attr({
9956 "aria-describedby": this.element.uniqueId().attr("id")
9957 });
9958 }
9959 },
9960
9961 _createTitlebar: function() {
9962 var uiDialogTitle;
9963
9964 this.uiDialogTitlebar = $("<div>")
9965 .addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix")
9966 .prependTo( this.uiDialog );
9967 this._on( this.uiDialogTitlebar, {
9968 mousedown: function( event ) {
9969 // Don't prevent click on close button (#8838)
9970 // Focusing a dialog that is partially scrolled out of view
9971 // causes the browser to scroll it into view, preventing the click event
9972 if ( !$( event.target ).closest(".ui-dialog-titlebar-close") ) {
9973 // Dialog isn't getting focus when dragging (#8063)
9974 this.uiDialog.focus();
9975 }
9976 }
9977 });
9978
9979 // support: IE
9980 // Use type="button" to prevent enter keypresses in textboxes from closing the
9981 // dialog in IE (#9312)
9982 this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
9983 .button({
9984 label: this.options.closeText,
9985 icons: {
9986 primary: "ui-icon-closethick"
9987 },
9988 text: false
9989 })
9990 .addClass("ui-dialog-titlebar-close")
9991 .appendTo( this.uiDialogTitlebar );
9992 this._on( this.uiDialogTitlebarClose, {
9993 click: function( event ) {
9994 event.preventDefault();
9995 this.close( event );
9996 }
9997 });
9998
9999 uiDialogTitle = $("<span>")
10000 .uniqueId()
10001 .addClass("ui-dialog-title")
10002 .prependTo( this.uiDialogTitlebar );
10003 this._title( uiDialogTitle );
10004
10005 this.uiDialog.attr({
10006 "aria-labelledby": uiDialogTitle.attr("id")
10007 });
10008 },
10009
10010 _title: function( title ) {
10011 if ( !this.options.title ) {
10012 title.html("&#160;");
10013 }
10014 title.text( this.options.title );
10015 },
10016
10017 _createButtonPane: function() {
10018 this.uiDialogButtonPane = $("<div>")
10019 .addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix");
10020
10021 this.uiButtonSet = $("<div>")
10022 .addClass("ui-dialog-buttonset")
10023 .appendTo( this.uiDialogButtonPane );
10024
10025 this._createButtons();
10026 },
10027
10028 _createButtons: function() {
10029 var that = this,
10030 buttons = this.options.buttons;
10031
10032 // if we already have a button pane, remove it
10033 this.uiDialogButtonPane.remove();
10034 this.uiButtonSet.empty();
10035
10036 if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) {
10037 this.uiDialog.removeClass("ui-dialog-buttons");
10038 return;
10039 }
10040
10041 $.each( buttons, function( name, props ) {
10042 var click, buttonOptions;
10043 props = $.isFunction( props ) ?
10044 { click: props, text: name } :
10045 props;
10046 // Default to a non-submitting button
10047 props = $.extend( { type: "button" }, props );
10048 // Change the context for the click callback to be the main element
10049 click = props.click;
10050 props.click = function() {
10051 click.apply( that.element[0], arguments );
10052 };
10053 buttonOptions = {
10054 icons: props.icons,
10055 text: props.showText
10056 };
10057 delete props.icons;
10058 delete props.showText;
10059 $( "<button></button>", props )
10060 .button( buttonOptions )
10061 .appendTo( that.uiButtonSet );
10062 });
10063 this.uiDialog.addClass("ui-dialog-buttons");
10064 this.uiDialogButtonPane.appendTo( this.uiDialog );
10065 },
10066
10067 _makeDraggable: function() {
10068 var that = this,
10069 options = this.options;
10070
10071 function filteredUi( ui ) {
10072 return {
10073 position: ui.position,
10074 offset: ui.offset
10075 };
10076 }
10077
10078 this.uiDialog.draggable({
10079 cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
10080 handle: ".ui-dialog-titlebar",
10081 containment: "document",
10082 start: function( event, ui ) {
10083 $( this ).addClass("ui-dialog-dragging");
10084 that._blockFrames();
10085 that._trigger( "dragStart", event, filteredUi( ui ) );
10086 },
10087 drag: function( event, ui ) {
10088 that._trigger( "drag", event, filteredUi( ui ) );
10089 },
10090 stop: function( event, ui ) {
10091 options.position = [
10092 ui.position.left - that.document.scrollLeft(),
10093 ui.position.top - that.document.scrollTop()
10094 ];
10095 $( this ).removeClass("ui-dialog-dragging");
10096 that._unblockFrames();
10097 that._trigger( "dragStop", event, filteredUi( ui ) );
10098 }
10099 });
10100 },
10101
10102 _makeResizable: function() {
10103 var that = this,
10104 options = this.options,
10105 handles = options.resizable,
10106 // .ui-resizable has position: relative defined in the stylesheet
10107 // but dialogs have to use absolute or fixed positioning
10108 position = this.uiDialog.css("position"),
10109 resizeHandles = typeof handles === "string" ?
10110 handles :
10111 "n,e,s,w,se,sw,ne,nw";
10112
10113 function filteredUi( ui ) {
10114 return {
10115 originalPosition: ui.originalPosition,
10116 originalSize: ui.originalSize,
10117 position: ui.position,
10118 size: ui.size
10119 };
10120 }
10121
10122 this.uiDialog.resizable({
10123 cancel: ".ui-dialog-content",
10124 containment: "document",
10125 alsoResize: this.element,
10126 maxWidth: options.maxWidth,
10127 maxHeight: options.maxHeight,
10128 minWidth: options.minWidth,
10129 minHeight: this._minHeight(),
10130 handles: resizeHandles,
10131 start: function( event, ui ) {
10132 $( this ).addClass("ui-dialog-resizing");
10133 that._blockFrames();
10134 that._trigger( "resizeStart", event, filteredUi( ui ) );
10135 },
10136 resize: function( event, ui ) {
10137 that._trigger( "resize", event, filteredUi( ui ) );
10138 },
10139 stop: function( event, ui ) {
10140 options.height = $( this ).height();
10141 options.width = $( this ).width();
10142 $( this ).removeClass("ui-dialog-resizing");
10143 that._unblockFrames();
10144 that._trigger( "resizeStop", event, filteredUi( ui ) );
10145 }
10146 })
10147 .css( "position", position );
10148 },
10149
10150 _minHeight: function() {
10151 var options = this.options;
10152
10153 return options.height === "auto" ?
10154 options.minHeight :
10155 Math.min( options.minHeight, options.height );
10156 },
10157
10158 _position: function() {
10159 // Need to show the dialog to get the actual offset in the position plugin
10160 var isVisible = this.uiDialog.is(":visible");
10161 if ( !isVisible ) {
10162 this.uiDialog.show();
10163 }
10164 this.uiDialog.position( this.options.position );
10165 if ( !isVisible ) {
10166 this.uiDialog.hide();
10167 }
10168 },
10169
10170 _setOptions: function( options ) {
10171 var that = this,
10172 resize = false,
10173 resizableOptions = {};
10174
10175 $.each( options, function( key, value ) {
10176 that._setOption( key, value );
10177
10178 if ( key in sizeRelatedOptions ) {
10179 resize = true;
10180 }
10181 if ( key in resizableRelatedOptions ) {
10182 resizableOptions[ key ] = value;
10183 }
10184 });
10185
10186 if ( resize ) {
10187 this._size();
10188 this._position();
10189 }
10190 if ( this.uiDialog.is(":data(ui-resizable)") ) {
10191 this.uiDialog.resizable( "option", resizableOptions );
10192 }
10193 },
10194
10195 _setOption: function( key, value ) {
10196 var isDraggable, isResizable,
10197 uiDialog = this.uiDialog;
10198
10199 if ( key === "dialogClass" ) {
10200 uiDialog
10201 .removeClass( this.options.dialogClass )
10202 .addClass( value );
10203 }
10204
10205 if ( key === "disabled" ) {
10206 return;
10207 }
10208
10209 this._super( key, value );
10210
10211 if ( key === "appendTo" ) {
10212 this.uiDialog.appendTo( this._appendTo() );
10213 }
10214
10215 if ( key === "buttons" ) {
10216 this._createButtons();
10217 }
10218
10219 if ( key === "closeText" ) {
10220 this.uiDialogTitlebarClose.button({
10221 // Ensure that we always pass a string
10222 label: "" + value
10223 });
10224 }
10225
10226 if ( key === "draggable" ) {
10227 isDraggable = uiDialog.is(":data(ui-draggable)");
10228 if ( isDraggable && !value ) {
10229 uiDialog.draggable("destroy");
10230 }
10231
10232 if ( !isDraggable && value ) {
10233 this._makeDraggable();
10234 }
10235 }
10236
10237 if ( key === "position" ) {
10238 this._position();
10239 }
10240
10241 if ( key === "resizable" ) {
10242 // currently resizable, becoming non-resizable
10243 isResizable = uiDialog.is(":data(ui-resizable)");
10244 if ( isResizable && !value ) {
10245 uiDialog.resizable("destroy");
10246 }
10247
10248 // currently resizable, changing handles
10249 if ( isResizable && typeof value === "string" ) {
10250 uiDialog.resizable( "option", "handles", value );
10251 }
10252
10253 // currently non-resizable, becoming resizable
10254 if ( !isResizable && value !== false ) {
10255 this._makeResizable();
10256 }
10257 }
10258
10259 if ( key === "title" ) {
10260 this._title( this.uiDialogTitlebar.find(".ui-dialog-title") );
10261 }
10262 },
10263
10264 _size: function() {
10265 // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
10266 // divs will both have width and height set, so we need to reset them
10267 var nonContentHeight, minContentHeight, maxContentHeight,
10268 options = this.options;
10269
10270 // Reset content sizing
10271 this.element.show().css({
10272 width: "auto",
10273 minHeight: 0,
10274 maxHeight: "none",
10275 height: 0
10276 });
10277
10278 if ( options.minWidth > options.width ) {
10279 options.width = options.minWidth;
10280 }
10281
10282 // reset wrapper sizing
10283 // determine the height of all the non-content elements
10284 nonContentHeight = this.uiDialog.css({
10285 height: "auto",
10286 width: options.width
10287 })
10288 .outerHeight();
10289 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
10290 maxContentHeight = typeof options.maxHeight === "number" ?
10291 Math.max( 0, options.maxHeight - nonContentHeight ) :
10292 "none";
10293
10294 if ( options.height === "auto" ) {
10295 this.element.css({
10296 minHeight: minContentHeight,
10297 maxHeight: maxContentHeight,
10298 height: "auto"
10299 });
10300 } else {
10301 this.element.height( Math.max( 0, options.height - nonContentHeight ) );
10302 }
10303
10304 if (this.uiDialog.is(":data(ui-resizable)") ) {
10305 this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
10306 }
10307 },
10308
10309 _blockFrames: function() {
10310 this.iframeBlocks = this.document.find( "iframe" ).map(function() {
10311 var iframe = $( this );
10312
10313 return $( "<div>" )
10314 .css({
10315 position: "absolute",
10316 width: iframe.outerWidth(),
10317 height: iframe.outerHeight()
10318 })
10319 .appendTo( iframe.parent() )
10320 .offset( iframe.offset() )[0];
10321 });
10322 },
10323
10324 _unblockFrames: function() {
10325 if ( this.iframeBlocks ) {
10326 this.iframeBlocks.remove();
10327 delete this.iframeBlocks;
10328 }
10329 },
10330
10331 _allowInteraction: function( event ) {
10332 if ( $( event.target ).closest(".ui-dialog").length ) {
10333 return true;
10334 }
10335
10336 // TODO: Remove hack when datepicker implements
10337 // the .ui-front logic (#8989)
10338 return !!$( event.target ).closest(".ui-datepicker").length;
10339 },
10340
10341 _createOverlay: function() {
10342 if ( !this.options.modal ) {
10343 return;
10344 }
10345
10346 var that = this,
10347 widgetFullName = this.widgetFullName;
10348 if ( !$.ui.dialog.overlayInstances ) {
10349 // Prevent use of anchors and inputs.
10350 // We use a delay in case the overlay is created from an
10351 // event that we're going to be cancelling. (#2804)
10352 this._delay(function() {
10353 // Handle .dialog().dialog("close") (#4065)
10354 if ( $.ui.dialog.overlayInstances ) {
10355 this.document.bind( "focusin.dialog", function( event ) {
10356 if ( !that._allowInteraction( event ) ) {
10357 event.preventDefault();
10358 $(".ui-dialog:visible:last .ui-dialog-content")
10359 .data( widgetFullName )._focusTabbable();
10360 }
10361 });
10362 }
10363 });
10364 }
10365
10366 this.overlay = $("<div>")
10367 .addClass("ui-widget-overlay ui-front")
10368 .appendTo( this._appendTo() );
10369 this._on( this.overlay, {
10370 mousedown: "_keepFocus"
10371 });
10372 $.ui.dialog.overlayInstances++;
10373 },
10374
10375 _destroyOverlay: function() {
10376 if ( !this.options.modal ) {
10377 return;
10378 }
10379
10380 if ( this.overlay ) {
10381 $.ui.dialog.overlayInstances--;
10382
10383 if ( !$.ui.dialog.overlayInstances ) {
10384 this.document.unbind( "focusin.dialog" );
10385 }
10386 this.overlay.remove();
10387 this.overlay = null;
10388 }
10389 }
10390 });
10391
10392 $.ui.dialog.overlayInstances = 0;
10393
10394 // DEPRECATED
10395 if ( $.uiBackCompat !== false ) {
10396 // position option with array notation
10397 // just override with old implementation
10398 $.widget( "ui.dialog", $.ui.dialog, {
10399 _position: function() {
10400 var position = this.options.position,
10401 myAt = [],
10402 offset = [ 0, 0 ],
10403 isVisible;
10404
10405 if ( position ) {
10406 if ( typeof position === "string" || (typeof position === "object" && "0" in position ) ) {
10407 myAt = position.split ? position.split(" ") : [ position[0], position[1] ];
10408 if ( myAt.length === 1 ) {
10409 myAt[1] = myAt[0];
10410 }
10411
10412 $.each( [ "left", "top" ], function( i, offsetPosition ) {
10413 if ( +myAt[ i ] === myAt[ i ] ) {
10414 offset[ i ] = myAt[ i ];
10415 myAt[ i ] = offsetPosition;
10416 }
10417 });
10418
10419 position = {
10420 my: myAt[0] + (offset[0] < 0 ? offset[0] : "+" + offset[0]) + " " +
10421 myAt[1] + (offset[1] < 0 ? offset[1] : "+" + offset[1]),
10422 at: myAt.join(" ")
10423 };
10424 }
10425
10426 position = $.extend( {}, $.ui.dialog.prototype.options.position, position );
10427 } else {
10428 position = $.ui.dialog.prototype.options.position;
10429 }
10430
10431 // need to show the dialog to get the actual offset in the position plugin
10432 isVisible = this.uiDialog.is(":visible");
10433 if ( !isVisible ) {
10434 this.uiDialog.show();
10435 }
10436 this.uiDialog.position( position );
10437 if ( !isVisible ) {
10438 this.uiDialog.hide();
10439 }
10440 }
10441 });
10442 }
10443
10444 }( jQuery ) );
10445
10446 (function( $, undefined ) {
10447
10448 var rvertical = /up|down|vertical/,
10449 rpositivemotion = /up|left|vertical|horizontal/;
10450
10451 $.effects.effect.blind = function( o, done ) {
10452 // Create element
10453 var el = $( this ),
10454 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10455 mode = $.effects.setMode( el, o.mode || "hide" ),
10456 direction = o.direction || "up",
10457 vertical = rvertical.test( direction ),
10458 ref = vertical ? "height" : "width",
10459 ref2 = vertical ? "top" : "left",
10460 motion = rpositivemotion.test( direction ),
10461 animation = {},
10462 show = mode === "show",
10463 wrapper, distance, margin;
10464
10465 // if already wrapped, the wrapper's properties are my property. #6245
10466 if ( el.parent().is( ".ui-effects-wrapper" ) ) {
10467 $.effects.save( el.parent(), props );
10468 } else {
10469 $.effects.save( el, props );
10470 }
10471 el.show();
10472 wrapper = $.effects.createWrapper( el ).css({
10473 overflow: "hidden"
10474 });
10475
10476 distance = wrapper[ ref ]();
10477 margin = parseFloat( wrapper.css( ref2 ) ) || 0;
10478
10479 animation[ ref ] = show ? distance : 0;
10480 if ( !motion ) {
10481 el
10482 .css( vertical ? "bottom" : "right", 0 )
10483 .css( vertical ? "top" : "left", "auto" )
10484 .css({ position: "absolute" });
10485
10486 animation[ ref2 ] = show ? margin : distance + margin;
10487 }
10488
10489 // start at 0 if we are showing
10490 if ( show ) {
10491 wrapper.css( ref, 0 );
10492 if ( ! motion ) {
10493 wrapper.css( ref2, margin + distance );
10494 }
10495 }
10496
10497 // Animate
10498 wrapper.animate( animation, {
10499 duration: o.duration,
10500 easing: o.easing,
10501 queue: false,
10502 complete: function() {
10503 if ( mode === "hide" ) {
10504 el.hide();
10505 }
10506 $.effects.restore( el, props );
10507 $.effects.removeWrapper( el );
10508 done();
10509 }
10510 });
10511
10512 };
10513
10514 })(jQuery);
10515
10516 (function( $, undefined ) {
10517
10518 $.effects.effect.bounce = function( o, done ) {
10519 var el = $( this ),
10520 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10521
10522 // defaults:
10523 mode = $.effects.setMode( el, o.mode || "effect" ),
10524 hide = mode === "hide",
10525 show = mode === "show",
10526 direction = o.direction || "up",
10527 distance = o.distance,
10528 times = o.times || 5,
10529
10530 // number of internal animations
10531 anims = times * 2 + ( show || hide ? 1 : 0 ),
10532 speed = o.duration / anims,
10533 easing = o.easing,
10534
10535 // utility:
10536 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
10537 motion = ( direction === "up" || direction === "left" ),
10538 i,
10539 upAnim,
10540 downAnim,
10541
10542 // we will need to re-assemble the queue to stack our animations in place
10543 queue = el.queue(),
10544 queuelen = queue.length;
10545
10546 // Avoid touching opacity to prevent clearType and PNG issues in IE
10547 if ( show || hide ) {
10548 props.push( "opacity" );
10549 }
10550
10551 $.effects.save( el, props );
10552 el.show();
10553 $.effects.createWrapper( el ); // Create Wrapper
10554
10555 // default distance for the BIGGEST bounce is the outer Distance / 3
10556 if ( !distance ) {
10557 distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
10558 }
10559
10560 if ( show ) {
10561 downAnim = { opacity: 1 };
10562 downAnim[ ref ] = 0;
10563
10564 // if we are showing, force opacity 0 and set the initial position
10565 // then do the "first" animation
10566 el.css( "opacity", 0 )
10567 .css( ref, motion ? -distance * 2 : distance * 2 )
10568 .animate( downAnim, speed, easing );
10569 }
10570
10571 // start at the smallest distance if we are hiding
10572 if ( hide ) {
10573 distance = distance / Math.pow( 2, times - 1 );
10574 }
10575
10576 downAnim = {};
10577 downAnim[ ref ] = 0;
10578 // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
10579 for ( i = 0; i < times; i++ ) {
10580 upAnim = {};
10581 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
10582
10583 el.animate( upAnim, speed, easing )
10584 .animate( downAnim, speed, easing );
10585
10586 distance = hide ? distance * 2 : distance / 2;
10587 }
10588
10589 // Last Bounce when Hiding
10590 if ( hide ) {
10591 upAnim = { opacity: 0 };
10592 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
10593
10594 el.animate( upAnim, speed, easing );
10595 }
10596
10597 el.queue(function() {
10598 if ( hide ) {
10599 el.hide();
10600 }
10601 $.effects.restore( el, props );
10602 $.effects.removeWrapper( el );
10603 done();
10604 });
10605
10606 // inject all the animations we just queued to be first in line (after "inprogress")
10607 if ( queuelen > 1) {
10608 queue.splice.apply( queue,
10609 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
10610 }
10611 el.dequeue();
10612
10613 };
10614
10615 })(jQuery);
10616
10617 (function( $, undefined ) {
10618
10619 $.effects.effect.clip = function( o, done ) {
10620 // Create element
10621 var el = $( this ),
10622 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10623 mode = $.effects.setMode( el, o.mode || "hide" ),
10624 show = mode === "show",
10625 direction = o.direction || "vertical",
10626 vert = direction === "vertical",
10627 size = vert ? "height" : "width",
10628 position = vert ? "top" : "left",
10629 animation = {},
10630 wrapper, animate, distance;
10631
10632 // Save & Show
10633 $.effects.save( el, props );
10634 el.show();
10635
10636 // Create Wrapper
10637 wrapper = $.effects.createWrapper( el ).css({
10638 overflow: "hidden"
10639 });
10640 animate = ( el[0].tagName === "IMG" ) ? wrapper : el;
10641 distance = animate[ size ]();
10642
10643 // Shift
10644 if ( show ) {
10645 animate.css( size, 0 );
10646 animate.css( position, distance / 2 );
10647 }
10648
10649 // Create Animation Object:
10650 animation[ size ] = show ? distance : 0;
10651 animation[ position ] = show ? 0 : distance / 2;
10652
10653 // Animate
10654 animate.animate( animation, {
10655 queue: false,
10656 duration: o.duration,
10657 easing: o.easing,
10658 complete: function() {
10659 if ( !show ) {
10660 el.hide();
10661 }
10662 $.effects.restore( el, props );
10663 $.effects.removeWrapper( el );
10664 done();
10665 }
10666 });
10667
10668 };
10669
10670 })(jQuery);
10671
10672 (function( $, undefined ) {
10673
10674 $.effects.effect.drop = function( o, done ) {
10675
10676 var el = $( this ),
10677 props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
10678 mode = $.effects.setMode( el, o.mode || "hide" ),
10679 show = mode === "show",
10680 direction = o.direction || "left",
10681 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
10682 motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
10683 animation = {
10684 opacity: show ? 1 : 0
10685 },
10686 distance;
10687
10688 // Adjust
10689 $.effects.save( el, props );
10690 el.show();
10691 $.effects.createWrapper( el );
10692
10693 distance = o.distance || el[ ref === "top" ? "outerHeight": "outerWidth" ]( true ) / 2;
10694
10695 if ( show ) {
10696 el
10697 .css( "opacity", 0 )
10698 .css( ref, motion === "pos" ? -distance : distance );
10699 }
10700
10701 // Animation
10702 animation[ ref ] = ( show ?
10703 ( motion === "pos" ? "+=" : "-=" ) :
10704 ( motion === "pos" ? "-=" : "+=" ) ) +
10705 distance;
10706
10707 // Animate
10708 el.animate( animation, {
10709 queue: false,
10710 duration: o.duration,
10711 easing: o.easing,
10712 complete: function() {
10713 if ( mode === "hide" ) {
10714 el.hide();
10715 }
10716 $.effects.restore( el, props );
10717 $.effects.removeWrapper( el );
10718 done();
10719 }
10720 });
10721 };
10722
10723 })(jQuery);
10724
10725 (function( $, undefined ) {
10726
10727 $.effects.effect.explode = function( o, done ) {
10728
10729 var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3,
10730 cells = rows,
10731 el = $( this ),
10732 mode = $.effects.setMode( el, o.mode || "hide" ),
10733 show = mode === "show",
10734
10735 // show and then visibility:hidden the element before calculating offset
10736 offset = el.show().css( "visibility", "hidden" ).offset(),
10737
10738 // width and height of a piece
10739 width = Math.ceil( el.outerWidth() / cells ),
10740 height = Math.ceil( el.outerHeight() / rows ),
10741 pieces = [],
10742
10743 // loop
10744 i, j, left, top, mx, my;
10745
10746 // children animate complete:
10747 function childComplete() {
10748 pieces.push( this );
10749 if ( pieces.length === rows * cells ) {
10750 animComplete();
10751 }
10752 }
10753
10754 // clone the element for each row and cell.
10755 for( i = 0; i < rows ; i++ ) { // ===>
10756 top = offset.top + i * height;
10757 my = i - ( rows - 1 ) / 2 ;
10758
10759 for( j = 0; j < cells ; j++ ) { // |||
10760 left = offset.left + j * width;
10761 mx = j - ( cells - 1 ) / 2 ;
10762
10763 // Create a clone of the now hidden main element that will be absolute positioned
10764 // within a wrapper div off the -left and -top equal to size of our pieces
10765 el
10766 .clone()
10767 .appendTo( "body" )
10768 .wrap( "<div></div>" )
10769 .css({
10770 position: "absolute",
10771 visibility: "visible",
10772 left: -j * width,
10773 top: -i * height
10774 })
10775
10776 // select the wrapper - make it overflow: hidden and absolute positioned based on
10777 // where the original was located +left and +top equal to the size of pieces
10778 .parent()
10779 .addClass( "ui-effects-explode" )
10780 .css({
10781 position: "absolute",
10782 overflow: "hidden",
10783 width: width,
10784 height: height,
10785 left: left + ( show ? mx * width : 0 ),
10786 top: top + ( show ? my * height : 0 ),
10787 opacity: show ? 0 : 1
10788 }).animate({
10789 left: left + ( show ? 0 : mx * width ),
10790 top: top + ( show ? 0 : my * height ),
10791 opacity: show ? 1 : 0
10792 }, o.duration || 500, o.easing, childComplete );
10793 }
10794 }
10795
10796 function animComplete() {
10797 el.css({
10798 visibility: "visible"
10799 });
10800 $( pieces ).remove();
10801 if ( !show ) {
10802 el.hide();
10803 }
10804 done();
10805 }
10806 };
10807
10808 })(jQuery);
10809
10810 (function( $, undefined ) {
10811
10812 $.effects.effect.fade = function( o, done ) {
10813 var el = $( this ),
10814 mode = $.effects.setMode( el, o.mode || "toggle" );
10815
10816 el.animate({
10817 opacity: mode
10818 }, {
10819 queue: false,
10820 duration: o.duration,
10821 easing: o.easing,
10822 complete: done
10823 });
10824 };
10825
10826 })( jQuery );
10827
10828 (function( $, undefined ) {
10829
10830 $.effects.effect.fold = function( o, done ) {
10831
10832 // Create element
10833 var el = $( this ),
10834 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10835 mode = $.effects.setMode( el, o.mode || "hide" ),
10836 show = mode === "show",
10837 hide = mode === "hide",
10838 size = o.size || 15,
10839 percent = /([0-9]+)%/.exec( size ),
10840 horizFirst = !!o.horizFirst,
10841 widthFirst = show !== horizFirst,
10842 ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ],
10843 duration = o.duration / 2,
10844 wrapper, distance,
10845 animation1 = {},
10846 animation2 = {};
10847
10848 $.effects.save( el, props );
10849 el.show();
10850
10851 // Create Wrapper
10852 wrapper = $.effects.createWrapper( el ).css({
10853 overflow: "hidden"
10854 });
10855 distance = widthFirst ?
10856 [ wrapper.width(), wrapper.height() ] :
10857 [ wrapper.height(), wrapper.width() ];
10858
10859 if ( percent ) {
10860 size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
10861 }
10862 if ( show ) {
10863 wrapper.css( horizFirst ? {
10864 height: 0,
10865 width: size
10866 } : {
10867 height: size,
10868 width: 0
10869 });
10870 }
10871
10872 // Animation
10873 animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size;
10874 animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0;
10875
10876 // Animate
10877 wrapper
10878 .animate( animation1, duration, o.easing )
10879 .animate( animation2, duration, o.easing, function() {
10880 if ( hide ) {
10881 el.hide();
10882 }
10883 $.effects.restore( el, props );
10884 $.effects.removeWrapper( el );
10885 done();
10886 });
10887
10888 };
10889
10890 })(jQuery);
10891
10892 (function( $, undefined ) {
10893
10894 $.effects.effect.highlight = function( o, done ) {
10895 var elem = $( this ),
10896 props = [ "backgroundImage", "backgroundColor", "opacity" ],
10897 mode = $.effects.setMode( elem, o.mode || "show" ),
10898 animation = {
10899 backgroundColor: elem.css( "backgroundColor" )
10900 };
10901
10902 if (mode === "hide") {
10903 animation.opacity = 0;
10904 }
10905
10906 $.effects.save( elem, props );
10907
10908 elem
10909 .show()
10910 .css({
10911 backgroundImage: "none",
10912 backgroundColor: o.color || "#ffff99"
10913 })
10914 .animate( animation, {
10915 queue: false,
10916 duration: o.duration,
10917 easing: o.easing,
10918 complete: function() {
10919 if ( mode === "hide" ) {
10920 elem.hide();
10921 }
10922 $.effects.restore( elem, props );
10923 done();
10924 }
10925 });
10926 };
10927
10928 })(jQuery);
10929
10930 (function( $, undefined ) {
10931
10932 $.effects.effect.pulsate = function( o, done ) {
10933 var elem = $( this ),
10934 mode = $.effects.setMode( elem, o.mode || "show" ),
10935 show = mode === "show",
10936 hide = mode === "hide",
10937 showhide = ( show || mode === "hide" ),
10938
10939 // showing or hiding leaves of the "last" animation
10940 anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
10941 duration = o.duration / anims,
10942 animateTo = 0,
10943 queue = elem.queue(),
10944 queuelen = queue.length,
10945 i;
10946
10947 if ( show || !elem.is(":visible")) {
10948 elem.css( "opacity", 0 ).show();
10949 animateTo = 1;
10950 }
10951
10952 // anims - 1 opacity "toggles"
10953 for ( i = 1; i < anims; i++ ) {
10954 elem.animate({
10955 opacity: animateTo
10956 }, duration, o.easing );
10957 animateTo = 1 - animateTo;
10958 }
10959
10960 elem.animate({
10961 opacity: animateTo
10962 }, duration, o.easing);
10963
10964 elem.queue(function() {
10965 if ( hide ) {
10966 elem.hide();
10967 }
10968 done();
10969 });
10970
10971 // We just queued up "anims" animations, we need to put them next in the queue
10972 if ( queuelen > 1 ) {
10973 queue.splice.apply( queue,
10974 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
10975 }
10976 elem.dequeue();
10977 };
10978
10979 })(jQuery);
10980
10981 (function( $, undefined ) {
10982
10983 $.effects.effect.puff = function( o, done ) {
10984 var elem = $( this ),
10985 mode = $.effects.setMode( elem, o.mode || "hide" ),
10986 hide = mode === "hide",
10987 percent = parseInt( o.percent, 10 ) || 150,
10988 factor = percent / 100,
10989 original = {
10990 height: elem.height(),
10991 width: elem.width(),
10992 outerHeight: elem.outerHeight(),
10993 outerWidth: elem.outerWidth()
10994 };
10995
10996 $.extend( o, {
10997 effect: "scale",
10998 queue: false,
10999 fade: true,
11000 mode: mode,
11001 complete: done,
11002 percent: hide ? percent : 100,
11003 from: hide ?
11004 original :
11005 {
11006 height: original.height * factor,
11007 width: original.width * factor,
11008 outerHeight: original.outerHeight * factor,
11009 outerWidth: original.outerWidth * factor
11010 }
11011 });
11012
11013 elem.effect( o );
11014 };
11015
11016 $.effects.effect.scale = function( o, done ) {
11017
11018 // Create element
11019 var el = $( this ),
11020 options = $.extend( true, {}, o ),
11021 mode = $.effects.setMode( el, o.mode || "effect" ),
11022 percent = parseInt( o.percent, 10 ) ||
11023 ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ),
11024 direction = o.direction || "both",
11025 origin = o.origin,
11026 original = {
11027 height: el.height(),
11028 width: el.width(),
11029 outerHeight: el.outerHeight(),
11030 outerWidth: el.outerWidth()
11031 },
11032 factor = {
11033 y: direction !== "horizontal" ? (percent / 100) : 1,
11034 x: direction !== "vertical" ? (percent / 100) : 1
11035 };
11036
11037 // We are going to pass this effect to the size effect:
11038 options.effect = "size";
11039 options.queue = false;
11040 options.complete = done;
11041
11042 // Set default origin and restore for show/hide
11043 if ( mode !== "effect" ) {
11044 options.origin = origin || ["middle","center"];
11045 options.restore = true;
11046 }
11047
11048 options.from = o.from || ( mode === "show" ? {
11049 height: 0,
11050 width: 0,
11051 outerHeight: 0,
11052 outerWidth: 0
11053 } : original );
11054 options.to = {
11055 height: original.height * factor.y,
11056 width: original.width * factor.x,
11057 outerHeight: original.outerHeight * factor.y,
11058 outerWidth: original.outerWidth * factor.x
11059 };
11060
11061 // Fade option to support puff
11062 if ( options.fade ) {
11063 if ( mode === "show" ) {
11064 options.from.opacity = 0;
11065 options.to.opacity = 1;
11066 }
11067 if ( mode === "hide" ) {
11068 options.from.opacity = 1;
11069 options.to.opacity = 0;
11070 }
11071 }
11072
11073 // Animate
11074 el.effect( options );
11075
11076 };
11077
11078 $.effects.effect.size = function( o, done ) {
11079
11080 // Create element
11081 var original, baseline, factor,
11082 el = $( this ),
11083 props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ],
11084
11085 // Always restore
11086 props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ],
11087
11088 // Copy for children
11089 props2 = [ "width", "height", "overflow" ],
11090 cProps = [ "fontSize" ],
11091 vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
11092 hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
11093
11094 // Set options
11095 mode = $.effects.setMode( el, o.mode || "effect" ),
11096 restore = o.restore || mode !== "effect",
11097 scale = o.scale || "both",
11098 origin = o.origin || [ "middle", "center" ],
11099 position = el.css( "position" ),
11100 props = restore ? props0 : props1,
11101 zero = {
11102 height: 0,
11103 width: 0,
11104 outerHeight: 0,
11105 outerWidth: 0
11106 };
11107
11108 if ( mode === "show" ) {
11109 el.show();
11110 }
11111 original = {
11112 height: el.height(),
11113 width: el.width(),
11114 outerHeight: el.outerHeight(),
11115 outerWidth: el.outerWidth()
11116 };
11117
11118 if ( o.mode === "toggle" && mode === "show" ) {
11119 el.from = o.to || zero;
11120 el.to = o.from || original;
11121 } else {
11122 el.from = o.from || ( mode === "show" ? zero : original );
11123 el.to = o.to || ( mode === "hide" ? zero : original );
11124 }
11125
11126 // Set scaling factor
11127 factor = {
11128 from: {
11129 y: el.from.height / original.height,
11130 x: el.from.width / original.width
11131 },
11132 to: {
11133 y: el.to.height / original.height,
11134 x: el.to.width / original.width
11135 }
11136 };
11137
11138 // Scale the css box
11139 if ( scale === "box" || scale === "both" ) {
11140
11141 // Vertical props scaling
11142 if ( factor.from.y !== factor.to.y ) {
11143 props = props.concat( vProps );
11144 el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
11145 el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
11146 }
11147
11148 // Horizontal props scaling
11149 if ( factor.from.x !== factor.to.x ) {
11150 props = props.concat( hProps );
11151 el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
11152 el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
11153 }
11154 }
11155
11156 // Scale the content
11157 if ( scale === "content" || scale === "both" ) {
11158
11159 // Vertical props scaling
11160 if ( factor.from.y !== factor.to.y ) {
11161 props = props.concat( cProps ).concat( props2 );
11162 el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
11163 el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
11164 }
11165 }
11166
11167 $.effects.save( el, props );
11168 el.show();
11169 $.effects.createWrapper( el );
11170 el.css( "overflow", "hidden" ).css( el.from );
11171
11172 // Adjust
11173 if (origin) { // Calculate baseline shifts
11174 baseline = $.effects.getBaseline( origin, original );
11175 el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
11176 el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
11177 el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
11178 el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
11179 }
11180 el.css( el.from ); // set top & left
11181
11182 // Animate
11183 if ( scale === "content" || scale === "both" ) { // Scale the children
11184
11185 // Add margins/font-size
11186 vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps);
11187 hProps = hProps.concat([ "marginLeft", "marginRight" ]);
11188 props2 = props0.concat(vProps).concat(hProps);
11189
11190 el.find( "*[width]" ).each( function(){
11191 var child = $( this ),
11192 c_original = {
11193 height: child.height(),
11194 width: child.width(),
11195 outerHeight: child.outerHeight(),
11196 outerWidth: child.outerWidth()
11197 };
11198 if (restore) {
11199 $.effects.save(child, props2);
11200 }
11201
11202 child.from = {
11203 height: c_original.height * factor.from.y,
11204 width: c_original.width * factor.from.x,
11205 outerHeight: c_original.outerHeight * factor.from.y,
11206 outerWidth: c_original.outerWidth * factor.from.x
11207 };
11208 child.to = {
11209 height: c_original.height * factor.to.y,
11210 width: c_original.width * factor.to.x,
11211 outerHeight: c_original.height * factor.to.y,
11212 outerWidth: c_original.width * factor.to.x
11213 };
11214
11215 // Vertical props scaling
11216 if ( factor.from.y !== factor.to.y ) {
11217 child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
11218 child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
11219 }
11220
11221 // Horizontal props scaling
11222 if ( factor.from.x !== factor.to.x ) {
11223 child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
11224 child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
11225 }
11226
11227 // Animate children
11228 child.css( child.from );
11229 child.animate( child.to, o.duration, o.easing, function() {
11230
11231 // Restore children
11232 if ( restore ) {
11233 $.effects.restore( child, props2 );
11234 }
11235 });
11236 });
11237 }
11238
11239 // Animate
11240 el.animate( el.to, {
11241 queue: false,
11242 duration: o.duration,
11243 easing: o.easing,
11244 complete: function() {
11245 if ( el.to.opacity === 0 ) {
11246 el.css( "opacity", el.from.opacity );
11247 }
11248 if( mode === "hide" ) {
11249 el.hide();
11250 }
11251 $.effects.restore( el, props );
11252 if ( !restore ) {
11253
11254 // we need to calculate our new positioning based on the scaling
11255 if ( position === "static" ) {
11256 el.css({
11257 position: "relative",
11258 top: el.to.top,
11259 left: el.to.left
11260 });
11261 } else {
11262 $.each([ "top", "left" ], function( idx, pos ) {
11263 el.css( pos, function( _, str ) {
11264 var val = parseInt( str, 10 ),
11265 toRef = idx ? el.to.left : el.to.top;
11266
11267 // if original was "auto", recalculate the new value from wrapper
11268 if ( str === "auto" ) {
11269 return toRef + "px";
11270 }
11271
11272 return val + toRef + "px";
11273 });
11274 });
11275 }
11276 }
11277
11278 $.effects.removeWrapper( el );
11279 done();
11280 }
11281 });
11282
11283 };
11284
11285 })(jQuery);
11286
11287 (function( $, undefined ) {
11288
11289 $.effects.effect.shake = function( o, done ) {
11290
11291 var el = $( this ),
11292 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
11293 mode = $.effects.setMode( el, o.mode || "effect" ),
11294 direction = o.direction || "left",
11295 distance = o.distance || 20,
11296 times = o.times || 3,
11297 anims = times * 2 + 1,
11298 speed = Math.round(o.duration/anims),
11299 ref = (direction === "up" || direction === "down") ? "top" : "left",
11300 positiveMotion = (direction === "up" || direction === "left"),
11301 animation = {},
11302 animation1 = {},
11303 animation2 = {},
11304 i,
11305
11306 // we will need to re-assemble the queue to stack our animations in place
11307 queue = el.queue(),
11308 queuelen = queue.length;
11309
11310 $.effects.save( el, props );
11311 el.show();
11312 $.effects.createWrapper( el );
11313
11314 // Animation
11315 animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
11316 animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
11317 animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
11318
11319 // Animate
11320 el.animate( animation, speed, o.easing );
11321
11322 // Shakes
11323 for ( i = 1; i < times; i++ ) {
11324 el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing );
11325 }
11326 el
11327 .animate( animation1, speed, o.easing )
11328 .animate( animation, speed / 2, o.easing )
11329 .queue(function() {
11330 if ( mode === "hide" ) {
11331 el.hide();
11332 }
11333 $.effects.restore( el, props );
11334 $.effects.removeWrapper( el );
11335 done();
11336 });
11337
11338 // inject all the animations we just queued to be first in line (after "inprogress")
11339 if ( queuelen > 1) {
11340 queue.splice.apply( queue,
11341 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
11342 }
11343 el.dequeue();
11344
11345 };
11346
11347 })(jQuery);
11348
11349 (function( $, undefined ) {
11350
11351 $.effects.effect.slide = function( o, done ) {
11352
11353 // Create element
11354 var el = $( this ),
11355 props = [ "position", "top", "bottom", "left", "right", "width", "height" ],
11356 mode = $.effects.setMode( el, o.mode || "show" ),
11357 show = mode === "show",
11358 direction = o.direction || "left",
11359 ref = (direction === "up" || direction === "down") ? "top" : "left",
11360 positiveMotion = (direction === "up" || direction === "left"),
11361 distance,
11362 animation = {};
11363
11364 // Adjust
11365 $.effects.save( el, props );
11366 el.show();
11367 distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true );
11368
11369 $.effects.createWrapper( el ).css({
11370 overflow: "hidden"
11371 });
11372
11373 if ( show ) {
11374 el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance );
11375 }
11376
11377 // Animation
11378 animation[ ref ] = ( show ?
11379 ( positiveMotion ? "+=" : "-=") :
11380 ( positiveMotion ? "-=" : "+=")) +
11381 distance;
11382
11383 // Animate
11384 el.animate( animation, {
11385 queue: false,
11386 duration: o.duration,
11387 easing: o.easing,
11388 complete: function() {
11389 if ( mode === "hide" ) {
11390 el.hide();
11391 }
11392 $.effects.restore( el, props );
11393 $.effects.removeWrapper( el );
11394 done();
11395 }
11396 });
11397 };
11398
11399 })(jQuery);
11400
11401 (function( $, undefined ) {
11402
11403 $.effects.effect.transfer = function( o, done ) {
11404 var elem = $( this ),
11405 target = $( o.to ),
11406 targetFixed = target.css( "position" ) === "fixed",
11407 body = $("body"),
11408 fixTop = targetFixed ? body.scrollTop() : 0,
11409 fixLeft = targetFixed ? body.scrollLeft() : 0,
11410 endPosition = target.offset(),
11411 animation = {
11412 top: endPosition.top - fixTop ,
11413 left: endPosition.left - fixLeft ,
11414 height: target.innerHeight(),
11415 width: target.innerWidth()
11416 },
11417 startPosition = elem.offset(),
11418 transfer = $( "<div class='ui-effects-transfer'></div>" )
11419 .appendTo( document.body )
11420 .addClass( o.className )
11421 .css({
11422 top: startPosition.top - fixTop ,
11423 left: startPosition.left - fixLeft ,
11424 height: elem.innerHeight(),
11425 width: elem.innerWidth(),
11426 position: targetFixed ? "fixed" : "absolute"
11427 })
11428 .animate( animation, o.duration, o.easing, function() {
11429 transfer.remove();
11430 done();
11431 });
11432 };
11433
11434 })(jQuery);
11435
11436 (function( $, undefined ) {
11437
11438 $.widget( "ui.menu", {
11439 version: "1.10.4",
11440 defaultElement: "<ul>",
11441 delay: 300,
11442 options: {
11443 icons: {
11444 submenu: "ui-icon-carat-1-e"
11445 },
11446 menus: "ul",
11447 position: {
11448 my: "left top",
11449 at: "right top"
11450 },
11451 role: "menu",
11452
11453 // callbacks
11454 blur: null,
11455 focus: null,
11456 select: null
11457 },
11458
11459 _create: function() {
11460 this.activeMenu = this.element;
11461 // flag used to prevent firing of the click handler
11462 // as the event bubbles up through nested menus
11463 this.mouseHandled = false;
11464 this.element
11465 .uniqueId()
11466 .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
11467 .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
11468 .attr({
11469 role: this.options.role,
11470 tabIndex: 0
11471 })
11472 // need to catch all clicks on disabled menu
11473 // not possible through _on
11474 .bind( "click" + this.eventNamespace, $.proxy(function( event ) {
11475 if ( this.options.disabled ) {
11476 event.preventDefault();
11477 }
11478 }, this ));
11479
11480 if ( this.options.disabled ) {
11481 this.element
11482 .addClass( "ui-state-disabled" )
11483 .attr( "aria-disabled", "true" );
11484 }
11485
11486 this._on({
11487 // Prevent focus from sticking to links inside menu after clicking
11488 // them (focus should always stay on UL during navigation).
11489 "mousedown .ui-menu-item > a": function( event ) {
11490 event.preventDefault();
11491 },
11492 "click .ui-state-disabled > a": function( event ) {
11493 event.preventDefault();
11494 },
11495 "click .ui-menu-item:has(a)": function( event ) {
11496 var target = $( event.target ).closest( ".ui-menu-item" );
11497 if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
11498 this.select( event );
11499
11500 // Only set the mouseHandled flag if the event will bubble, see #9469.
11501 if ( !event.isPropagationStopped() ) {
11502 this.mouseHandled = true;
11503 }
11504
11505 // Open submenu on click
11506 if ( target.has( ".ui-menu" ).length ) {
11507 this.expand( event );
11508 } else if ( !this.element.is( ":focus" ) && $( this.document[ 0 ].activeElement ).closest( ".ui-menu" ).length ) {
11509
11510 // Redirect focus to the menu
11511 this.element.trigger( "focus", [ true ] );
11512
11513 // If the active item is on the top level, let it stay active.
11514 // Otherwise, blur the active item since it is no longer visible.
11515 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
11516 clearTimeout( this.timer );
11517 }
11518 }
11519 }
11520 },
11521 "mouseenter .ui-menu-item": function( event ) {
11522 var target = $( event.currentTarget );
11523 // Remove ui-state-active class from siblings of the newly focused menu item
11524 // to avoid a jump caused by adjacent elements both having a class with a border
11525 target.siblings().children( ".ui-state-active" ).removeClass( "ui-state-active" );
11526 this.focus( event, target );
11527 },
11528 mouseleave: "collapseAll",
11529 "mouseleave .ui-menu": "collapseAll",
11530 focus: function( event, keepActiveItem ) {
11531 // If there's already an active item, keep it active
11532 // If not, activate the first item
11533 var item = this.active || this.element.children( ".ui-menu-item" ).eq( 0 );
11534
11535 if ( !keepActiveItem ) {
11536 this.focus( event, item );
11537 }
11538 },
11539 blur: function( event ) {
11540 this._delay(function() {
11541 if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
11542 this.collapseAll( event );
11543 }
11544 });
11545 },
11546 keydown: "_keydown"
11547 });
11548
11549 this.refresh();
11550
11551 // Clicks outside of a menu collapse any open menus
11552 this._on( this.document, {
11553 click: function( event ) {
11554 if ( !$( event.target ).closest( ".ui-menu" ).length ) {
11555 this.collapseAll( event );
11556 }
11557
11558 // Reset the mouseHandled flag
11559 this.mouseHandled = false;
11560 }
11561 });
11562 },
11563
11564 _destroy: function() {
11565 // Destroy (sub)menus
11566 this.element
11567 .removeAttr( "aria-activedescendant" )
11568 .find( ".ui-menu" ).addBack()
11569 .removeClass( "ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons" )
11570 .removeAttr( "role" )
11571 .removeAttr( "tabIndex" )
11572 .removeAttr( "aria-labelledby" )
11573 .removeAttr( "aria-expanded" )
11574 .removeAttr( "aria-hidden" )
11575 .removeAttr( "aria-disabled" )
11576 .removeUniqueId()
11577 .show();
11578
11579 // Destroy menu items
11580 this.element.find( ".ui-menu-item" )
11581 .removeClass( "ui-menu-item" )
11582 .removeAttr( "role" )
11583 .removeAttr( "aria-disabled" )
11584 .children( "a" )
11585 .removeUniqueId()
11586 .removeClass( "ui-corner-all ui-state-hover" )
11587 .removeAttr( "tabIndex" )
11588 .removeAttr( "role" )
11589 .removeAttr( "aria-haspopup" )
11590 .children().each( function() {
11591 var elem = $( this );
11592 if ( elem.data( "ui-menu-submenu-carat" ) ) {
11593 elem.remove();
11594 }
11595 });
11596
11597 // Destroy menu dividers
11598 this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
11599 },
11600
11601 _keydown: function( event ) {
11602 var match, prev, character, skip, regex,
11603 preventDefault = true;
11604
11605 function escape( value ) {
11606 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
11607 }
11608
11609 switch ( event.keyCode ) {
11610 case $.ui.keyCode.PAGE_UP:
11611 this.previousPage( event );
11612 break;
11613 case $.ui.keyCode.PAGE_DOWN:
11614 this.nextPage( event );
11615 break;
11616 case $.ui.keyCode.HOME:
11617 this._move( "first", "first", event );
11618 break;
11619 case $.ui.keyCode.END:
11620 this._move( "last", "last", event );
11621 break;
11622 case $.ui.keyCode.UP:
11623 this.previous( event );
11624 break;
11625 case $.ui.keyCode.DOWN:
11626 this.next( event );
11627 break;
11628 case $.ui.keyCode.LEFT:
11629 this.collapse( event );
11630 break;
11631 case $.ui.keyCode.RIGHT:
11632 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
11633 this.expand( event );
11634 }
11635 break;
11636 case $.ui.keyCode.ENTER:
11637 case $.ui.keyCode.SPACE:
11638 this._activate( event );
11639 break;
11640 case $.ui.keyCode.ESCAPE:
11641 this.collapse( event );
11642 break;
11643 default:
11644 preventDefault = false;
11645 prev = this.previousFilter || "";
11646 character = String.fromCharCode( event.keyCode );
11647 skip = false;
11648
11649 clearTimeout( this.filterTimer );
11650
11651 if ( character === prev ) {
11652 skip = true;
11653 } else {
11654 character = prev + character;
11655 }
11656
11657 regex = new RegExp( "^" + escape( character ), "i" );
11658 match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
11659 return regex.test( $( this ).children( "a" ).text() );
11660 });
11661 match = skip && match.index( this.active.next() ) !== -1 ?
11662 this.active.nextAll( ".ui-menu-item" ) :
11663 match;
11664
11665 // If no matches on the current filter, reset to the last character pressed
11666 // to move down the menu to the first item that starts with that character
11667 if ( !match.length ) {
11668 character = String.fromCharCode( event.keyCode );
11669 regex = new RegExp( "^" + escape( character ), "i" );
11670 match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
11671 return regex.test( $( this ).children( "a" ).text() );
11672 });
11673 }
11674
11675 if ( match.length ) {
11676 this.focus( event, match );
11677 if ( match.length > 1 ) {
11678 this.previousFilter = character;
11679 this.filterTimer = this._delay(function() {
11680 delete this.previousFilter;
11681 }, 1000 );
11682 } else {
11683 delete this.previousFilter;
11684 }
11685 } else {
11686 delete this.previousFilter;
11687 }
11688 }
11689
11690 if ( preventDefault ) {
11691 event.preventDefault();
11692 }
11693 },
11694
11695 _activate: function( event ) {
11696 if ( !this.active.is( ".ui-state-disabled" ) ) {
11697 if ( this.active.children( "a[aria-haspopup='true']" ).length ) {
11698 this.expand( event );
11699 } else {
11700 this.select( event );
11701 }
11702 }
11703 },
11704
11705 refresh: function() {
11706 var menus,
11707 icon = this.options.icons.submenu,
11708 submenus = this.element.find( this.options.menus );
11709
11710 this.element.toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length );
11711
11712 // Initialize nested menus
11713 submenus.filter( ":not(.ui-menu)" )
11714 .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
11715 .hide()
11716 .attr({
11717 role: this.options.role,
11718 "aria-hidden": "true",
11719 "aria-expanded": "false"
11720 })
11721 .each(function() {
11722 var menu = $( this ),
11723 item = menu.prev( "a" ),
11724 submenuCarat = $( "<span>" )
11725 .addClass( "ui-menu-icon ui-icon " + icon )
11726 .data( "ui-menu-submenu-carat", true );
11727
11728 item
11729 .attr( "aria-haspopup", "true" )
11730 .prepend( submenuCarat );
11731 menu.attr( "aria-labelledby", item.attr( "id" ) );
11732 });
11733
11734 menus = submenus.add( this.element );
11735
11736 // Don't refresh list items that are already adapted
11737 menus.children( ":not(.ui-menu-item):has(a)" )
11738 .addClass( "ui-menu-item" )
11739 .attr( "role", "presentation" )
11740 .children( "a" )
11741 .uniqueId()
11742 .addClass( "ui-corner-all" )
11743 .attr({
11744 tabIndex: -1,
11745 role: this._itemRole()
11746 });
11747
11748 // Initialize unlinked menu-items containing spaces and/or dashes only as dividers
11749 menus.children( ":not(.ui-menu-item)" ).each(function() {
11750 var item = $( this );
11751 // hyphen, em dash, en dash
11752 if ( !/[^\-\u2014\u2013\s]/.test( item.text() ) ) {
11753 item.addClass( "ui-widget-content ui-menu-divider" );
11754 }
11755 });
11756
11757 // Add aria-disabled attribute to any disabled menu item
11758 menus.children( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
11759
11760 // If the active item has been removed, blur the menu
11761 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
11762 this.blur();
11763 }
11764 },
11765
11766 _itemRole: function() {
11767 return {
11768 menu: "menuitem",
11769 listbox: "option"
11770 }[ this.options.role ];
11771 },
11772
11773 _setOption: function( key, value ) {
11774 if ( key === "icons" ) {
11775 this.element.find( ".ui-menu-icon" )
11776 .removeClass( this.options.icons.submenu )
11777 .addClass( value.submenu );
11778 }
11779 this._super( key, value );
11780 },
11781
11782 focus: function( event, item ) {
11783 var nested, focused;
11784 this.blur( event, event && event.type === "focus" );
11785
11786 this._scrollIntoView( item );
11787
11788 this.active = item.first();
11789 focused = this.active.children( "a" ).addClass( "ui-state-focus" );
11790 // Only update aria-activedescendant if there's a role
11791 // otherwise we assume focus is managed elsewhere
11792 if ( this.options.role ) {
11793 this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
11794 }
11795
11796 // Highlight active parent menu item, if any
11797 this.active
11798 .parent()
11799 .closest( ".ui-menu-item" )
11800 .children( "a:first" )
11801 .addClass( "ui-state-active" );
11802
11803 if ( event && event.type === "keydown" ) {
11804 this._close();
11805 } else {
11806 this.timer = this._delay(function() {
11807 this._close();
11808 }, this.delay );
11809 }
11810
11811 nested = item.children( ".ui-menu" );
11812 if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
11813 this._startOpening(nested);
11814 }
11815 this.activeMenu = item.parent();
11816
11817 this._trigger( "focus", event, { item: item } );
11818 },
11819
11820 _scrollIntoView: function( item ) {
11821 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
11822 if ( this._hasScroll() ) {
11823 borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
11824 paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
11825 offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
11826 scroll = this.activeMenu.scrollTop();
11827 elementHeight = this.activeMenu.height();
11828 itemHeight = item.height();
11829
11830 if ( offset < 0 ) {
11831 this.activeMenu.scrollTop( scroll + offset );
11832 } else if ( offset + itemHeight > elementHeight ) {
11833 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
11834 }
11835 }
11836 },
11837
11838 blur: function( event, fromFocus ) {
11839 if ( !fromFocus ) {
11840 clearTimeout( this.timer );
11841 }
11842
11843 if ( !this.active ) {
11844 return;
11845 }
11846
11847 this.active.children( "a" ).removeClass( "ui-state-focus" );
11848 this.active = null;
11849
11850 this._trigger( "blur", event, { item: this.active } );
11851 },
11852
11853 _startOpening: function( submenu ) {
11854 clearTimeout( this.timer );
11855
11856 // Don't open if already open fixes a Firefox bug that caused a .5 pixel
11857 // shift in the submenu position when mousing over the carat icon
11858 if ( submenu.attr( "aria-hidden" ) !== "true" ) {
11859 return;
11860 }
11861
11862 this.timer = this._delay(function() {
11863 this._close();
11864 this._open( submenu );
11865 }, this.delay );
11866 },
11867
11868 _open: function( submenu ) {
11869 var position = $.extend({
11870 of: this.active
11871 }, this.options.position );
11872
11873 clearTimeout( this.timer );
11874 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
11875 .hide()
11876 .attr( "aria-hidden", "true" );
11877
11878 submenu
11879 .show()
11880 .removeAttr( "aria-hidden" )
11881 .attr( "aria-expanded", "true" )
11882 .position( position );
11883 },
11884
11885 collapseAll: function( event, all ) {
11886 clearTimeout( this.timer );
11887 this.timer = this._delay(function() {
11888 // If we were passed an event, look for the submenu that contains the event
11889 var currentMenu = all ? this.element :
11890 $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
11891
11892 // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
11893 if ( !currentMenu.length ) {
11894 currentMenu = this.element;
11895 }
11896
11897 this._close( currentMenu );
11898
11899 this.blur( event );
11900 this.activeMenu = currentMenu;
11901 }, this.delay );
11902 },
11903
11904 // With no arguments, closes the currently active menu - if nothing is active
11905 // it closes all menus. If passed an argument, it will search for menus BELOW
11906 _close: function( startMenu ) {
11907 if ( !startMenu ) {
11908 startMenu = this.active ? this.active.parent() : this.element;
11909 }
11910
11911 startMenu
11912 .find( ".ui-menu" )
11913 .hide()
11914 .attr( "aria-hidden", "true" )
11915 .attr( "aria-expanded", "false" )
11916 .end()
11917 .find( "a.ui-state-active" )
11918 .removeClass( "ui-state-active" );
11919 },
11920
11921 collapse: function( event ) {
11922 var newItem = this.active &&
11923 this.active.parent().closest( ".ui-menu-item", this.element );
11924 if ( newItem && newItem.length ) {
11925 this._close();
11926 this.focus( event, newItem );
11927 }
11928 },
11929
11930 expand: function( event ) {
11931 var newItem = this.active &&
11932 this.active
11933 .children( ".ui-menu " )
11934 .children( ".ui-menu-item" )
11935 .first();
11936
11937 if ( newItem && newItem.length ) {
11938 this._open( newItem.parent() );
11939
11940 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
11941 this._delay(function() {
11942 this.focus( event, newItem );
11943 });
11944 }
11945 },
11946
11947 next: function( event ) {
11948 this._move( "next", "first", event );
11949 },
11950
11951 previous: function( event ) {
11952 this._move( "prev", "last", event );
11953 },
11954
11955 isFirstItem: function() {
11956 return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
11957 },
11958
11959 isLastItem: function() {
11960 return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
11961 },
11962
11963 _move: function( direction, filter, event ) {
11964 var next;
11965 if ( this.active ) {
11966 if ( direction === "first" || direction === "last" ) {
11967 next = this.active
11968 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
11969 .eq( -1 );
11970 } else {
11971 next = this.active
11972 [ direction + "All" ]( ".ui-menu-item" )
11973 .eq( 0 );
11974 }
11975 }
11976 if ( !next || !next.length || !this.active ) {
11977 next = this.activeMenu.children( ".ui-menu-item" )[ filter ]();
11978 }
11979
11980 this.focus( event, next );
11981 },
11982
11983 nextPage: function( event ) {
11984 var item, base, height;
11985
11986 if ( !this.active ) {
11987 this.next( event );
11988 return;
11989 }
11990 if ( this.isLastItem() ) {
11991 return;
11992 }
11993 if ( this._hasScroll() ) {
11994 base = this.active.offset().top;
11995 height = this.element.height();
11996 this.active.nextAll( ".ui-menu-item" ).each(function() {
11997 item = $( this );
11998 return item.offset().top - base - height < 0;
11999 });
12000
12001 this.focus( event, item );
12002 } else {
12003 this.focus( event, this.activeMenu.children( ".ui-menu-item" )
12004 [ !this.active ? "first" : "last" ]() );
12005 }
12006 },
12007
12008 previousPage: function( event ) {
12009 var item, base, height;
12010 if ( !this.active ) {
12011 this.next( event );
12012 return;
12013 }
12014 if ( this.isFirstItem() ) {
12015 return;
12016 }
12017 if ( this._hasScroll() ) {
12018 base = this.active.offset().top;
12019 height = this.element.height();
12020 this.active.prevAll( ".ui-menu-item" ).each(function() {
12021 item = $( this );
12022 return item.offset().top - base + height > 0;
12023 });
12024
12025 this.focus( event, item );
12026 } else {
12027 this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
12028 }
12029 },
12030
12031 _hasScroll: function() {
12032 return this.element.outerHeight() < this.element.prop( "scrollHeight" );
12033 },
12034
12035 select: function( event ) {
12036 // TODO: It should never be possible to not have an active item at this
12037 // point, but the tests don't trigger mouseenter before click.
12038 this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
12039 var ui = { item: this.active };
12040 if ( !this.active.has( ".ui-menu" ).length ) {
12041 this.collapseAll( event, true );
12042 }
12043 this._trigger( "select", event, ui );
12044 }
12045 });
12046
12047 }( jQuery ));
12048
12049 (function( $, undefined ) {
12050
12051 $.ui = $.ui || {};
12052
12053 var cachedScrollbarWidth,
12054 max = Math.max,
12055 abs = Math.abs,
12056 round = Math.round,
12057 rhorizontal = /left|center|right/,
12058 rvertical = /top|center|bottom/,
12059 roffset = /[\+\-]\d+(\.[\d]+)?%?/,
12060 rposition = /^\w+/,
12061 rpercent = /%$/,
12062 _position = $.fn.position;
12063
12064 function getOffsets( offsets, width, height ) {
12065 return [
12066 parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
12067 parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
12068 ];
12069 }
12070
12071 function parseCss( element, property ) {
12072 return parseInt( $.css( element, property ), 10 ) || 0;
12073 }
12074
12075 function getDimensions( elem ) {
12076 var raw = elem[0];
12077 if ( raw.nodeType === 9 ) {
12078 return {
12079 width: elem.width(),
12080 height: elem.height(),
12081 offset: { top: 0, left: 0 }
12082 };
12083 }
12084 if ( $.isWindow( raw ) ) {
12085 return {
12086 width: elem.width(),
12087 height: elem.height(),
12088 offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
12089 };
12090 }
12091 if ( raw.preventDefault ) {
12092 return {
12093 width: 0,
12094 height: 0,
12095 offset: { top: raw.pageY, left: raw.pageX }
12096 };
12097 }
12098 return {
12099 width: elem.outerWidth(),
12100 height: elem.outerHeight(),
12101 offset: elem.offset()
12102 };
12103 }
12104
12105 $.position = {
12106 scrollbarWidth: function() {
12107 if ( cachedScrollbarWidth !== undefined ) {
12108 return cachedScrollbarWidth;
12109 }
12110 var w1, w2,
12111 div = $( "<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
12112 innerDiv = div.children()[0];
12113
12114 $( "body" ).append( div );
12115 w1 = innerDiv.offsetWidth;
12116 div.css( "overflow", "scroll" );
12117
12118 w2 = innerDiv.offsetWidth;
12119
12120 if ( w1 === w2 ) {
12121 w2 = div[0].clientWidth;
12122 }
12123
12124 div.remove();
12125
12126 return (cachedScrollbarWidth = w1 - w2);
12127 },
12128 getScrollInfo: function( within ) {
12129 var overflowX = within.isWindow || within.isDocument ? "" :
12130 within.element.css( "overflow-x" ),
12131 overflowY = within.isWindow || within.isDocument ? "" :
12132 within.element.css( "overflow-y" ),
12133 hasOverflowX = overflowX === "scroll" ||
12134 ( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
12135 hasOverflowY = overflowY === "scroll" ||
12136 ( overflowY === "auto" && within.height < within.element[0].scrollHeight );
12137 return {
12138 width: hasOverflowY ? $.position.scrollbarWidth() : 0,
12139 height: hasOverflowX ? $.position.scrollbarWidth() : 0
12140 };
12141 },
12142 getWithinInfo: function( element ) {
12143 var withinElement = $( element || window ),
12144 isWindow = $.isWindow( withinElement[0] ),
12145 isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9;
12146 return {
12147 element: withinElement,
12148 isWindow: isWindow,
12149 isDocument: isDocument,
12150 offset: withinElement.offset() || { left: 0, top: 0 },
12151 scrollLeft: withinElement.scrollLeft(),
12152 scrollTop: withinElement.scrollTop(),
12153 width: isWindow ? withinElement.width() : withinElement.outerWidth(),
12154 height: isWindow ? withinElement.height() : withinElement.outerHeight()
12155 };
12156 }
12157 };
12158
12159 $.fn.position = function( options ) {
12160 if ( !options || !options.of ) {
12161 return _position.apply( this, arguments );
12162 }
12163
12164 // make a copy, we don't want to modify arguments
12165 options = $.extend( {}, options );
12166
12167 var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
12168 target = $( options.of ),
12169 within = $.position.getWithinInfo( options.within ),
12170 scrollInfo = $.position.getScrollInfo( within ),
12171 collision = ( options.collision || "flip" ).split( " " ),
12172 offsets = {};
12173
12174 dimensions = getDimensions( target );
12175 if ( target[0].preventDefault ) {
12176 // force left top to allow flipping
12177 options.at = "left top";
12178 }
12179 targetWidth = dimensions.width;
12180 targetHeight = dimensions.height;
12181 targetOffset = dimensions.offset;
12182 // clone to reuse original targetOffset later
12183 basePosition = $.extend( {}, targetOffset );
12184
12185 // force my and at to have valid horizontal and vertical positions
12186 // if a value is missing or invalid, it will be converted to center
12187 $.each( [ "my", "at" ], function() {
12188 var pos = ( options[ this ] || "" ).split( " " ),
12189 horizontalOffset,
12190 verticalOffset;
12191
12192 if ( pos.length === 1) {
12193 pos = rhorizontal.test( pos[ 0 ] ) ?
12194 pos.concat( [ "center" ] ) :
12195 rvertical.test( pos[ 0 ] ) ?
12196 [ "center" ].concat( pos ) :
12197 [ "center", "center" ];
12198 }
12199 pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
12200 pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
12201
12202 // calculate offsets
12203 horizontalOffset = roffset.exec( pos[ 0 ] );
12204 verticalOffset = roffset.exec( pos[ 1 ] );
12205 offsets[ this ] = [
12206 horizontalOffset ? horizontalOffset[ 0 ] : 0,
12207 verticalOffset ? verticalOffset[ 0 ] : 0
12208 ];
12209
12210 // reduce to just the positions without the offsets
12211 options[ this ] = [
12212 rposition.exec( pos[ 0 ] )[ 0 ],
12213 rposition.exec( pos[ 1 ] )[ 0 ]
12214 ];
12215 });
12216
12217 // normalize collision option
12218 if ( collision.length === 1 ) {
12219 collision[ 1 ] = collision[ 0 ];
12220 }
12221
12222 if ( options.at[ 0 ] === "right" ) {
12223 basePosition.left += targetWidth;
12224 } else if ( options.at[ 0 ] === "center" ) {
12225 basePosition.left += targetWidth / 2;
12226 }
12227
12228 if ( options.at[ 1 ] === "bottom" ) {
12229 basePosition.top += targetHeight;
12230 } else if ( options.at[ 1 ] === "center" ) {
12231 basePosition.top += targetHeight / 2;
12232 }
12233
12234 atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
12235 basePosition.left += atOffset[ 0 ];
12236 basePosition.top += atOffset[ 1 ];
12237
12238 return this.each(function() {
12239 var collisionPosition, using,
12240 elem = $( this ),
12241 elemWidth = elem.outerWidth(),
12242 elemHeight = elem.outerHeight(),
12243 marginLeft = parseCss( this, "marginLeft" ),
12244 marginTop = parseCss( this, "marginTop" ),
12245 collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
12246 collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
12247 position = $.extend( {}, basePosition ),
12248 myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
12249
12250 if ( options.my[ 0 ] === "right" ) {
12251 position.left -= elemWidth;
12252 } else if ( options.my[ 0 ] === "center" ) {
12253 position.left -= elemWidth / 2;
12254 }
12255
12256 if ( options.my[ 1 ] === "bottom" ) {
12257 position.top -= elemHeight;
12258 } else if ( options.my[ 1 ] === "center" ) {
12259 position.top -= elemHeight / 2;
12260 }
12261
12262 position.left += myOffset[ 0 ];
12263 position.top += myOffset[ 1 ];
12264
12265 // if the browser doesn't support fractions, then round for consistent results
12266 if ( !$.support.offsetFractions ) {
12267 position.left = round( position.left );
12268 position.top = round( position.top );
12269 }
12270
12271 collisionPosition = {
12272 marginLeft: marginLeft,
12273 marginTop: marginTop
12274 };
12275
12276 $.each( [ "left", "top" ], function( i, dir ) {
12277 if ( $.ui.position[ collision[ i ] ] ) {
12278 $.ui.position[ collision[ i ] ][ dir ]( position, {
12279 targetWidth: targetWidth,
12280 targetHeight: targetHeight,
12281 elemWidth: elemWidth,
12282 elemHeight: elemHeight,
12283 collisionPosition: collisionPosition,
12284 collisionWidth: collisionWidth,
12285 collisionHeight: collisionHeight,
12286 offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
12287 my: options.my,
12288 at: options.at,
12289 within: within,
12290 elem : elem
12291 });
12292 }
12293 });
12294
12295 if ( options.using ) {
12296 // adds feedback as second argument to using callback, if present
12297 using = function( props ) {
12298 var left = targetOffset.left - position.left,
12299 right = left + targetWidth - elemWidth,
12300 top = targetOffset.top - position.top,
12301 bottom = top + targetHeight - elemHeight,
12302 feedback = {
12303 target: {
12304 element: target,
12305 left: targetOffset.left,
12306 top: targetOffset.top,
12307 width: targetWidth,
12308 height: targetHeight
12309 },
12310 element: {
12311 element: elem,
12312 left: position.left,
12313 top: position.top,
12314 width: elemWidth,
12315 height: elemHeight
12316 },
12317 horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
12318 vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
12319 };
12320 if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
12321 feedback.horizontal = "center";
12322 }
12323 if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
12324 feedback.vertical = "middle";
12325 }
12326 if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
12327 feedback.important = "horizontal";
12328 } else {
12329 feedback.important = "vertical";
12330 }
12331 options.using.call( this, props, feedback );
12332 };
12333 }
12334
12335 elem.offset( $.extend( position, { using: using } ) );
12336 });
12337 };
12338
12339 $.ui.position = {
12340 fit: {
12341 left: function( position, data ) {
12342 var within = data.within,
12343 withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
12344 outerWidth = within.width,
12345 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
12346 overLeft = withinOffset - collisionPosLeft,
12347 overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
12348 newOverRight;
12349
12350 // element is wider than within
12351 if ( data.collisionWidth > outerWidth ) {
12352 // element is initially over the left side of within
12353 if ( overLeft > 0 && overRight <= 0 ) {
12354 newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
12355 position.left += overLeft - newOverRight;
12356 // element is initially over right side of within
12357 } else if ( overRight > 0 && overLeft <= 0 ) {
12358 position.left = withinOffset;
12359 // element is initially over both left and right sides of within
12360 } else {
12361 if ( overLeft > overRight ) {
12362 position.left = withinOffset + outerWidth - data.collisionWidth;
12363 } else {
12364 position.left = withinOffset;
12365 }
12366 }
12367 // too far left -> align with left edge
12368 } else if ( overLeft > 0 ) {
12369 position.left += overLeft;
12370 // too far right -> align with right edge
12371 } else if ( overRight > 0 ) {
12372 position.left -= overRight;
12373 // adjust based on position and margin
12374 } else {
12375 position.left = max( position.left - collisionPosLeft, position.left );
12376 }
12377 },
12378 top: function( position, data ) {
12379 var within = data.within,
12380 withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
12381 outerHeight = data.within.height,
12382 collisionPosTop = position.top - data.collisionPosition.marginTop,
12383 overTop = withinOffset - collisionPosTop,
12384 overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
12385 newOverBottom;
12386
12387 // element is taller than within
12388 if ( data.collisionHeight > outerHeight ) {
12389 // element is initially over the top of within
12390 if ( overTop > 0 && overBottom <= 0 ) {
12391 newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
12392 position.top += overTop - newOverBottom;
12393 // element is initially over bottom of within
12394 } else if ( overBottom > 0 && overTop <= 0 ) {
12395 position.top = withinOffset;
12396 // element is initially over both top and bottom of within
12397 } else {
12398 if ( overTop > overBottom ) {
12399 position.top = withinOffset + outerHeight - data.collisionHeight;
12400 } else {
12401 position.top = withinOffset;
12402 }
12403 }
12404 // too far up -> align with top
12405 } else if ( overTop > 0 ) {
12406 position.top += overTop;
12407 // too far down -> align with bottom edge
12408 } else if ( overBottom > 0 ) {
12409 position.top -= overBottom;
12410 // adjust based on position and margin
12411 } else {
12412 position.top = max( position.top - collisionPosTop, position.top );
12413 }
12414 }
12415 },
12416 flip: {
12417 left: function( position, data ) {
12418 var within = data.within,
12419 withinOffset = within.offset.left + within.scrollLeft,
12420 outerWidth = within.width,
12421 offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
12422 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
12423 overLeft = collisionPosLeft - offsetLeft,
12424 overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
12425 myOffset = data.my[ 0 ] === "left" ?
12426 -data.elemWidth :
12427 data.my[ 0 ] === "right" ?
12428 data.elemWidth :
12429 0,
12430 atOffset = data.at[ 0 ] === "left" ?
12431 data.targetWidth :
12432 data.at[ 0 ] === "right" ?
12433 -data.targetWidth :
12434 0,
12435 offset = -2 * data.offset[ 0 ],
12436 newOverRight,
12437 newOverLeft;
12438
12439 if ( overLeft < 0 ) {
12440 newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
12441 if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
12442 position.left += myOffset + atOffset + offset;
12443 }
12444 }
12445 else if ( overRight > 0 ) {
12446 newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
12447 if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
12448 position.left += myOffset + atOffset + offset;
12449 }
12450 }
12451 },
12452 top: function( position, data ) {
12453 var within = data.within,
12454 withinOffset = within.offset.top + within.scrollTop,
12455 outerHeight = within.height,
12456 offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
12457 collisionPosTop = position.top - data.collisionPosition.marginTop,
12458 overTop = collisionPosTop - offsetTop,
12459 overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
12460 top = data.my[ 1 ] === "top",
12461 myOffset = top ?
12462 -data.elemHeight :
12463 data.my[ 1 ] === "bottom" ?
12464 data.elemHeight :
12465 0,
12466 atOffset = data.at[ 1 ] === "top" ?
12467 data.targetHeight :
12468 data.at[ 1 ] === "bottom" ?
12469 -data.targetHeight :
12470 0,
12471 offset = -2 * data.offset[ 1 ],
12472 newOverTop,
12473 newOverBottom;
12474 if ( overTop < 0 ) {
12475 newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
12476 if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) {
12477 position.top += myOffset + atOffset + offset;
12478 }
12479 }
12480 else if ( overBottom > 0 ) {
12481 newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
12482 if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) {
12483 position.top += myOffset + atOffset + offset;
12484 }
12485 }
12486 }
12487 },
12488 flipfit: {
12489 left: function() {
12490 $.ui.position.flip.left.apply( this, arguments );
12491 $.ui.position.fit.left.apply( this, arguments );
12492 },
12493 top: function() {
12494 $.ui.position.flip.top.apply( this, arguments );
12495 $.ui.position.fit.top.apply( this, arguments );
12496 }
12497 }
12498 };
12499
12500 // fraction support test
12501 (function () {
12502 var testElement, testElementParent, testElementStyle, offsetLeft, i,
12503 body = document.getElementsByTagName( "body" )[ 0 ],
12504 div = document.createElement( "div" );
12505
12506 //Create a "fake body" for testing based on method used in jQuery.support
12507 testElement = document.createElement( body ? "div" : "body" );
12508 testElementStyle = {
12509 visibility: "hidden",
12510 width: 0,
12511 height: 0,
12512 border: 0,
12513 margin: 0,
12514 background: "none"
12515 };
12516 if ( body ) {
12517 $.extend( testElementStyle, {
12518 position: "absolute",
12519 left: "-1000px",
12520 top: "-1000px"
12521 });
12522 }
12523 for ( i in testElementStyle ) {
12524 testElement.style[ i ] = testElementStyle[ i ];
12525 }
12526 testElement.appendChild( div );
12527 testElementParent = body || document.documentElement;
12528 testElementParent.insertBefore( testElement, testElementParent.firstChild );
12529
12530 div.style.cssText = "position: absolute; left: 10.7432222px;";
12531
12532 offsetLeft = $( div ).offset().left;
12533 $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11;
12534
12535 testElement.innerHTML = "";
12536 testElementParent.removeChild( testElement );
12537 })();
12538
12539 }( jQuery ) );
12540
12541 (function( $, undefined ) {
12542
12543 $.widget( "ui.progressbar", {
12544 version: "1.10.4",
12545 options: {
12546 max: 100,
12547 value: 0,
12548
12549 change: null,
12550 complete: null
12551 },
12552
12553 min: 0,
12554
12555 _create: function() {
12556 // Constrain initial value
12557 this.oldValue = this.options.value = this._constrainedValue();
12558
12559 this.element
12560 .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
12561 .attr({
12562 // Only set static values, aria-valuenow and aria-valuemax are
12563 // set inside _refreshValue()
12564 role: "progressbar",
12565 "aria-valuemin": this.min
12566 });
12567
12568 this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
12569 .appendTo( this.element );
12570
12571 this._refreshValue();
12572 },
12573
12574 _destroy: function() {
12575 this.element
12576 .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
12577 .removeAttr( "role" )
12578 .removeAttr( "aria-valuemin" )
12579 .removeAttr( "aria-valuemax" )
12580 .removeAttr( "aria-valuenow" );
12581
12582 this.valueDiv.remove();
12583 },
12584
12585 value: function( newValue ) {
12586 if ( newValue === undefined ) {
12587 return this.options.value;
12588 }
12589
12590 this.options.value = this._constrainedValue( newValue );
12591 this._refreshValue();
12592 },
12593
12594 _constrainedValue: function( newValue ) {
12595 if ( newValue === undefined ) {
12596 newValue = this.options.value;
12597 }
12598
12599 this.indeterminate = newValue === false;
12600
12601 // sanitize value
12602 if ( typeof newValue !== "number" ) {
12603 newValue = 0;
12604 }
12605
12606 return this.indeterminate ? false :
12607 Math.min( this.options.max, Math.max( this.min, newValue ) );
12608 },
12609
12610 _setOptions: function( options ) {
12611 // Ensure "value" option is set after other values (like max)
12612 var value = options.value;
12613 delete options.value;
12614
12615 this._super( options );
12616
12617 this.options.value = this._constrainedValue( value );
12618 this._refreshValue();
12619 },
12620
12621 _setOption: function( key, value ) {
12622 if ( key === "max" ) {
12623 // Don't allow a max less than min
12624 value = Math.max( this.min, value );
12625 }
12626
12627 this._super( key, value );
12628 },
12629
12630 _percentage: function() {
12631 return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
12632 },
12633
12634 _refreshValue: function() {
12635 var value = this.options.value,
12636 percentage = this._percentage();
12637
12638 this.valueDiv
12639 .toggle( this.indeterminate || value > this.min )
12640 .toggleClass( "ui-corner-right", value === this.options.max )
12641 .width( percentage.toFixed(0) + "%" );
12642
12643 this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate );
12644
12645 if ( this.indeterminate ) {
12646 this.element.removeAttr( "aria-valuenow" );
12647 if ( !this.overlayDiv ) {
12648 this.overlayDiv = $( "<div class='ui-progressbar-overlay'></div>" ).appendTo( this.valueDiv );
12649 }
12650 } else {
12651 this.element.attr({
12652 "aria-valuemax": this.options.max,
12653 "aria-valuenow": value
12654 });
12655 if ( this.overlayDiv ) {
12656 this.overlayDiv.remove();
12657 this.overlayDiv = null;
12658 }
12659 }
12660
12661 if ( this.oldValue !== value ) {
12662 this.oldValue = value;
12663 this._trigger( "change" );
12664 }
12665 if ( value === this.options.max ) {
12666 this._trigger( "complete" );
12667 }
12668 }
12669 });
12670
12671 })( jQuery );
12672
12673 (function( $, undefined ) {
12674
12675 // number of pages in a slider
12676 // (how many times can you page up/down to go through the whole range)
12677 var numPages = 5;
12678
12679 $.widget( "ui.slider", $.ui.mouse, {
12680 version: "1.10.4",
12681 widgetEventPrefix: "slide",
12682
12683 options: {
12684 animate: false,
12685 distance: 0,
12686 max: 100,
12687 min: 0,
12688 orientation: "horizontal",
12689 range: false,
12690 step: 1,
12691 value: 0,
12692 values: null,
12693
12694 // callbacks
12695 change: null,
12696 slide: null,
12697 start: null,
12698 stop: null
12699 },
12700
12701 _create: function() {
12702 this._keySliding = false;
12703 this._mouseSliding = false;
12704 this._animateOff = true;
12705 this._handleIndex = null;
12706 this._detectOrientation();
12707 this._mouseInit();
12708
12709 this.element
12710 .addClass( "ui-slider" +
12711 " ui-slider-" + this.orientation +
12712 " ui-widget" +
12713 " ui-widget-content" +
12714 " ui-corner-all");
12715
12716 this._refresh();
12717 this._setOption( "disabled", this.options.disabled );
12718
12719 this._animateOff = false;
12720 },
12721
12722 _refresh: function() {
12723 this._createRange();
12724 this._createHandles();
12725 this._setupEvents();
12726 this._refreshValue();
12727 },
12728
12729 _createHandles: function() {
12730 var i, handleCount,
12731 options = this.options,
12732 existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
12733 handle = "<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",
12734 handles = [];
12735
12736 handleCount = ( options.values && options.values.length ) || 1;
12737
12738 if ( existingHandles.length > handleCount ) {
12739 existingHandles.slice( handleCount ).remove();
12740 existingHandles = existingHandles.slice( 0, handleCount );
12741 }
12742
12743 for ( i = existingHandles.length; i < handleCount; i++ ) {
12744 handles.push( handle );
12745 }
12746
12747 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
12748
12749 this.handle = this.handles.eq( 0 );
12750
12751 this.handles.each(function( i ) {
12752 $( this ).data( "ui-slider-handle-index", i );
12753 });
12754 },
12755
12756 _createRange: function() {
12757 var options = this.options,
12758 classes = "";
12759
12760 if ( options.range ) {
12761 if ( options.range === true ) {
12762 if ( !options.values ) {
12763 options.values = [ this._valueMin(), this._valueMin() ];
12764 } else if ( options.values.length && options.values.length !== 2 ) {
12765 options.values = [ options.values[0], options.values[0] ];
12766 } else if ( $.isArray( options.values ) ) {
12767 options.values = options.values.slice(0);
12768 }
12769 }
12770
12771 if ( !this.range || !this.range.length ) {
12772 this.range = $( "<div></div>" )
12773 .appendTo( this.element );
12774
12775 classes = "ui-slider-range" +
12776 // note: this isn't the most fittingly semantic framework class for this element,
12777 // but worked best visually with a variety of themes
12778 " ui-widget-header ui-corner-all";
12779 } else {
12780 this.range.removeClass( "ui-slider-range-min ui-slider-range-max" )
12781 // Handle range switching from true to min/max
12782 .css({
12783 "left": "",
12784 "bottom": ""
12785 });
12786 }
12787
12788 this.range.addClass( classes +
12789 ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) );
12790 } else {
12791 if ( this.range ) {
12792 this.range.remove();
12793 }
12794 this.range = null;
12795 }
12796 },
12797
12798 _setupEvents: function() {
12799 var elements = this.handles.add( this.range ).filter( "a" );
12800 this._off( elements );
12801 this._on( elements, this._handleEvents );
12802 this._hoverable( elements );
12803 this._focusable( elements );
12804 },
12805
12806 _destroy: function() {
12807 this.handles.remove();
12808 if ( this.range ) {
12809 this.range.remove();
12810 }
12811
12812 this.element
12813 .removeClass( "ui-slider" +
12814 " ui-slider-horizontal" +
12815 " ui-slider-vertical" +
12816 " ui-widget" +
12817 " ui-widget-content" +
12818 " ui-corner-all" );
12819
12820 this._mouseDestroy();
12821 },
12822
12823 _mouseCapture: function( event ) {
12824 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
12825 that = this,
12826 o = this.options;
12827
12828 if ( o.disabled ) {
12829 return false;
12830 }
12831
12832 this.elementSize = {
12833 width: this.element.outerWidth(),
12834 height: this.element.outerHeight()
12835 };
12836 this.elementOffset = this.element.offset();
12837
12838 position = { x: event.pageX, y: event.pageY };
12839 normValue = this._normValueFromMouse( position );
12840 distance = this._valueMax() - this._valueMin() + 1;
12841 this.handles.each(function( i ) {
12842 var thisDistance = Math.abs( normValue - that.values(i) );
12843 if (( distance > thisDistance ) ||
12844 ( distance === thisDistance &&
12845 (i === that._lastChangedValue || that.values(i) === o.min ))) {
12846 distance = thisDistance;
12847 closestHandle = $( this );
12848 index = i;
12849 }
12850 });
12851
12852 allowed = this._start( event, index );
12853 if ( allowed === false ) {
12854 return false;
12855 }
12856 this._mouseSliding = true;
12857
12858 this._handleIndex = index;
12859
12860 closestHandle
12861 .addClass( "ui-state-active" )
12862 .focus();
12863
12864 offset = closestHandle.offset();
12865 mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
12866 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
12867 left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
12868 top: event.pageY - offset.top -
12869 ( closestHandle.height() / 2 ) -
12870 ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
12871 ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
12872 ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
12873 };
12874
12875 if ( !this.handles.hasClass( "ui-state-hover" ) ) {
12876 this._slide( event, index, normValue );
12877 }
12878 this._animateOff = true;
12879 return true;
12880 },
12881
12882 _mouseStart: function() {
12883 return true;
12884 },
12885
12886 _mouseDrag: function( event ) {
12887 var position = { x: event.pageX, y: event.pageY },
12888 normValue = this._normValueFromMouse( position );
12889
12890 this._slide( event, this._handleIndex, normValue );
12891
12892 return false;
12893 },
12894
12895 _mouseStop: function( event ) {
12896 this.handles.removeClass( "ui-state-active" );
12897 this._mouseSliding = false;
12898
12899 this._stop( event, this._handleIndex );
12900 this._change( event, this._handleIndex );
12901
12902 this._handleIndex = null;
12903 this._clickOffset = null;
12904 this._animateOff = false;
12905
12906 return false;
12907 },
12908
12909 _detectOrientation: function() {
12910 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
12911 },
12912
12913 _normValueFromMouse: function( position ) {
12914 var pixelTotal,
12915 pixelMouse,
12916 percentMouse,
12917 valueTotal,
12918 valueMouse;
12919
12920 if ( this.orientation === "horizontal" ) {
12921 pixelTotal = this.elementSize.width;
12922 pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
12923 } else {
12924 pixelTotal = this.elementSize.height;
12925 pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
12926 }
12927
12928 percentMouse = ( pixelMouse / pixelTotal );
12929 if ( percentMouse > 1 ) {
12930 percentMouse = 1;
12931 }
12932 if ( percentMouse < 0 ) {
12933 percentMouse = 0;
12934 }
12935 if ( this.orientation === "vertical" ) {
12936 percentMouse = 1 - percentMouse;
12937 }
12938
12939 valueTotal = this._valueMax() - this._valueMin();
12940 valueMouse = this._valueMin() + percentMouse * valueTotal;
12941
12942 return this._trimAlignValue( valueMouse );
12943 },
12944
12945 _start: function( event, index ) {
12946 var uiHash = {
12947 handle: this.handles[ index ],
12948 value: this.value()
12949 };
12950 if ( this.options.values && this.options.values.length ) {
12951 uiHash.value = this.values( index );
12952 uiHash.values = this.values();
12953 }
12954 return this._trigger( "start", event, uiHash );
12955 },
12956
12957 _slide: function( event, index, newVal ) {
12958 var otherVal,
12959 newValues,
12960 allowed;
12961
12962 if ( this.options.values && this.options.values.length ) {
12963 otherVal = this.values( index ? 0 : 1 );
12964
12965 if ( ( this.options.values.length === 2 && this.options.range === true ) &&
12966 ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
12967 ) {
12968 newVal = otherVal;
12969 }
12970
12971 if ( newVal !== this.values( index ) ) {
12972 newValues = this.values();
12973 newValues[ index ] = newVal;
12974 // A slide can be canceled by returning false from the slide callback
12975 allowed = this._trigger( "slide", event, {
12976 handle: this.handles[ index ],
12977 value: newVal,
12978 values: newValues
12979 } );
12980 otherVal = this.values( index ? 0 : 1 );
12981 if ( allowed !== false ) {
12982 this.values( index, newVal );
12983 }
12984 }
12985 } else {
12986 if ( newVal !== this.value() ) {
12987 // A slide can be canceled by returning false from the slide callback
12988 allowed = this._trigger( "slide", event, {
12989 handle: this.handles[ index ],
12990 value: newVal
12991 } );
12992 if ( allowed !== false ) {
12993 this.value( newVal );
12994 }
12995 }
12996 }
12997 },
12998
12999 _stop: function( event, index ) {
13000 var uiHash = {
13001 handle: this.handles[ index ],
13002 value: this.value()
13003 };
13004 if ( this.options.values && this.options.values.length ) {
13005 uiHash.value = this.values( index );
13006 uiHash.values = this.values();
13007 }
13008
13009 this._trigger( "stop", event, uiHash );
13010 },
13011
13012 _change: function( event, index ) {
13013 if ( !this._keySliding && !this._mouseSliding ) {
13014 var uiHash = {
13015 handle: this.handles[ index ],
13016 value: this.value()
13017 };
13018 if ( this.options.values && this.options.values.length ) {
13019 uiHash.value = this.values( index );
13020 uiHash.values = this.values();
13021 }
13022
13023 //store the last changed value index for reference when handles overlap
13024 this._lastChangedValue = index;
13025
13026 this._trigger( "change", event, uiHash );
13027 }
13028 },
13029
13030 value: function( newValue ) {
13031 if ( arguments.length ) {
13032 this.options.value = this._trimAlignValue( newValue );
13033 this._refreshValue();
13034 this._change( null, 0 );
13035 return;
13036 }
13037
13038 return this._value();
13039 },
13040
13041 values: function( index, newValue ) {
13042 var vals,
13043 newValues,
13044 i;
13045
13046 if ( arguments.length > 1 ) {
13047 this.options.values[ index ] = this._trimAlignValue( newValue );
13048 this._refreshValue();
13049 this._change( null, index );
13050 return;
13051 }
13052
13053 if ( arguments.length ) {
13054 if ( $.isArray( arguments[ 0 ] ) ) {
13055 vals = this.options.values;
13056 newValues = arguments[ 0 ];
13057 for ( i = 0; i < vals.length; i += 1 ) {
13058 vals[ i ] = this._trimAlignValue( newValues[ i ] );
13059 this._change( null, i );
13060 }
13061 this._refreshValue();
13062 } else {
13063 if ( this.options.values && this.options.values.length ) {
13064 return this._values( index );
13065 } else {
13066 return this.value();
13067 }
13068 }
13069 } else {
13070 return this._values();
13071 }
13072 },
13073
13074 _setOption: function( key, value ) {
13075 var i,
13076 valsLength = 0;
13077
13078 if ( key === "range" && this.options.range === true ) {
13079 if ( value === "min" ) {
13080 this.options.value = this._values( 0 );
13081 this.options.values = null;
13082 } else if ( value === "max" ) {
13083 this.options.value = this._values( this.options.values.length-1 );
13084 this.options.values = null;
13085 }
13086 }
13087
13088 if ( $.isArray( this.options.values ) ) {
13089 valsLength = this.options.values.length;
13090 }
13091
13092 $.Widget.prototype._setOption.apply( this, arguments );
13093
13094 switch ( key ) {
13095 case "orientation":
13096 this._detectOrientation();
13097 this.element
13098 .removeClass( "ui-slider-horizontal ui-slider-vertical" )
13099 .addClass( "ui-slider-" + this.orientation );
13100 this._refreshValue();
13101 break;
13102 case "value":
13103 this._animateOff = true;
13104 this._refreshValue();
13105 this._change( null, 0 );
13106 this._animateOff = false;
13107 break;
13108 case "values":
13109 this._animateOff = true;
13110 this._refreshValue();
13111 for ( i = 0; i < valsLength; i += 1 ) {
13112 this._change( null, i );
13113 }
13114 this._animateOff = false;
13115 break;
13116 case "min":
13117 case "max":
13118 this._animateOff = true;
13119 this._refreshValue();
13120 this._animateOff = false;
13121 break;
13122 case "range":
13123 this._animateOff = true;
13124 this._refresh();
13125 this._animateOff = false;
13126 break;
13127 }
13128 },
13129
13130 //internal value getter
13131 // _value() returns value trimmed by min and max, aligned by step
13132 _value: function() {
13133 var val = this.options.value;
13134 val = this._trimAlignValue( val );
13135
13136 return val;
13137 },
13138
13139 //internal values getter
13140 // _values() returns array of values trimmed by min and max, aligned by step
13141 // _values( index ) returns single value trimmed by min and max, aligned by step
13142 _values: function( index ) {
13143 var val,
13144 vals,
13145 i;
13146
13147 if ( arguments.length ) {
13148 val = this.options.values[ index ];
13149 val = this._trimAlignValue( val );
13150
13151 return val;
13152 } else if ( this.options.values && this.options.values.length ) {
13153 // .slice() creates a copy of the array
13154 // this copy gets trimmed by min and max and then returned
13155 vals = this.options.values.slice();
13156 for ( i = 0; i < vals.length; i+= 1) {
13157 vals[ i ] = this._trimAlignValue( vals[ i ] );
13158 }
13159
13160 return vals;
13161 } else {
13162 return [];
13163 }
13164 },
13165
13166 // returns the step-aligned value that val is closest to, between (inclusive) min and max
13167 _trimAlignValue: function( val ) {
13168 if ( val <= this._valueMin() ) {
13169 return this._valueMin();
13170 }
13171 if ( val >= this._valueMax() ) {
13172 return this._valueMax();
13173 }
13174 var step = ( this.options.step > 0 ) ? this.options.step : 1,
13175 valModStep = (val - this._valueMin()) % step,
13176 alignValue = val - valModStep;
13177
13178 if ( Math.abs(valModStep) * 2 >= step ) {
13179 alignValue += ( valModStep > 0 ) ? step : ( -step );
13180 }
13181
13182 // Since JavaScript has problems with large floats, round
13183 // the final value to 5 digits after the decimal point (see #4124)
13184 return parseFloat( alignValue.toFixed(5) );
13185 },
13186
13187 _valueMin: function() {
13188 return this.options.min;
13189 },
13190
13191 _valueMax: function() {
13192 return this.options.max;
13193 },
13194
13195 _refreshValue: function() {
13196 var lastValPercent, valPercent, value, valueMin, valueMax,
13197 oRange = this.options.range,
13198 o = this.options,
13199 that = this,
13200 animate = ( !this._animateOff ) ? o.animate : false,
13201 _set = {};
13202
13203 if ( this.options.values && this.options.values.length ) {
13204 this.handles.each(function( i ) {
13205 valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
13206 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
13207 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
13208 if ( that.options.range === true ) {
13209 if ( that.orientation === "horizontal" ) {
13210 if ( i === 0 ) {
13211 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
13212 }
13213 if ( i === 1 ) {
13214 that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
13215 }
13216 } else {
13217 if ( i === 0 ) {
13218 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
13219 }
13220 if ( i === 1 ) {
13221 that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
13222 }
13223 }
13224 }
13225 lastValPercent = valPercent;
13226 });
13227 } else {
13228 value = this.value();
13229 valueMin = this._valueMin();
13230 valueMax = this._valueMax();
13231 valPercent = ( valueMax !== valueMin ) ?
13232 ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
13233 0;
13234 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
13235 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
13236
13237 if ( oRange === "min" && this.orientation === "horizontal" ) {
13238 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
13239 }
13240 if ( oRange === "max" && this.orientation === "horizontal" ) {
13241 this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
13242 }
13243 if ( oRange === "min" && this.orientation === "vertical" ) {
13244 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
13245 }
13246 if ( oRange === "max" && this.orientation === "vertical" ) {
13247 this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
13248 }
13249 }
13250 },
13251
13252 _handleEvents: {
13253 keydown: function( event ) {
13254 var allowed, curVal, newVal, step,
13255 index = $( event.target ).data( "ui-slider-handle-index" );
13256
13257 switch ( event.keyCode ) {
13258 case $.ui.keyCode.HOME:
13259 case $.ui.keyCode.END:
13260 case $.ui.keyCode.PAGE_UP:
13261 case $.ui.keyCode.PAGE_DOWN:
13262 case $.ui.keyCode.UP:
13263 case $.ui.keyCode.RIGHT:
13264 case $.ui.keyCode.DOWN:
13265 case $.ui.keyCode.LEFT:
13266 event.preventDefault();
13267 if ( !this._keySliding ) {
13268 this._keySliding = true;
13269 $( event.target ).addClass( "ui-state-active" );
13270 allowed = this._start( event, index );
13271 if ( allowed === false ) {
13272 return;
13273 }
13274 }
13275 break;
13276 }
13277
13278 step = this.options.step;
13279 if ( this.options.values && this.options.values.length ) {
13280 curVal = newVal = this.values( index );
13281 } else {
13282 curVal = newVal = this.value();
13283 }
13284
13285 switch ( event.keyCode ) {
13286 case $.ui.keyCode.HOME:
13287 newVal = this._valueMin();
13288 break;
13289 case $.ui.keyCode.END:
13290 newVal = this._valueMax();
13291 break;
13292 case $.ui.keyCode.PAGE_UP:
13293 newVal = this._trimAlignValue( curVal + ( (this._valueMax() - this._valueMin()) / numPages ) );
13294 break;
13295 case $.ui.keyCode.PAGE_DOWN:
13296 newVal = this._trimAlignValue( curVal - ( (this._valueMax() - this._valueMin()) / numPages ) );
13297 break;
13298 case $.ui.keyCode.UP:
13299 case $.ui.keyCode.RIGHT:
13300 if ( curVal === this._valueMax() ) {
13301 return;
13302 }
13303 newVal = this._trimAlignValue( curVal + step );
13304 break;
13305 case $.ui.keyCode.DOWN:
13306 case $.ui.keyCode.LEFT:
13307 if ( curVal === this._valueMin() ) {
13308 return;
13309 }
13310 newVal = this._trimAlignValue( curVal - step );
13311 break;
13312 }
13313
13314 this._slide( event, index, newVal );
13315 },
13316 click: function( event ) {
13317 event.preventDefault();
13318 },
13319 keyup: function( event ) {
13320 var index = $( event.target ).data( "ui-slider-handle-index" );
13321
13322 if ( this._keySliding ) {
13323 this._keySliding = false;
13324 this._stop( event, index );
13325 this._change( event, index );
13326 $( event.target ).removeClass( "ui-state-active" );
13327 }
13328 }
13329 }
13330
13331 });
13332
13333 }(jQuery));
13334
13335 (function( $ ) {
13336
13337 function modifier( fn ) {
13338 return function() {
13339 var previous = this.element.val();
13340 fn.apply( this, arguments );
13341 this._refresh();
13342 if ( previous !== this.element.val() ) {
13343 this._trigger( "change" );
13344 }
13345 };
13346 }
13347
13348 $.widget( "ui.spinner", {
13349 version: "1.10.4",
13350 defaultElement: "<input>",
13351 widgetEventPrefix: "spin",
13352 options: {
13353 culture: null,
13354 icons: {
13355 down: "ui-icon-triangle-1-s",
13356 up: "ui-icon-triangle-1-n"
13357 },
13358 incremental: true,
13359 max: null,
13360 min: null,
13361 numberFormat: null,
13362 page: 10,
13363 step: 1,
13364
13365 change: null,
13366 spin: null,
13367 start: null,
13368 stop: null
13369 },
13370
13371 _create: function() {
13372 // handle string values that need to be parsed
13373 this._setOption( "max", this.options.max );
13374 this._setOption( "min", this.options.min );
13375 this._setOption( "step", this.options.step );
13376
13377 // Only format if there is a value, prevents the field from being marked
13378 // as invalid in Firefox, see #9573.
13379 if ( this.value() !== "" ) {
13380 // Format the value, but don't constrain.
13381 this._value( this.element.val(), true );
13382 }
13383
13384 this._draw();
13385 this._on( this._events );
13386 this._refresh();
13387
13388 // turning off autocomplete prevents the browser from remembering the
13389 // value when navigating through history, so we re-enable autocomplete
13390 // if the page is unloaded before the widget is destroyed. #7790
13391 this._on( this.window, {
13392 beforeunload: function() {
13393 this.element.removeAttr( "autocomplete" );
13394 }
13395 });
13396 },
13397
13398 _getCreateOptions: function() {
13399 var options = {},
13400 element = this.element;
13401
13402 $.each( [ "min", "max", "step" ], function( i, option ) {
13403 var value = element.attr( option );
13404 if ( value !== undefined && value.length ) {
13405 options[ option ] = value;
13406 }
13407 });
13408
13409 return options;
13410 },
13411
13412 _events: {
13413 keydown: function( event ) {
13414 if ( this._start( event ) && this._keydown( event ) ) {
13415 event.preventDefault();
13416 }
13417 },
13418 keyup: "_stop",
13419 focus: function() {
13420 this.previous = this.element.val();
13421 },
13422 blur: function( event ) {
13423 if ( this.cancelBlur ) {
13424 delete this.cancelBlur;
13425 return;
13426 }
13427
13428 this._stop();
13429 this._refresh();
13430 if ( this.previous !== this.element.val() ) {
13431 this._trigger( "change", event );
13432 }
13433 },
13434 mousewheel: function( event, delta ) {
13435 if ( !delta ) {
13436 return;
13437 }
13438 if ( !this.spinning && !this._start( event ) ) {
13439 return false;
13440 }
13441
13442 this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
13443 clearTimeout( this.mousewheelTimer );
13444 this.mousewheelTimer = this._delay(function() {
13445 if ( this.spinning ) {
13446 this._stop( event );
13447 }
13448 }, 100 );
13449 event.preventDefault();
13450 },
13451 "mousedown .ui-spinner-button": function( event ) {
13452 var previous;
13453
13454 // We never want the buttons to have focus; whenever the user is
13455 // interacting with the spinner, the focus should be on the input.
13456 // If the input is focused then this.previous is properly set from
13457 // when the input first received focus. If the input is not focused
13458 // then we need to set this.previous based on the value before spinning.
13459 previous = this.element[0] === this.document[0].activeElement ?
13460 this.previous : this.element.val();
13461 function checkFocus() {
13462 var isActive = this.element[0] === this.document[0].activeElement;
13463 if ( !isActive ) {
13464 this.element.focus();
13465 this.previous = previous;
13466 // support: IE
13467 // IE sets focus asynchronously, so we need to check if focus
13468 // moved off of the input because the user clicked on the button.
13469 this._delay(function() {
13470 this.previous = previous;
13471 });
13472 }
13473 }
13474
13475 // ensure focus is on (or stays on) the text field
13476 event.preventDefault();
13477 checkFocus.call( this );
13478
13479 // support: IE
13480 // IE doesn't prevent moving focus even with event.preventDefault()
13481 // so we set a flag to know when we should ignore the blur event
13482 // and check (again) if focus moved off of the input.
13483 this.cancelBlur = true;
13484 this._delay(function() {
13485 delete this.cancelBlur;
13486 checkFocus.call( this );
13487 });
13488
13489 if ( this._start( event ) === false ) {
13490 return;
13491 }
13492
13493 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
13494 },
13495 "mouseup .ui-spinner-button": "_stop",
13496 "mouseenter .ui-spinner-button": function( event ) {
13497 // button will add ui-state-active if mouse was down while mouseleave and kept down
13498 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
13499 return;
13500 }
13501
13502 if ( this._start( event ) === false ) {
13503 return false;
13504 }
13505 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
13506 },
13507 // TODO: do we really want to consider this a stop?
13508 // shouldn't we just stop the repeater and wait until mouseup before
13509 // we trigger the stop event?
13510 "mouseleave .ui-spinner-button": "_stop"
13511 },
13512
13513 _draw: function() {
13514 var uiSpinner = this.uiSpinner = this.element
13515 .addClass( "ui-spinner-input" )
13516 .attr( "autocomplete", "off" )
13517 .wrap( this._uiSpinnerHtml() )
13518 .parent()
13519 // add buttons
13520 .append( this._buttonHtml() );
13521
13522 this.element.attr( "role", "spinbutton" );
13523
13524 // button bindings
13525 this.buttons = uiSpinner.find( ".ui-spinner-button" )
13526 .attr( "tabIndex", -1 )
13527 .button()
13528 .removeClass( "ui-corner-all" );
13529
13530 // IE 6 doesn't understand height: 50% for the buttons
13531 // unless the wrapper has an explicit height
13532 if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&
13533 uiSpinner.height() > 0 ) {
13534 uiSpinner.height( uiSpinner.height() );
13535 }
13536
13537 // disable spinner if element was already disabled
13538 if ( this.options.disabled ) {
13539 this.disable();
13540 }
13541 },
13542
13543 _keydown: function( event ) {
13544 var options = this.options,
13545 keyCode = $.ui.keyCode;
13546
13547 switch ( event.keyCode ) {
13548 case keyCode.UP:
13549 this._repeat( null, 1, event );
13550 return true;
13551 case keyCode.DOWN:
13552 this._repeat( null, -1, event );
13553 return true;
13554 case keyCode.PAGE_UP:
13555 this._repeat( null, options.page, event );
13556 return true;
13557 case keyCode.PAGE_DOWN:
13558 this._repeat( null, -options.page, event );
13559 return true;
13560 }
13561
13562 return false;
13563 },
13564
13565 _uiSpinnerHtml: function() {
13566 return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>";
13567 },
13568
13569 _buttonHtml: function() {
13570 return "" +
13571 "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" +
13572 "<span class='ui-icon " + this.options.icons.up + "'>&#9650;</span>" +
13573 "</a>" +
13574 "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" +
13575 "<span class='ui-icon " + this.options.icons.down + "'>&#9660;</span>" +
13576 "</a>";
13577 },
13578
13579 _start: function( event ) {
13580 if ( !this.spinning && this._trigger( "start", event ) === false ) {
13581 return false;
13582 }
13583
13584 if ( !this.counter ) {
13585 this.counter = 1;
13586 }
13587 this.spinning = true;
13588 return true;
13589 },
13590
13591 _repeat: function( i, steps, event ) {
13592 i = i || 500;
13593
13594 clearTimeout( this.timer );
13595 this.timer = this._delay(function() {
13596 this._repeat( 40, steps, event );
13597 }, i );
13598
13599 this._spin( steps * this.options.step, event );
13600 },
13601
13602 _spin: function( step, event ) {
13603 var value = this.value() || 0;
13604
13605 if ( !this.counter ) {
13606 this.counter = 1;
13607 }
13608
13609 value = this._adjustValue( value + step * this._increment( this.counter ) );
13610
13611 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) {
13612 this._value( value );
13613 this.counter++;
13614 }
13615 },
13616
13617 _increment: function( i ) {
13618 var incremental = this.options.incremental;
13619
13620 if ( incremental ) {
13621 return $.isFunction( incremental ) ?
13622 incremental( i ) :
13623 Math.floor( i*i*i/50000 - i*i/500 + 17*i/200 + 1 );
13624 }
13625
13626 return 1;
13627 },
13628
13629 _precision: function() {
13630 var precision = this._precisionOf( this.options.step );
13631 if ( this.options.min !== null ) {
13632 precision = Math.max( precision, this._precisionOf( this.options.min ) );
13633 }
13634 return precision;
13635 },
13636
13637 _precisionOf: function( num ) {
13638 var str = num.toString(),
13639 decimal = str.indexOf( "." );
13640 return decimal === -1 ? 0 : str.length - decimal - 1;
13641 },
13642
13643 _adjustValue: function( value ) {
13644 var base, aboveMin,
13645 options = this.options;
13646
13647 // make sure we're at a valid step
13648 // - find out where we are relative to the base (min or 0)
13649 base = options.min !== null ? options.min : 0;
13650 aboveMin = value - base;
13651 // - round to the nearest step
13652 aboveMin = Math.round(aboveMin / options.step) * options.step;
13653 // - rounding is based on 0, so adjust back to our base
13654 value = base + aboveMin;
13655
13656 // fix precision from bad JS floating point math
13657 value = parseFloat( value.toFixed( this._precision() ) );
13658
13659 // clamp the value
13660 if ( options.max !== null && value > options.max) {
13661 return options.max;
13662 }
13663 if ( options.min !== null && value < options.min ) {
13664 return options.min;
13665 }
13666
13667 return value;
13668 },
13669
13670 _stop: function( event ) {
13671 if ( !this.spinning ) {
13672 return;
13673 }
13674
13675 clearTimeout( this.timer );
13676 clearTimeout( this.mousewheelTimer );
13677 this.counter = 0;
13678 this.spinning = false;
13679 this._trigger( "stop", event );
13680 },
13681
13682 _setOption: function( key, value ) {
13683 if ( key === "culture" || key === "numberFormat" ) {
13684 var prevValue = this._parse( this.element.val() );
13685 this.options[ key ] = value;
13686 this.element.val( this._format( prevValue ) );
13687 return;
13688 }
13689
13690 if ( key === "max" || key === "min" || key === "step" ) {
13691 if ( typeof value === "string" ) {
13692 value = this._parse( value );
13693 }
13694 }
13695 if ( key === "icons" ) {
13696 this.buttons.first().find( ".ui-icon" )
13697 .removeClass( this.options.icons.up )
13698 .addClass( value.up );
13699 this.buttons.last().find( ".ui-icon" )
13700 .removeClass( this.options.icons.down )
13701 .addClass( value.down );
13702 }
13703
13704 this._super( key, value );
13705
13706 if ( key === "disabled" ) {
13707 if ( value ) {
13708 this.element.prop( "disabled", true );
13709 this.buttons.button( "disable" );
13710 } else {
13711 this.element.prop( "disabled", false );
13712 this.buttons.button( "enable" );
13713 }
13714 }
13715 },
13716
13717 _setOptions: modifier(function( options ) {
13718 this._super( options );
13719 this._value( this.element.val() );
13720 }),
13721
13722 _parse: function( val ) {
13723 if ( typeof val === "string" && val !== "" ) {
13724 val = window.Globalize && this.options.numberFormat ?
13725 Globalize.parseFloat( val, 10, this.options.culture ) : +val;
13726 }
13727 return val === "" || isNaN( val ) ? null : val;
13728 },
13729
13730 _format: function( value ) {
13731 if ( value === "" ) {
13732 return "";
13733 }
13734 return window.Globalize && this.options.numberFormat ?
13735 Globalize.format( value, this.options.numberFormat, this.options.culture ) :
13736 value;
13737 },
13738
13739 _refresh: function() {
13740 this.element.attr({
13741 "aria-valuemin": this.options.min,
13742 "aria-valuemax": this.options.max,
13743 // TODO: what should we do with values that can't be parsed?
13744 "aria-valuenow": this._parse( this.element.val() )
13745 });
13746 },
13747
13748 // update the value without triggering change
13749 _value: function( value, allowAny ) {
13750 var parsed;
13751 if ( value !== "" ) {
13752 parsed = this._parse( value );
13753 if ( parsed !== null ) {
13754 if ( !allowAny ) {
13755 parsed = this._adjustValue( parsed );
13756 }
13757 value = this._format( parsed );
13758 }
13759 }
13760 this.element.val( value );
13761 this._refresh();
13762 },
13763
13764 _destroy: function() {
13765 this.element
13766 .removeClass( "ui-spinner-input" )
13767 .prop( "disabled", false )
13768 .removeAttr( "autocomplete" )
13769 .removeAttr( "role" )
13770 .removeAttr( "aria-valuemin" )
13771 .removeAttr( "aria-valuemax" )
13772 .removeAttr( "aria-valuenow" );
13773 this.uiSpinner.replaceWith( this.element );
13774 },
13775
13776 stepUp: modifier(function( steps ) {
13777 this._stepUp( steps );
13778 }),
13779 _stepUp: function( steps ) {
13780 if ( this._start() ) {
13781 this._spin( (steps || 1) * this.options.step );
13782 this._stop();
13783 }
13784 },
13785
13786 stepDown: modifier(function( steps ) {
13787 this._stepDown( steps );
13788 }),
13789 _stepDown: function( steps ) {
13790 if ( this._start() ) {
13791 this._spin( (steps || 1) * -this.options.step );
13792 this._stop();
13793 }
13794 },
13795
13796 pageUp: modifier(function( pages ) {
13797 this._stepUp( (pages || 1) * this.options.page );
13798 }),
13799
13800 pageDown: modifier(function( pages ) {
13801 this._stepDown( (pages || 1) * this.options.page );
13802 }),
13803
13804 value: function( newVal ) {
13805 if ( !arguments.length ) {
13806 return this._parse( this.element.val() );
13807 }
13808 modifier( this._value ).call( this, newVal );
13809 },
13810
13811 widget: function() {
13812 return this.uiSpinner;
13813 }
13814 });
13815
13816 }( jQuery ) );
13817
13818 (function( $, undefined ) {
13819
13820 var tabId = 0,
13821 rhash = /#.*$/;
13822
13823 function getNextTabId() {
13824 return ++tabId;
13825 }
13826
13827 function isLocal( anchor ) {
13828 // support: IE7
13829 // IE7 doesn't normalize the href property when set via script (#9317)
13830 anchor = anchor.cloneNode( false );
13831
13832 return anchor.hash.length > 1 &&
13833 decodeURIComponent( anchor.href.replace( rhash, "" ) ) ===
13834 decodeURIComponent( location.href.replace( rhash, "" ) );
13835 }
13836
13837 $.widget( "ui.tabs", {
13838 version: "1.10.4",
13839 delay: 300,
13840 options: {
13841 active: null,
13842 collapsible: false,
13843 event: "click",
13844 heightStyle: "content",
13845 hide: null,
13846 show: null,
13847
13848 // callbacks
13849 activate: null,
13850 beforeActivate: null,
13851 beforeLoad: null,
13852 load: null
13853 },
13854
13855 _create: function() {
13856 var that = this,
13857 options = this.options;
13858
13859 this.running = false;
13860
13861 this.element
13862 .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" )
13863 .toggleClass( "ui-tabs-collapsible", options.collapsible )
13864 // Prevent users from focusing disabled tabs via click
13865 .delegate( ".ui-tabs-nav > li", "mousedown" + this.eventNamespace, function( event ) {
13866 if ( $( this ).is( ".ui-state-disabled" ) ) {
13867 event.preventDefault();
13868 }
13869 })
13870 // support: IE <9
13871 // Preventing the default action in mousedown doesn't prevent IE
13872 // from focusing the element, so if the anchor gets focused, blur.
13873 // We don't have to worry about focusing the previously focused
13874 // element since clicking on a non-focusable element should focus
13875 // the body anyway.
13876 .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() {
13877 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
13878 this.blur();
13879 }
13880 });
13881
13882 this._processTabs();
13883 options.active = this._initialActive();
13884
13885 // Take disabling tabs via class attribute from HTML
13886 // into account and update option properly.
13887 if ( $.isArray( options.disabled ) ) {
13888 options.disabled = $.unique( options.disabled.concat(
13889 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
13890 return that.tabs.index( li );
13891 })
13892 ) ).sort();
13893 }
13894
13895 // check for length avoids error when initializing empty list
13896 if ( this.options.active !== false && this.anchors.length ) {
13897 this.active = this._findActive( options.active );
13898 } else {
13899 this.active = $();
13900 }
13901
13902 this._refresh();
13903
13904 if ( this.active.length ) {
13905 this.load( options.active );
13906 }
13907 },
13908
13909 _initialActive: function() {
13910 var active = this.options.active,
13911 collapsible = this.options.collapsible,
13912 locationHash = location.hash.substring( 1 );
13913
13914 if ( active === null ) {
13915 // check the fragment identifier in the URL
13916 if ( locationHash ) {
13917 this.tabs.each(function( i, tab ) {
13918 if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
13919 active = i;
13920 return false;
13921 }
13922 });
13923 }
13924
13925 // check for a tab marked active via a class
13926 if ( active === null ) {
13927 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
13928 }
13929
13930 // no active tab, set to false
13931 if ( active === null || active === -1 ) {
13932 active = this.tabs.length ? 0 : false;
13933 }
13934 }
13935
13936 // handle numbers: negative, out of range
13937 if ( active !== false ) {
13938 active = this.tabs.index( this.tabs.eq( active ) );
13939 if ( active === -1 ) {
13940 active = collapsible ? false : 0;
13941 }
13942 }
13943
13944 // don't allow collapsible: false and active: false
13945 if ( !collapsible && active === false && this.anchors.length ) {
13946 active = 0;
13947 }
13948
13949 return active;
13950 },
13951
13952 _getCreateEventData: function() {
13953 return {
13954 tab: this.active,
13955 panel: !this.active.length ? $() : this._getPanelForTab( this.active )
13956 };
13957 },
13958
13959 _tabKeydown: function( event ) {
13960 var focusedTab = $( this.document[0].activeElement ).closest( "li" ),
13961 selectedIndex = this.tabs.index( focusedTab ),
13962 goingForward = true;
13963
13964 if ( this._handlePageNav( event ) ) {
13965 return;
13966 }
13967
13968 switch ( event.keyCode ) {
13969 case $.ui.keyCode.RIGHT:
13970 case $.ui.keyCode.DOWN:
13971 selectedIndex++;
13972 break;
13973 case $.ui.keyCode.UP:
13974 case $.ui.keyCode.LEFT:
13975 goingForward = false;
13976 selectedIndex--;
13977 break;
13978 case $.ui.keyCode.END:
13979 selectedIndex = this.anchors.length - 1;
13980 break;
13981 case $.ui.keyCode.HOME:
13982 selectedIndex = 0;
13983 break;
13984 case $.ui.keyCode.SPACE:
13985 // Activate only, no collapsing
13986 event.preventDefault();
13987 clearTimeout( this.activating );
13988 this._activate( selectedIndex );
13989 return;
13990 case $.ui.keyCode.ENTER:
13991 // Toggle (cancel delayed activation, allow collapsing)
13992 event.preventDefault();
13993 clearTimeout( this.activating );
13994 // Determine if we should collapse or activate
13995 this._activate( selectedIndex === this.options.active ? false : selectedIndex );
13996 return;
13997 default:
13998 return;
13999 }
14000
14001 // Focus the appropriate tab, based on which key was pressed
14002 event.preventDefault();
14003 clearTimeout( this.activating );
14004 selectedIndex = this._focusNextTab( selectedIndex, goingForward );
14005
14006 // Navigating with control key will prevent automatic activation
14007 if ( !event.ctrlKey ) {
14008 // Update aria-selected immediately so that AT think the tab is already selected.
14009 // Otherwise AT may confuse the user by stating that they need to activate the tab,
14010 // but the tab will already be activated by the time the announcement finishes.
14011 focusedTab.attr( "aria-selected", "false" );
14012 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
14013
14014 this.activating = this._delay(function() {
14015 this.option( "active", selectedIndex );
14016 }, this.delay );
14017 }
14018 },
14019
14020 _panelKeydown: function( event ) {
14021 if ( this._handlePageNav( event ) ) {
14022 return;
14023 }
14024
14025 // Ctrl+up moves focus to the current tab
14026 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
14027 event.preventDefault();
14028 this.active.focus();
14029 }
14030 },
14031
14032 // Alt+page up/down moves focus to the previous/next tab (and activates)
14033 _handlePageNav: function( event ) {
14034 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
14035 this._activate( this._focusNextTab( this.options.active - 1, false ) );
14036 return true;
14037 }
14038 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
14039 this._activate( this._focusNextTab( this.options.active + 1, true ) );
14040 return true;
14041 }
14042 },
14043
14044 _findNextTab: function( index, goingForward ) {
14045 var lastTabIndex = this.tabs.length - 1;
14046
14047 function constrain() {
14048 if ( index > lastTabIndex ) {
14049 index = 0;
14050 }
14051 if ( index < 0 ) {
14052 index = lastTabIndex;
14053 }
14054 return index;
14055 }
14056
14057 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
14058 index = goingForward ? index + 1 : index - 1;
14059 }
14060
14061 return index;
14062 },
14063
14064 _focusNextTab: function( index, goingForward ) {
14065 index = this._findNextTab( index, goingForward );
14066 this.tabs.eq( index ).focus();
14067 return index;
14068 },
14069
14070 _setOption: function( key, value ) {
14071 if ( key === "active" ) {
14072 // _activate() will handle invalid values and update this.options
14073 this._activate( value );
14074 return;
14075 }
14076
14077 if ( key === "disabled" ) {
14078 // don't use the widget factory's disabled handling
14079 this._setupDisabled( value );
14080 return;
14081 }
14082
14083 this._super( key, value);
14084
14085 if ( key === "collapsible" ) {
14086 this.element.toggleClass( "ui-tabs-collapsible", value );
14087 // Setting collapsible: false while collapsed; open first panel
14088 if ( !value && this.options.active === false ) {
14089 this._activate( 0 );
14090 }
14091 }
14092
14093 if ( key === "event" ) {
14094 this._setupEvents( value );
14095 }
14096
14097 if ( key === "heightStyle" ) {
14098 this._setupHeightStyle( value );
14099 }
14100 },
14101
14102 _tabId: function( tab ) {
14103 return tab.attr( "aria-controls" ) || "ui-tabs-" + getNextTabId();
14104 },
14105
14106 _sanitizeSelector: function( hash ) {
14107 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
14108 },
14109
14110 refresh: function() {
14111 var options = this.options,
14112 lis = this.tablist.children( ":has(a[href])" );
14113
14114 // get disabled tabs from class attribute from HTML
14115 // this will get converted to a boolean if needed in _refresh()
14116 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
14117 return lis.index( tab );
14118 });
14119
14120 this._processTabs();
14121
14122 // was collapsed or no tabs
14123 if ( options.active === false || !this.anchors.length ) {
14124 options.active = false;
14125 this.active = $();
14126 // was active, but active tab is gone
14127 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
14128 // all remaining tabs are disabled
14129 if ( this.tabs.length === options.disabled.length ) {
14130 options.active = false;
14131 this.active = $();
14132 // activate previous tab
14133 } else {
14134 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
14135 }
14136 // was active, active tab still exists
14137 } else {
14138 // make sure active index is correct
14139 options.active = this.tabs.index( this.active );
14140 }
14141
14142 this._refresh();
14143 },
14144
14145 _refresh: function() {
14146 this._setupDisabled( this.options.disabled );
14147 this._setupEvents( this.options.event );
14148 this._setupHeightStyle( this.options.heightStyle );
14149
14150 this.tabs.not( this.active ).attr({
14151 "aria-selected": "false",
14152 tabIndex: -1
14153 });
14154 this.panels.not( this._getPanelForTab( this.active ) )
14155 .hide()
14156 .attr({
14157 "aria-expanded": "false",
14158 "aria-hidden": "true"
14159 });
14160
14161 // Make sure one tab is in the tab order
14162 if ( !this.active.length ) {
14163 this.tabs.eq( 0 ).attr( "tabIndex", 0 );
14164 } else {
14165 this.active
14166 .addClass( "ui-tabs-active ui-state-active" )
14167 .attr({
14168 "aria-selected": "true",
14169 tabIndex: 0
14170 });
14171 this._getPanelForTab( this.active )
14172 .show()
14173 .attr({
14174 "aria-expanded": "true",
14175 "aria-hidden": "false"
14176 });
14177 }
14178 },
14179
14180 _processTabs: function() {
14181 var that = this;
14182
14183 this.tablist = this._getList()
14184 .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
14185 .attr( "role", "tablist" );
14186
14187 this.tabs = this.tablist.find( "> li:has(a[href])" )
14188 .addClass( "ui-state-default ui-corner-top" )
14189 .attr({
14190 role: "tab",
14191 tabIndex: -1
14192 });
14193
14194 this.anchors = this.tabs.map(function() {
14195 return $( "a", this )[ 0 ];
14196 })
14197 .addClass( "ui-tabs-anchor" )
14198 .attr({
14199 role: "presentation",
14200 tabIndex: -1
14201 });
14202
14203 this.panels = $();
14204
14205 this.anchors.each(function( i, anchor ) {
14206 var selector, panel, panelId,
14207 anchorId = $( anchor ).uniqueId().attr( "id" ),
14208 tab = $( anchor ).closest( "li" ),
14209 originalAriaControls = tab.attr( "aria-controls" );
14210
14211 // inline tab
14212 if ( isLocal( anchor ) ) {
14213 selector = anchor.hash;
14214 panel = that.element.find( that._sanitizeSelector( selector ) );
14215 // remote tab
14216 } else {
14217 panelId = that._tabId( tab );
14218 selector = "#" + panelId;
14219 panel = that.element.find( selector );
14220 if ( !panel.length ) {
14221 panel = that._createPanel( panelId );
14222 panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
14223 }
14224 panel.attr( "aria-live", "polite" );
14225 }
14226
14227 if ( panel.length) {
14228 that.panels = that.panels.add( panel );
14229 }
14230 if ( originalAriaControls ) {
14231 tab.data( "ui-tabs-aria-controls", originalAriaControls );
14232 }
14233 tab.attr({
14234 "aria-controls": selector.substring( 1 ),
14235 "aria-labelledby": anchorId
14236 });
14237 panel.attr( "aria-labelledby", anchorId );
14238 });
14239
14240 this.panels
14241 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
14242 .attr( "role", "tabpanel" );
14243 },
14244
14245 // allow overriding how to find the list for rare usage scenarios (#7715)
14246 _getList: function() {
14247 return this.tablist || this.element.find( "ol,ul" ).eq( 0 );
14248 },
14249
14250 _createPanel: function( id ) {
14251 return $( "<div>" )
14252 .attr( "id", id )
14253 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
14254 .data( "ui-tabs-destroy", true );
14255 },
14256
14257 _setupDisabled: function( disabled ) {
14258 if ( $.isArray( disabled ) ) {
14259 if ( !disabled.length ) {
14260 disabled = false;
14261 } else if ( disabled.length === this.anchors.length ) {
14262 disabled = true;
14263 }
14264 }
14265
14266 // disable tabs
14267 for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {
14268 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
14269 $( li )
14270 .addClass( "ui-state-disabled" )
14271 .attr( "aria-disabled", "true" );
14272 } else {
14273 $( li )
14274 .removeClass( "ui-state-disabled" )
14275 .removeAttr( "aria-disabled" );
14276 }
14277 }
14278
14279 this.options.disabled = disabled;
14280 },
14281
14282 _setupEvents: function( event ) {
14283 var events = {
14284 click: function( event ) {
14285 event.preventDefault();
14286 }
14287 };
14288 if ( event ) {
14289 $.each( event.split(" "), function( index, eventName ) {
14290 events[ eventName ] = "_eventHandler";
14291 });
14292 }
14293
14294 this._off( this.anchors.add( this.tabs ).add( this.panels ) );
14295 this._on( this.anchors, events );
14296 this._on( this.tabs, { keydown: "_tabKeydown" } );
14297 this._on( this.panels, { keydown: "_panelKeydown" } );
14298
14299 this._focusable( this.tabs );
14300 this._hoverable( this.tabs );
14301 },
14302
14303 _setupHeightStyle: function( heightStyle ) {
14304 var maxHeight,
14305 parent = this.element.parent();
14306
14307 if ( heightStyle === "fill" ) {
14308 maxHeight = parent.height();
14309 maxHeight -= this.element.outerHeight() - this.element.height();
14310
14311 this.element.siblings( ":visible" ).each(function() {
14312 var elem = $( this ),
14313 position = elem.css( "position" );
14314
14315 if ( position === "absolute" || position === "fixed" ) {
14316 return;
14317 }
14318 maxHeight -= elem.outerHeight( true );
14319 });
14320
14321 this.element.children().not( this.panels ).each(function() {
14322 maxHeight -= $( this ).outerHeight( true );
14323 });
14324
14325 this.panels.each(function() {
14326 $( this ).height( Math.max( 0, maxHeight -
14327 $( this ).innerHeight() + $( this ).height() ) );
14328 })
14329 .css( "overflow", "auto" );
14330 } else if ( heightStyle === "auto" ) {
14331 maxHeight = 0;
14332 this.panels.each(function() {
14333 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
14334 }).height( maxHeight );
14335 }
14336 },
14337
14338 _eventHandler: function( event ) {
14339 var options = this.options,
14340 active = this.active,
14341 anchor = $( event.currentTarget ),
14342 tab = anchor.closest( "li" ),
14343 clickedIsActive = tab[ 0 ] === active[ 0 ],
14344 collapsing = clickedIsActive && options.collapsible,
14345 toShow = collapsing ? $() : this._getPanelForTab( tab ),
14346 toHide = !active.length ? $() : this._getPanelForTab( active ),
14347 eventData = {
14348 oldTab: active,
14349 oldPanel: toHide,
14350 newTab: collapsing ? $() : tab,
14351 newPanel: toShow
14352 };
14353
14354 event.preventDefault();
14355
14356 if ( tab.hasClass( "ui-state-disabled" ) ||
14357 // tab is already loading
14358 tab.hasClass( "ui-tabs-loading" ) ||
14359 // can't switch durning an animation
14360 this.running ||
14361 // click on active header, but not collapsible
14362 ( clickedIsActive && !options.collapsible ) ||
14363 // allow canceling activation
14364 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
14365 return;
14366 }
14367
14368 options.active = collapsing ? false : this.tabs.index( tab );
14369
14370 this.active = clickedIsActive ? $() : tab;
14371 if ( this.xhr ) {
14372 this.xhr.abort();
14373 }
14374
14375 if ( !toHide.length && !toShow.length ) {
14376 $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
14377 }
14378
14379 if ( toShow.length ) {
14380 this.load( this.tabs.index( tab ), event );
14381 }
14382 this._toggle( event, eventData );
14383 },
14384
14385 // handles show/hide for selecting tabs
14386 _toggle: function( event, eventData ) {
14387 var that = this,
14388 toShow = eventData.newPanel,
14389 toHide = eventData.oldPanel;
14390
14391 this.running = true;
14392
14393 function complete() {
14394 that.running = false;
14395 that._trigger( "activate", event, eventData );
14396 }
14397
14398 function show() {
14399 eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
14400
14401 if ( toShow.length && that.options.show ) {
14402 that._show( toShow, that.options.show, complete );
14403 } else {
14404 toShow.show();
14405 complete();
14406 }
14407 }
14408
14409 // start out by hiding, then showing, then completing
14410 if ( toHide.length && this.options.hide ) {
14411 this._hide( toHide, this.options.hide, function() {
14412 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
14413 show();
14414 });
14415 } else {
14416 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
14417 toHide.hide();
14418 show();
14419 }
14420
14421 toHide.attr({
14422 "aria-expanded": "false",
14423 "aria-hidden": "true"
14424 });
14425 eventData.oldTab.attr( "aria-selected", "false" );
14426 // If we're switching tabs, remove the old tab from the tab order.
14427 // If we're opening from collapsed state, remove the previous tab from the tab order.
14428 // If we're collapsing, then keep the collapsing tab in the tab order.
14429 if ( toShow.length && toHide.length ) {
14430 eventData.oldTab.attr( "tabIndex", -1 );
14431 } else if ( toShow.length ) {
14432 this.tabs.filter(function() {
14433 return $( this ).attr( "tabIndex" ) === 0;
14434 })
14435 .attr( "tabIndex", -1 );
14436 }
14437
14438 toShow.attr({
14439 "aria-expanded": "true",
14440 "aria-hidden": "false"
14441 });
14442 eventData.newTab.attr({
14443 "aria-selected": "true",
14444 tabIndex: 0
14445 });
14446 },
14447
14448 _activate: function( index ) {
14449 var anchor,
14450 active = this._findActive( index );
14451
14452 // trying to activate the already active panel
14453 if ( active[ 0 ] === this.active[ 0 ] ) {
14454 return;
14455 }
14456
14457 // trying to collapse, simulate a click on the current active header
14458 if ( !active.length ) {
14459 active = this.active;
14460 }
14461
14462 anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
14463 this._eventHandler({
14464 target: anchor,
14465 currentTarget: anchor,
14466 preventDefault: $.noop
14467 });
14468 },
14469
14470 _findActive: function( index ) {
14471 return index === false ? $() : this.tabs.eq( index );
14472 },
14473
14474 _getIndex: function( index ) {
14475 // meta-function to give users option to provide a href string instead of a numerical index.
14476 if ( typeof index === "string" ) {
14477 index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) );
14478 }
14479
14480 return index;
14481 },
14482
14483 _destroy: function() {
14484 if ( this.xhr ) {
14485 this.xhr.abort();
14486 }
14487
14488 this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" );
14489
14490 this.tablist
14491 .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
14492 .removeAttr( "role" );
14493
14494 this.anchors
14495 .removeClass( "ui-tabs-anchor" )
14496 .removeAttr( "role" )
14497 .removeAttr( "tabIndex" )
14498 .removeUniqueId();
14499
14500 this.tabs.add( this.panels ).each(function() {
14501 if ( $.data( this, "ui-tabs-destroy" ) ) {
14502 $( this ).remove();
14503 } else {
14504 $( this )
14505 .removeClass( "ui-state-default ui-state-active ui-state-disabled " +
14506 "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" )
14507 .removeAttr( "tabIndex" )
14508 .removeAttr( "aria-live" )
14509 .removeAttr( "aria-busy" )
14510 .removeAttr( "aria-selected" )
14511 .removeAttr( "aria-labelledby" )
14512 .removeAttr( "aria-hidden" )
14513 .removeAttr( "aria-expanded" )
14514 .removeAttr( "role" );
14515 }
14516 });
14517
14518 this.tabs.each(function() {
14519 var li = $( this ),
14520 prev = li.data( "ui-tabs-aria-controls" );
14521 if ( prev ) {
14522 li
14523 .attr( "aria-controls", prev )
14524 .removeData( "ui-tabs-aria-controls" );
14525 } else {
14526 li.removeAttr( "aria-controls" );
14527 }
14528 });
14529
14530 this.panels.show();
14531
14532 if ( this.options.heightStyle !== "content" ) {
14533 this.panels.css( "height", "" );
14534 }
14535 },
14536
14537 enable: function( index ) {
14538 var disabled = this.options.disabled;
14539 if ( disabled === false ) {
14540 return;
14541 }
14542
14543 if ( index === undefined ) {
14544 disabled = false;
14545 } else {
14546 index = this._getIndex( index );
14547 if ( $.isArray( disabled ) ) {
14548 disabled = $.map( disabled, function( num ) {
14549 return num !== index ? num : null;
14550 });
14551 } else {
14552 disabled = $.map( this.tabs, function( li, num ) {
14553 return num !== index ? num : null;
14554 });
14555 }
14556 }
14557 this._setupDisabled( disabled );
14558 },
14559
14560 disable: function( index ) {
14561 var disabled = this.options.disabled;
14562 if ( disabled === true ) {
14563 return;
14564 }
14565
14566 if ( index === undefined ) {
14567 disabled = true;
14568 } else {
14569 index = this._getIndex( index );
14570 if ( $.inArray( index, disabled ) !== -1 ) {
14571 return;
14572 }
14573 if ( $.isArray( disabled ) ) {
14574 disabled = $.merge( [ index ], disabled ).sort();
14575 } else {
14576 disabled = [ index ];
14577 }
14578 }
14579 this._setupDisabled( disabled );
14580 },
14581
14582 load: function( index, event ) {
14583 index = this._getIndex( index );
14584 var that = this,
14585 tab = this.tabs.eq( index ),
14586 anchor = tab.find( ".ui-tabs-anchor" ),
14587 panel = this._getPanelForTab( tab ),
14588 eventData = {
14589 tab: tab,
14590 panel: panel
14591 };
14592
14593 // not remote
14594 if ( isLocal( anchor[ 0 ] ) ) {
14595 return;
14596 }
14597
14598 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
14599
14600 // support: jQuery <1.8
14601 // jQuery <1.8 returns false if the request is canceled in beforeSend,
14602 // but as of 1.8, $.ajax() always returns a jqXHR object.
14603 if ( this.xhr && this.xhr.statusText !== "canceled" ) {
14604 tab.addClass( "ui-tabs-loading" );
14605 panel.attr( "aria-busy", "true" );
14606
14607 this.xhr
14608 .success(function( response ) {
14609 // support: jQuery <1.8
14610 // http://bugs.jquery.com/ticket/11778
14611 setTimeout(function() {
14612 panel.html( response );
14613 that._trigger( "load", event, eventData );
14614 }, 1 );
14615 })
14616 .complete(function( jqXHR, status ) {
14617 // support: jQuery <1.8
14618 // http://bugs.jquery.com/ticket/11778
14619 setTimeout(function() {
14620 if ( status === "abort" ) {
14621 that.panels.stop( false, true );
14622 }
14623
14624 tab.removeClass( "ui-tabs-loading" );
14625 panel.removeAttr( "aria-busy" );
14626
14627 if ( jqXHR === that.xhr ) {
14628 delete that.xhr;
14629 }
14630 }, 1 );
14631 });
14632 }
14633 },
14634
14635 _ajaxSettings: function( anchor, event, eventData ) {
14636 var that = this;
14637 return {
14638 url: anchor.attr( "href" ),
14639 beforeSend: function( jqXHR, settings ) {
14640 return that._trigger( "beforeLoad", event,
14641 $.extend( { jqXHR : jqXHR, ajaxSettings: settings }, eventData ) );
14642 }
14643 };
14644 },
14645
14646 _getPanelForTab: function( tab ) {
14647 var id = $( tab ).attr( "aria-controls" );
14648 return this.element.find( this._sanitizeSelector( "#" + id ) );
14649 }
14650 });
14651
14652 })( jQuery );
14653
14654 (function( $ ) {
14655
14656 var increments = 0;
14657
14658 function addDescribedBy( elem, id ) {
14659 var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ );
14660 describedby.push( id );
14661 elem
14662 .data( "ui-tooltip-id", id )
14663 .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
14664 }
14665
14666 function removeDescribedBy( elem ) {
14667 var id = elem.data( "ui-tooltip-id" ),
14668 describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ),
14669 index = $.inArray( id, describedby );
14670 if ( index !== -1 ) {
14671 describedby.splice( index, 1 );
14672 }
14673
14674 elem.removeData( "ui-tooltip-id" );
14675 describedby = $.trim( describedby.join( " " ) );
14676 if ( describedby ) {
14677 elem.attr( "aria-describedby", describedby );
14678 } else {
14679 elem.removeAttr( "aria-describedby" );
14680 }
14681 }
14682
14683 $.widget( "ui.tooltip", {
14684 version: "1.10.4",
14685 options: {
14686 content: function() {
14687 // support: IE<9, Opera in jQuery <1.7
14688 // .text() can't accept undefined, so coerce to a string
14689 var title = $( this ).attr( "title" ) || "";
14690 // Escape title, since we're going from an attribute to raw HTML
14691 return $( "<a>" ).text( title ).html();
14692 },
14693 hide: true,
14694 // Disabled elements have inconsistent behavior across browsers (#8661)
14695 items: "[title]:not([disabled])",
14696 position: {
14697 my: "left top+15",
14698 at: "left bottom",
14699 collision: "flipfit flip"
14700 },
14701 show: true,
14702 tooltipClass: null,
14703 track: false,
14704
14705 // callbacks
14706 close: null,
14707 open: null
14708 },
14709
14710 _create: function() {
14711 this._on({
14712 mouseover: "open",
14713 focusin: "open"
14714 });
14715
14716 // IDs of generated tooltips, needed for destroy
14717 this.tooltips = {};
14718 // IDs of parent tooltips where we removed the title attribute
14719 this.parents = {};
14720
14721 if ( this.options.disabled ) {
14722 this._disable();
14723 }
14724 },
14725
14726 _setOption: function( key, value ) {
14727 var that = this;
14728
14729 if ( key === "disabled" ) {
14730 this[ value ? "_disable" : "_enable" ]();
14731 this.options[ key ] = value;
14732 // disable element style changes
14733 return;
14734 }
14735
14736 this._super( key, value );
14737
14738 if ( key === "content" ) {
14739 $.each( this.tooltips, function( id, element ) {
14740 that._updateContent( element );
14741 });
14742 }
14743 },
14744
14745 _disable: function() {
14746 var that = this;
14747
14748 // close open tooltips
14749 $.each( this.tooltips, function( id, element ) {
14750 var event = $.Event( "blur" );
14751 event.target = event.currentTarget = element[0];
14752 that.close( event, true );
14753 });
14754
14755 // remove title attributes to prevent native tooltips
14756 this.element.find( this.options.items ).addBack().each(function() {
14757 var element = $( this );
14758 if ( element.is( "[title]" ) ) {
14759 element
14760 .data( "ui-tooltip-title", element.attr( "title" ) )
14761 .attr( "title", "" );
14762 }
14763 });
14764 },
14765
14766 _enable: function() {
14767 // restore title attributes
14768 this.element.find( this.options.items ).addBack().each(function() {
14769 var element = $( this );
14770 if ( element.data( "ui-tooltip-title" ) ) {
14771 element.attr( "title", element.data( "ui-tooltip-title" ) );
14772 }
14773 });
14774 },
14775
14776 open: function( event ) {
14777 var that = this,
14778 target = $( event ? event.target : this.element )
14779 // we need closest here due to mouseover bubbling,
14780 // but always pointing at the same event target
14781 .closest( this.options.items );
14782
14783 // No element to show a tooltip for or the tooltip is already open
14784 if ( !target.length || target.data( "ui-tooltip-id" ) ) {
14785 return;
14786 }
14787
14788 if ( target.attr( "title" ) ) {
14789 target.data( "ui-tooltip-title", target.attr( "title" ) );
14790 }
14791
14792 target.data( "ui-tooltip-open", true );
14793
14794 // kill parent tooltips, custom or native, for hover
14795 if ( event && event.type === "mouseover" ) {
14796 target.parents().each(function() {
14797 var parent = $( this ),
14798 blurEvent;
14799 if ( parent.data( "ui-tooltip-open" ) ) {
14800 blurEvent = $.Event( "blur" );
14801 blurEvent.target = blurEvent.currentTarget = this;
14802 that.close( blurEvent, true );
14803 }
14804 if ( parent.attr( "title" ) ) {
14805 parent.uniqueId();
14806 that.parents[ this.id ] = {
14807 element: this,
14808 title: parent.attr( "title" )
14809 };
14810 parent.attr( "title", "" );
14811 }
14812 });
14813 }
14814
14815 this._updateContent( target, event );
14816 },
14817
14818 _updateContent: function( target, event ) {
14819 var content,
14820 contentOption = this.options.content,
14821 that = this,
14822 eventType = event ? event.type : null;
14823
14824 if ( typeof contentOption === "string" ) {
14825 return this._open( event, target, contentOption );
14826 }
14827
14828 content = contentOption.call( target[0], function( response ) {
14829 // ignore async response if tooltip was closed already
14830 if ( !target.data( "ui-tooltip-open" ) ) {
14831 return;
14832 }
14833 // IE may instantly serve a cached response for ajax requests
14834 // delay this call to _open so the other call to _open runs first
14835 that._delay(function() {
14836 // jQuery creates a special event for focusin when it doesn't
14837 // exist natively. To improve performance, the native event
14838 // object is reused and the type is changed. Therefore, we can't
14839 // rely on the type being correct after the event finished
14840 // bubbling, so we set it back to the previous value. (#8740)
14841 if ( event ) {
14842 event.type = eventType;
14843 }
14844 this._open( event, target, response );
14845 });
14846 });
14847 if ( content ) {
14848 this._open( event, target, content );
14849 }
14850 },
14851
14852 _open: function( event, target, content ) {
14853 var tooltip, events, delayedShow,
14854 positionOption = $.extend( {}, this.options.position );
14855
14856 if ( !content ) {
14857 return;
14858 }
14859
14860 // Content can be updated multiple times. If the tooltip already
14861 // exists, then just update the content and bail.
14862 tooltip = this._find( target );
14863 if ( tooltip.length ) {
14864 tooltip.find( ".ui-tooltip-content" ).html( content );
14865 return;
14866 }
14867
14868 // if we have a title, clear it to prevent the native tooltip
14869 // we have to check first to avoid defining a title if none exists
14870 // (we don't want to cause an element to start matching [title])
14871 //
14872 // We use removeAttr only for key events, to allow IE to export the correct
14873 // accessible attributes. For mouse events, set to empty string to avoid
14874 // native tooltip showing up (happens only when removing inside mouseover).
14875 if ( target.is( "[title]" ) ) {
14876 if ( event && event.type === "mouseover" ) {
14877 target.attr( "title", "" );
14878 } else {
14879 target.removeAttr( "title" );
14880 }
14881 }
14882
14883 tooltip = this._tooltip( target );
14884 addDescribedBy( target, tooltip.attr( "id" ) );
14885 tooltip.find( ".ui-tooltip-content" ).html( content );
14886
14887 function position( event ) {
14888 positionOption.of = event;
14889 if ( tooltip.is( ":hidden" ) ) {
14890 return;
14891 }
14892 tooltip.position( positionOption );
14893 }
14894 if ( this.options.track && event && /^mouse/.test( event.type ) ) {
14895 this._on( this.document, {
14896 mousemove: position
14897 });
14898 // trigger once to override element-relative positioning
14899 position( event );
14900 } else {
14901 tooltip.position( $.extend({
14902 of: target
14903 }, this.options.position ) );
14904 }
14905
14906 tooltip.hide();
14907
14908 this._show( tooltip, this.options.show );
14909 // Handle tracking tooltips that are shown with a delay (#8644). As soon
14910 // as the tooltip is visible, position the tooltip using the most recent
14911 // event.
14912 if ( this.options.show && this.options.show.delay ) {
14913 delayedShow = this.delayedShow = setInterval(function() {
14914 if ( tooltip.is( ":visible" ) ) {
14915 position( positionOption.of );
14916 clearInterval( delayedShow );
14917 }
14918 }, $.fx.interval );
14919 }
14920
14921 this._trigger( "open", event, { tooltip: tooltip } );
14922
14923 events = {
14924 keyup: function( event ) {
14925 if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
14926 var fakeEvent = $.Event(event);
14927 fakeEvent.currentTarget = target[0];
14928 this.close( fakeEvent, true );
14929 }
14930 },
14931 remove: function() {
14932 this._removeTooltip( tooltip );
14933 }
14934 };
14935 if ( !event || event.type === "mouseover" ) {
14936 events.mouseleave = "close";
14937 }
14938 if ( !event || event.type === "focusin" ) {
14939 events.focusout = "close";
14940 }
14941 this._on( true, target, events );
14942 },
14943
14944 close: function( event ) {
14945 var that = this,
14946 target = $( event ? event.currentTarget : this.element ),
14947 tooltip = this._find( target );
14948
14949 // disabling closes the tooltip, so we need to track when we're closing
14950 // to avoid an infinite loop in case the tooltip becomes disabled on close
14951 if ( this.closing ) {
14952 return;
14953 }
14954
14955 // Clear the interval for delayed tracking tooltips
14956 clearInterval( this.delayedShow );
14957
14958 // only set title if we had one before (see comment in _open())
14959 if ( target.data( "ui-tooltip-title" ) ) {
14960 target.attr( "title", target.data( "ui-tooltip-title" ) );
14961 }
14962
14963 removeDescribedBy( target );
14964
14965 tooltip.stop( true );
14966 this._hide( tooltip, this.options.hide, function() {
14967 that._removeTooltip( $( this ) );
14968 });
14969
14970 target.removeData( "ui-tooltip-open" );
14971 this._off( target, "mouseleave focusout keyup" );
14972 // Remove 'remove' binding only on delegated targets
14973 if ( target[0] !== this.element[0] ) {
14974 this._off( target, "remove" );
14975 }
14976 this._off( this.document, "mousemove" );
14977
14978 if ( event && event.type === "mouseleave" ) {
14979 $.each( this.parents, function( id, parent ) {
14980 $( parent.element ).attr( "title", parent.title );
14981 delete that.parents[ id ];
14982 });
14983 }
14984
14985 this.closing = true;
14986 this._trigger( "close", event, { tooltip: tooltip } );
14987 this.closing = false;
14988 },
14989
14990 _tooltip: function( element ) {
14991 var id = "ui-tooltip-" + increments++,
14992 tooltip = $( "<div>" )
14993 .attr({
14994 id: id,
14995 role: "tooltip"
14996 })
14997 .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " +
14998 ( this.options.tooltipClass || "" ) );
14999 $( "<div>" )
15000 .addClass( "ui-tooltip-content" )
15001 .appendTo( tooltip );
15002 tooltip.appendTo( this.document[0].body );
15003 this.tooltips[ id ] = element;
15004 return tooltip;
15005 },
15006
15007 _find: function( target ) {
15008 var id = target.data( "ui-tooltip-id" );
15009 return id ? $( "#" + id ) : $();
15010 },
15011
15012 _removeTooltip: function( tooltip ) {
15013 tooltip.remove();
15014 delete this.tooltips[ tooltip.attr( "id" ) ];
15015 },
15016
15017 _destroy: function() {
15018 var that = this;
15019
15020 // close open tooltips
15021 $.each( this.tooltips, function( id, element ) {
15022 // Delegate to close method to handle common cleanup
15023 var event = $.Event( "blur" );
15024 event.target = event.currentTarget = element[0];
15025 that.close( event, true );
15026
15027 // Remove immediately; destroying an open tooltip doesn't use the
15028 // hide animation
15029 $( "#" + id ).remove();
15030
15031 // Restore the title
15032 if ( element.data( "ui-tooltip-title" ) ) {
15033 element.attr( "title", element.data( "ui-tooltip-title" ) );
15034 element.removeData( "ui-tooltip-title" );
15035 }
15036 });
15037 }
15038 });
15039
15040 }( jQuery ) );