blob: b5e8d2e15c2a7fba1b8aac0fd9b64850d50fa5db [file] [log] [blame]
Alison Craig1aced7d2015-04-10 12:00:02 -06001/*! jQuery UI - v1.10.1 - 2013-02-15
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 2013 jQuery Foundation and other contributors; Licensed MIT */
5
6(function( $, undefined ) {
7
8var uuid = 0,
9 runiqueId = /^ui-id-\d+$/;
10
11// prevent duplicate loading
12// this is only a problem because we proxy existing functions
13// and we don't want to double proxy them
14$.ui = $.ui || {};
15if ( $.ui.version ) {
16 return;
17}
18
19$.extend( $.ui, {
20 version: "1.10.1",
21
22 keyCode: {
23 BACKSPACE: 8,
24 COMMA: 188,
25 DELETE: 46,
26 DOWN: 40,
27 END: 35,
28 ENTER: 13,
29 ESCAPE: 27,
30 HOME: 36,
31 LEFT: 37,
32 NUMPAD_ADD: 107,
33 NUMPAD_DECIMAL: 110,
34 NUMPAD_DIVIDE: 111,
35 NUMPAD_ENTER: 108,
36 NUMPAD_MULTIPLY: 106,
37 NUMPAD_SUBTRACT: 109,
38 PAGE_DOWN: 34,
39 PAGE_UP: 33,
40 PERIOD: 190,
41 RIGHT: 39,
42 SPACE: 32,
43 TAB: 9,
44 UP: 38
45 }
46});
47
48// plugins
49$.fn.extend({
50 _focus: $.fn.focus,
51 focus: function( delay, fn ) {
52 return typeof delay === "number" ?
53 this.each(function() {
54 var elem = this;
55 setTimeout(function() {
56 $( elem ).focus();
57 if ( fn ) {
58 fn.call( elem );
59 }
60 }, delay );
61 }) :
62 this._focus.apply( this, arguments );
63 },
64
65 scrollParent: function() {
66 var scrollParent;
67 if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) {
68 scrollParent = this.parents().filter(function() {
69 return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
70 }).eq(0);
71 } else {
72 scrollParent = this.parents().filter(function() {
73 return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
74 }).eq(0);
75 }
76
77 return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent;
78 },
79
80 zIndex: function( zIndex ) {
81 if ( zIndex !== undefined ) {
82 return this.css( "zIndex", zIndex );
83 }
84
85 if ( this.length ) {
86 var elem = $( this[ 0 ] ), position, value;
87 while ( elem.length && elem[ 0 ] !== document ) {
88 // Ignore z-index if position is set to a value where z-index is ignored by the browser
89 // This makes behavior of this function consistent across browsers
90 // WebKit always returns auto if the element is positioned
91 position = elem.css( "position" );
92 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
93 // IE returns 0 when zIndex is not specified
94 // other browsers return a string
95 // we ignore the case of nested elements with an explicit value of 0
96 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
97 value = parseInt( elem.css( "zIndex" ), 10 );
98 if ( !isNaN( value ) && value !== 0 ) {
99 return value;
100 }
101 }
102 elem = elem.parent();
103 }
104 }
105
106 return 0;
107 },
108
109 uniqueId: function() {
110 return this.each(function() {
111 if ( !this.id ) {
112 this.id = "ui-id-" + (++uuid);
113 }
114 });
115 },
116
117 removeUniqueId: function() {
118 return this.each(function() {
119 if ( runiqueId.test( this.id ) ) {
120 $( this ).removeAttr( "id" );
121 }
122 });
123 }
124});
125
126// selectors
127function focusable( element, isTabIndexNotNaN ) {
128 var map, mapName, img,
129 nodeName = element.nodeName.toLowerCase();
130 if ( "area" === nodeName ) {
131 map = element.parentNode;
132 mapName = map.name;
133 if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
134 return false;
135 }
136 img = $( "img[usemap=#" + mapName + "]" )[0];
137 return !!img && visible( img );
138 }
139 return ( /input|select|textarea|button|object/.test( nodeName ) ?
140 !element.disabled :
141 "a" === nodeName ?
142 element.href || isTabIndexNotNaN :
143 isTabIndexNotNaN) &&
144 // the element and all of its ancestors must be visible
145 visible( element );
146}
147
148function visible( element ) {
149 return $.expr.filters.visible( element ) &&
150 !$( element ).parents().addBack().filter(function() {
151 return $.css( this, "visibility" ) === "hidden";
152 }).length;
153}
154
155$.extend( $.expr[ ":" ], {
156 data: $.expr.createPseudo ?
157 $.expr.createPseudo(function( dataName ) {
158 return function( elem ) {
159 return !!$.data( elem, dataName );
160 };
161 }) :
162 // support: jQuery <1.8
163 function( elem, i, match ) {
164 return !!$.data( elem, match[ 3 ] );
165 },
166
167 focusable: function( element ) {
168 return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
169 },
170
171 tabbable: function( element ) {
172 var tabIndex = $.attr( element, "tabindex" ),
173 isTabIndexNaN = isNaN( tabIndex );
174 return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
175 }
176});
177
178// support: jQuery <1.8
179if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
180 $.each( [ "Width", "Height" ], function( i, name ) {
181 var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
182 type = name.toLowerCase(),
183 orig = {
184 innerWidth: $.fn.innerWidth,
185 innerHeight: $.fn.innerHeight,
186 outerWidth: $.fn.outerWidth,
187 outerHeight: $.fn.outerHeight
188 };
189
190 function reduce( elem, size, border, margin ) {
191 $.each( side, function() {
192 size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
193 if ( border ) {
194 size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
195 }
196 if ( margin ) {
197 size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
198 }
199 });
200 return size;
201 }
202
203 $.fn[ "inner" + name ] = function( size ) {
204 if ( size === undefined ) {
205 return orig[ "inner" + name ].call( this );
206 }
207
208 return this.each(function() {
209 $( this ).css( type, reduce( this, size ) + "px" );
210 });
211 };
212
213 $.fn[ "outer" + name] = function( size, margin ) {
214 if ( typeof size !== "number" ) {
215 return orig[ "outer" + name ].call( this, size );
216 }
217
218 return this.each(function() {
219 $( this).css( type, reduce( this, size, true, margin ) + "px" );
220 });
221 };
222 });
223}
224
225// support: jQuery <1.8
226if ( !$.fn.addBack ) {
227 $.fn.addBack = function( selector ) {
228 return this.add( selector == null ?
229 this.prevObject : this.prevObject.filter( selector )
230 );
231 };
232}
233
234// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
235if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
236 $.fn.removeData = (function( removeData ) {
237 return function( key ) {
238 if ( arguments.length ) {
239 return removeData.call( this, $.camelCase( key ) );
240 } else {
241 return removeData.call( this );
242 }
243 };
244 })( $.fn.removeData );
245}
246
247
248
249
250
251// deprecated
252$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
253
254$.support.selectstart = "onselectstart" in document.createElement( "div" );
255$.fn.extend({
256 disableSelection: function() {
257 return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
258 ".ui-disableSelection", function( event ) {
259 event.preventDefault();
260 });
261 },
262
263 enableSelection: function() {
264 return this.unbind( ".ui-disableSelection" );
265 }
266});
267
268$.extend( $.ui, {
269 // $.ui.plugin is deprecated. Use the proxy pattern instead.
270 plugin: {
271 add: function( module, option, set ) {
272 var i,
273 proto = $.ui[ module ].prototype;
274 for ( i in set ) {
275 proto.plugins[ i ] = proto.plugins[ i ] || [];
276 proto.plugins[ i ].push( [ option, set[ i ] ] );
277 }
278 },
279 call: function( instance, name, args ) {
280 var i,
281 set = instance.plugins[ name ];
282 if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) {
283 return;
284 }
285
286 for ( i = 0; i < set.length; i++ ) {
287 if ( instance.options[ set[ i ][ 0 ] ] ) {
288 set[ i ][ 1 ].apply( instance.element, args );
289 }
290 }
291 }
292 },
293
294 // only used by resizable
295 hasScroll: function( el, a ) {
296
297 //If overflow is hidden, the element might have extra content, but the user wants to hide it
298 if ( $( el ).css( "overflow" ) === "hidden") {
299 return false;
300 }
301
302 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
303 has = false;
304
305 if ( el[ scroll ] > 0 ) {
306 return true;
307 }
308
309 // TODO: determine which cases actually cause this to happen
310 // if the element doesn't have the scroll set, see if it's possible to
311 // set the scroll
312 el[ scroll ] = 1;
313 has = ( el[ scroll ] > 0 );
314 el[ scroll ] = 0;
315 return has;
316 }
317});
318
319})( jQuery );
320
321(function( $, undefined ) {
322
323var uuid = 0,
324 slice = Array.prototype.slice,
325 _cleanData = $.cleanData;
326$.cleanData = function( elems ) {
327 for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
328 try {
329 $( elem ).triggerHandler( "remove" );
330 // http://bugs.jquery.com/ticket/8235
331 } catch( e ) {}
332 }
333 _cleanData( elems );
334};
335
336$.widget = function( name, base, prototype ) {
337 var fullName, existingConstructor, constructor, basePrototype,
338 // proxiedPrototype allows the provided prototype to remain unmodified
339 // so that it can be used as a mixin for multiple widgets (#8876)
340 proxiedPrototype = {},
341 namespace = name.split( "." )[ 0 ];
342
343 name = name.split( "." )[ 1 ];
344 fullName = namespace + "-" + name;
345
346 if ( !prototype ) {
347 prototype = base;
348 base = $.Widget;
349 }
350
351 // create selector for plugin
352 $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
353 return !!$.data( elem, fullName );
354 };
355
356 $[ namespace ] = $[ namespace ] || {};
357 existingConstructor = $[ namespace ][ name ];
358 constructor = $[ namespace ][ name ] = function( options, element ) {
359 // allow instantiation without "new" keyword
360 if ( !this._createWidget ) {
361 return new constructor( options, element );
362 }
363
364 // allow instantiation without initializing for simple inheritance
365 // must use "new" keyword (the code above always passes args)
366 if ( arguments.length ) {
367 this._createWidget( options, element );
368 }
369 };
370 // extend with the existing constructor to carry over any static properties
371 $.extend( constructor, existingConstructor, {
372 version: prototype.version,
373 // copy the object used to create the prototype in case we need to
374 // redefine the widget later
375 _proto: $.extend( {}, prototype ),
376 // track widgets that inherit from this widget in case this widget is
377 // redefined after a widget inherits from it
378 _childConstructors: []
379 });
380
381 basePrototype = new base();
382 // we need to make the options hash a property directly on the new instance
383 // otherwise we'll modify the options hash on the prototype that we're
384 // inheriting from
385 basePrototype.options = $.widget.extend( {}, basePrototype.options );
386 $.each( prototype, function( prop, value ) {
387 if ( !$.isFunction( value ) ) {
388 proxiedPrototype[ prop ] = value;
389 return;
390 }
391 proxiedPrototype[ prop ] = (function() {
392 var _super = function() {
393 return base.prototype[ prop ].apply( this, arguments );
394 },
395 _superApply = function( args ) {
396 return base.prototype[ prop ].apply( this, args );
397 };
398 return function() {
399 var __super = this._super,
400 __superApply = this._superApply,
401 returnValue;
402
403 this._super = _super;
404 this._superApply = _superApply;
405
406 returnValue = value.apply( this, arguments );
407
408 this._super = __super;
409 this._superApply = __superApply;
410
411 return returnValue;
412 };
413 })();
414 });
415 constructor.prototype = $.widget.extend( basePrototype, {
416 // TODO: remove support for widgetEventPrefix
417 // always use the name + a colon as the prefix, e.g., draggable:start
418 // don't prefix for widgets that aren't DOM-based
419 widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name
420 }, proxiedPrototype, {
421 constructor: constructor,
422 namespace: namespace,
423 widgetName: name,
424 widgetFullName: fullName
425 });
426
427 // If this widget is being redefined then we need to find all widgets that
428 // are inheriting from it and redefine all of them so that they inherit from
429 // the new version of this widget. We're essentially trying to replace one
430 // level in the prototype chain.
431 if ( existingConstructor ) {
432 $.each( existingConstructor._childConstructors, function( i, child ) {
433 var childPrototype = child.prototype;
434
435 // redefine the child widget using the same prototype that was
436 // originally used, but inherit from the new version of the base
437 $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
438 });
439 // remove the list of existing child constructors from the old constructor
440 // so the old child constructors can be garbage collected
441 delete existingConstructor._childConstructors;
442 } else {
443 base._childConstructors.push( constructor );
444 }
445
446 $.widget.bridge( name, constructor );
447};
448
449$.widget.extend = function( target ) {
450 var input = slice.call( arguments, 1 ),
451 inputIndex = 0,
452 inputLength = input.length,
453 key,
454 value;
455 for ( ; inputIndex < inputLength; inputIndex++ ) {
456 for ( key in input[ inputIndex ] ) {
457 value = input[ inputIndex ][ key ];
458 if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
459 // Clone objects
460 if ( $.isPlainObject( value ) ) {
461 target[ key ] = $.isPlainObject( target[ key ] ) ?
462 $.widget.extend( {}, target[ key ], value ) :
463 // Don't extend strings, arrays, etc. with objects
464 $.widget.extend( {}, value );
465 // Copy everything else by reference
466 } else {
467 target[ key ] = value;
468 }
469 }
470 }
471 }
472 return target;
473};
474
475$.widget.bridge = function( name, object ) {
476 var fullName = object.prototype.widgetFullName || name;
477 $.fn[ name ] = function( options ) {
478 var isMethodCall = typeof options === "string",
479 args = slice.call( arguments, 1 ),
480 returnValue = this;
481
482 // allow multiple hashes to be passed on init
483 options = !isMethodCall && args.length ?
484 $.widget.extend.apply( null, [ options ].concat(args) ) :
485 options;
486
487 if ( isMethodCall ) {
488 this.each(function() {
489 var methodValue,
490 instance = $.data( this, fullName );
491 if ( !instance ) {
492 return $.error( "cannot call methods on " + name + " prior to initialization; " +
493 "attempted to call method '" + options + "'" );
494 }
495 if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
496 return $.error( "no such method '" + options + "' for " + name + " widget instance" );
497 }
498 methodValue = instance[ options ].apply( instance, args );
499 if ( methodValue !== instance && methodValue !== undefined ) {
500 returnValue = methodValue && methodValue.jquery ?
501 returnValue.pushStack( methodValue.get() ) :
502 methodValue;
503 return false;
504 }
505 });
506 } else {
507 this.each(function() {
508 var instance = $.data( this, fullName );
509 if ( instance ) {
510 instance.option( options || {} )._init();
511 } else {
512 $.data( this, fullName, new object( options, this ) );
513 }
514 });
515 }
516
517 return returnValue;
518 };
519};
520
521$.Widget = function( /* options, element */ ) {};
522$.Widget._childConstructors = [];
523
524$.Widget.prototype = {
525 widgetName: "widget",
526 widgetEventPrefix: "",
527 defaultElement: "<div>",
528 options: {
529 disabled: false,
530
531 // callbacks
532 create: null
533 },
534 _createWidget: function( options, element ) {
535 element = $( element || this.defaultElement || this )[ 0 ];
536 this.element = $( element );
537 this.uuid = uuid++;
538 this.eventNamespace = "." + this.widgetName + this.uuid;
539 this.options = $.widget.extend( {},
540 this.options,
541 this._getCreateOptions(),
542 options );
543
544 this.bindings = $();
545 this.hoverable = $();
546 this.focusable = $();
547
548 if ( element !== this ) {
549 $.data( element, this.widgetFullName, this );
550 this._on( true, this.element, {
551 remove: function( event ) {
552 if ( event.target === element ) {
553 this.destroy();
554 }
555 }
556 });
557 this.document = $( element.style ?
558 // element within the document
559 element.ownerDocument :
560 // element is window or document
561 element.document || element );
562 this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
563 }
564
565 this._create();
566 this._trigger( "create", null, this._getCreateEventData() );
567 this._init();
568 },
569 _getCreateOptions: $.noop,
570 _getCreateEventData: $.noop,
571 _create: $.noop,
572 _init: $.noop,
573
574 destroy: function() {
575 this._destroy();
576 // we can probably remove the unbind calls in 2.0
577 // all event bindings should go through this._on()
578 this.element
579 .unbind( this.eventNamespace )
580 // 1.9 BC for #7810
581 // TODO remove dual storage
582 .removeData( this.widgetName )
583 .removeData( this.widgetFullName )
584 // support: jquery <1.6.3
585 // http://bugs.jquery.com/ticket/9413
586 .removeData( $.camelCase( this.widgetFullName ) );
587 this.widget()
588 .unbind( this.eventNamespace )
589 .removeAttr( "aria-disabled" )
590 .removeClass(
591 this.widgetFullName + "-disabled " +
592 "ui-state-disabled" );
593
594 // clean up events and states
595 this.bindings.unbind( this.eventNamespace );
596 this.hoverable.removeClass( "ui-state-hover" );
597 this.focusable.removeClass( "ui-state-focus" );
598 },
599 _destroy: $.noop,
600
601 widget: function() {
602 return this.element;
603 },
604
605 option: function( key, value ) {
606 var options = key,
607 parts,
608 curOption,
609 i;
610
611 if ( arguments.length === 0 ) {
612 // don't return a reference to the internal hash
613 return $.widget.extend( {}, this.options );
614 }
615
616 if ( typeof key === "string" ) {
617 // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
618 options = {};
619 parts = key.split( "." );
620 key = parts.shift();
621 if ( parts.length ) {
622 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
623 for ( i = 0; i < parts.length - 1; i++ ) {
624 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
625 curOption = curOption[ parts[ i ] ];
626 }
627 key = parts.pop();
628 if ( value === undefined ) {
629 return curOption[ key ] === undefined ? null : curOption[ key ];
630 }
631 curOption[ key ] = value;
632 } else {
633 if ( value === undefined ) {
634 return this.options[ key ] === undefined ? null : this.options[ key ];
635 }
636 options[ key ] = value;
637 }
638 }
639
640 this._setOptions( options );
641
642 return this;
643 },
644 _setOptions: function( options ) {
645 var key;
646
647 for ( key in options ) {
648 this._setOption( key, options[ key ] );
649 }
650
651 return this;
652 },
653 _setOption: function( key, value ) {
654 this.options[ key ] = value;
655
656 if ( key === "disabled" ) {
657 this.widget()
658 .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value )
659 .attr( "aria-disabled", value );
660 this.hoverable.removeClass( "ui-state-hover" );
661 this.focusable.removeClass( "ui-state-focus" );
662 }
663
664 return this;
665 },
666
667 enable: function() {
668 return this._setOption( "disabled", false );
669 },
670 disable: function() {
671 return this._setOption( "disabled", true );
672 },
673
674 _on: function( suppressDisabledCheck, element, handlers ) {
675 var delegateElement,
676 instance = this;
677
678 // no suppressDisabledCheck flag, shuffle arguments
679 if ( typeof suppressDisabledCheck !== "boolean" ) {
680 handlers = element;
681 element = suppressDisabledCheck;
682 suppressDisabledCheck = false;
683 }
684
685 // no element argument, shuffle and use this.element
686 if ( !handlers ) {
687 handlers = element;
688 element = this.element;
689 delegateElement = this.widget();
690 } else {
691 // accept selectors, DOM elements
692 element = delegateElement = $( element );
693 this.bindings = this.bindings.add( element );
694 }
695
696 $.each( handlers, function( event, handler ) {
697 function handlerProxy() {
698 // allow widgets to customize the disabled handling
699 // - disabled as an array instead of boolean
700 // - disabled class as method for disabling individual parts
701 if ( !suppressDisabledCheck &&
702 ( instance.options.disabled === true ||
703 $( this ).hasClass( "ui-state-disabled" ) ) ) {
704 return;
705 }
706 return ( typeof handler === "string" ? instance[ handler ] : handler )
707 .apply( instance, arguments );
708 }
709
710 // copy the guid so direct unbinding works
711 if ( typeof handler !== "string" ) {
712 handlerProxy.guid = handler.guid =
713 handler.guid || handlerProxy.guid || $.guid++;
714 }
715
716 var match = event.match( /^(\w+)\s*(.*)$/ ),
717 eventName = match[1] + instance.eventNamespace,
718 selector = match[2];
719 if ( selector ) {
720 delegateElement.delegate( selector, eventName, handlerProxy );
721 } else {
722 element.bind( eventName, handlerProxy );
723 }
724 });
725 },
726
727 _off: function( element, eventName ) {
728 eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
729 element.unbind( eventName ).undelegate( eventName );
730 },
731
732 _delay: function( handler, delay ) {
733 function handlerProxy() {
734 return ( typeof handler === "string" ? instance[ handler ] : handler )
735 .apply( instance, arguments );
736 }
737 var instance = this;
738 return setTimeout( handlerProxy, delay || 0 );
739 },
740
741 _hoverable: function( element ) {
742 this.hoverable = this.hoverable.add( element );
743 this._on( element, {
744 mouseenter: function( event ) {
745 $( event.currentTarget ).addClass( "ui-state-hover" );
746 },
747 mouseleave: function( event ) {
748 $( event.currentTarget ).removeClass( "ui-state-hover" );
749 }
750 });
751 },
752
753 _focusable: function( element ) {
754 this.focusable = this.focusable.add( element );
755 this._on( element, {
756 focusin: function( event ) {
757 $( event.currentTarget ).addClass( "ui-state-focus" );
758 },
759 focusout: function( event ) {
760 $( event.currentTarget ).removeClass( "ui-state-focus" );
761 }
762 });
763 },
764
765 _trigger: function( type, event, data ) {
766 var prop, orig,
767 callback = this.options[ type ];
768
769 data = data || {};
770 event = $.Event( event );
771 event.type = ( type === this.widgetEventPrefix ?
772 type :
773 this.widgetEventPrefix + type ).toLowerCase();
774 // the original event may come from any element
775 // so we need to reset the target on the new event
776 event.target = this.element[ 0 ];
777
778 // copy original event properties over to the new event
779 orig = event.originalEvent;
780 if ( orig ) {
781 for ( prop in orig ) {
782 if ( !( prop in event ) ) {
783 event[ prop ] = orig[ prop ];
784 }
785 }
786 }
787
788 this.element.trigger( event, data );
789 return !( $.isFunction( callback ) &&
790 callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
791 event.isDefaultPrevented() );
792 }
793};
794
795$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
796 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
797 if ( typeof options === "string" ) {
798 options = { effect: options };
799 }
800 var hasOptions,
801 effectName = !options ?
802 method :
803 options === true || typeof options === "number" ?
804 defaultEffect :
805 options.effect || defaultEffect;
806 options = options || {};
807 if ( typeof options === "number" ) {
808 options = { duration: options };
809 }
810 hasOptions = !$.isEmptyObject( options );
811 options.complete = callback;
812 if ( options.delay ) {
813 element.delay( options.delay );
814 }
815 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
816 element[ method ]( options );
817 } else if ( effectName !== method && element[ effectName ] ) {
818 element[ effectName ]( options.duration, options.easing, callback );
819 } else {
820 element.queue(function( next ) {
821 $( this )[ method ]();
822 if ( callback ) {
823 callback.call( element[ 0 ] );
824 }
825 next();
826 });
827 }
828 };
829});
830
831})( jQuery );
832
833(function( $, undefined ) {
834
835var mouseHandled = false;
836$( document ).mouseup( function() {
837 mouseHandled = false;
838});
839
840$.widget("ui.mouse", {
841 version: "1.10.1",
842 options: {
843 cancel: "input,textarea,button,select,option",
844 distance: 1,
845 delay: 0
846 },
847 _mouseInit: function() {
848 var that = this;
849
850 this.element
851 .bind("mousedown."+this.widgetName, function(event) {
852 return that._mouseDown(event);
853 })
854 .bind("click."+this.widgetName, function(event) {
855 if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) {
856 $.removeData(event.target, that.widgetName + ".preventClickEvent");
857 event.stopImmediatePropagation();
858 return false;
859 }
860 });
861
862 this.started = false;
863 },
864
865 // TODO: make sure destroying one instance of mouse doesn't mess with
866 // other instances of mouse
867 _mouseDestroy: function() {
868 this.element.unbind("."+this.widgetName);
869 if ( this._mouseMoveDelegate ) {
870 $(document)
871 .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate)
872 .unbind("mouseup."+this.widgetName, this._mouseUpDelegate);
873 }
874 },
875
876 _mouseDown: function(event) {
877 // don't let more than one widget handle mouseStart
878 if( mouseHandled ) { return; }
879
880 // we may have missed mouseup (out of window)
881 (this._mouseStarted && this._mouseUp(event));
882
883 this._mouseDownEvent = event;
884
885 var that = this,
886 btnIsLeft = (event.which === 1),
887 // event.target.nodeName works around a bug in IE 8 with
888 // disabled inputs (#7620)
889 elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
890 if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
891 return true;
892 }
893
894 this.mouseDelayMet = !this.options.delay;
895 if (!this.mouseDelayMet) {
896 this._mouseDelayTimer = setTimeout(function() {
897 that.mouseDelayMet = true;
898 }, this.options.delay);
899 }
900
901 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
902 this._mouseStarted = (this._mouseStart(event) !== false);
903 if (!this._mouseStarted) {
904 event.preventDefault();
905 return true;
906 }
907 }
908
909 // Click event may never have fired (Gecko & Opera)
910 if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) {
911 $.removeData(event.target, this.widgetName + ".preventClickEvent");
912 }
913
914 // these delegates are required to keep context
915 this._mouseMoveDelegate = function(event) {
916 return that._mouseMove(event);
917 };
918 this._mouseUpDelegate = function(event) {
919 return that._mouseUp(event);
920 };
921 $(document)
922 .bind("mousemove."+this.widgetName, this._mouseMoveDelegate)
923 .bind("mouseup."+this.widgetName, this._mouseUpDelegate);
924
925 event.preventDefault();
926
927 mouseHandled = true;
928 return true;
929 },
930
931 _mouseMove: function(event) {
932 // IE mouseup check - mouseup happened when mouse was out of window
933 if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) {
934 return this._mouseUp(event);
935 }
936
937 if (this._mouseStarted) {
938 this._mouseDrag(event);
939 return event.preventDefault();
940 }
941
942 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
943 this._mouseStarted =
944 (this._mouseStart(this._mouseDownEvent, event) !== false);
945 (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
946 }
947
948 return !this._mouseStarted;
949 },
950
951 _mouseUp: function(event) {
952 $(document)
953 .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate)
954 .unbind("mouseup."+this.widgetName, this._mouseUpDelegate);
955
956 if (this._mouseStarted) {
957 this._mouseStarted = false;
958
959 if (event.target === this._mouseDownEvent.target) {
960 $.data(event.target, this.widgetName + ".preventClickEvent", true);
961 }
962
963 this._mouseStop(event);
964 }
965
966 return false;
967 },
968
969 _mouseDistanceMet: function(event) {
970 return (Math.max(
971 Math.abs(this._mouseDownEvent.pageX - event.pageX),
972 Math.abs(this._mouseDownEvent.pageY - event.pageY)
973 ) >= this.options.distance
974 );
975 },
976
977 _mouseDelayMet: function(/* event */) {
978 return this.mouseDelayMet;
979 },
980
981 // These are placeholder methods, to be overriden by extending plugin
982 _mouseStart: function(/* event */) {},
983 _mouseDrag: function(/* event */) {},
984 _mouseStop: function(/* event */) {},
985 _mouseCapture: function(/* event */) { return true; }
986});
987
988})(jQuery);
989
990(function( $, undefined ) {
991
992$.widget("ui.draggable", $.ui.mouse, {
993 version: "1.10.1",
994 widgetEventPrefix: "drag",
995 options: {
996 addClasses: true,
997 appendTo: "parent",
998 axis: false,
999 connectToSortable: false,
1000 containment: false,
1001 cursor: "auto",
1002 cursorAt: false,
1003 grid: false,
1004 handle: false,
1005 helper: "original",
1006 iframeFix: false,
1007 opacity: false,
1008 refreshPositions: false,
1009 revert: false,
1010 revertDuration: 500,
1011 scope: "default",
1012 scroll: true,
1013 scrollSensitivity: 20,
1014 scrollSpeed: 20,
1015 snap: false,
1016 snapMode: "both",
1017 snapTolerance: 20,
1018 stack: false,
1019 zIndex: false,
1020
1021 // callbacks
1022 drag: null,
1023 start: null,
1024 stop: null
1025 },
1026 _create: function() {
1027
1028 if (this.options.helper === "original" && !(/^(?:r|a|f)/).test(this.element.css("position"))) {
1029 this.element[0].style.position = "relative";
1030 }
1031 if (this.options.addClasses){
1032 this.element.addClass("ui-draggable");
1033 }
1034 if (this.options.disabled){
1035 this.element.addClass("ui-draggable-disabled");
1036 }
1037
1038 this._mouseInit();
1039
1040 },
1041
1042 _destroy: function() {
1043 this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
1044 this._mouseDestroy();
1045 },
1046
1047 _mouseCapture: function(event) {
1048
1049 var o = this.options;
1050
1051 // among others, prevent a drag on a resizable-handle
1052 if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) {
1053 return false;
1054 }
1055
1056 //Quit if we're not on a valid handle
1057 this.handle = this._getHandle(event);
1058 if (!this.handle) {
1059 return false;
1060 }
1061
1062 $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
1063 $("<div class='ui-draggable-iframeFix' style='background: #fff;'></div>")
1064 .css({
1065 width: this.offsetWidth+"px", height: this.offsetHeight+"px",
1066 position: "absolute", opacity: "0.001", zIndex: 1000
1067 })
1068 .css($(this).offset())
1069 .appendTo("body");
1070 });
1071
1072 return true;
1073
1074 },
1075
1076 _mouseStart: function(event) {
1077
1078 var o = this.options;
1079
1080 //Create and append the visible helper
1081 this.helper = this._createHelper(event);
1082
1083 this.helper.addClass("ui-draggable-dragging");
1084
1085 //Cache the helper size
1086 this._cacheHelperProportions();
1087
1088 //If ddmanager is used for droppables, set the global draggable
1089 if($.ui.ddmanager) {
1090 $.ui.ddmanager.current = this;
1091 }
1092
1093 /*
1094 * - Position generation -
1095 * This block generates everything position related - it's the core of draggables.
1096 */
1097
1098 //Cache the margins of the original element
1099 this._cacheMargins();
1100
1101 //Store the helper's css position
1102 this.cssPosition = this.helper.css("position");
1103 this.scrollParent = this.helper.scrollParent();
1104
1105 //The element's absolute position on the page minus margins
1106 this.offset = this.positionAbs = this.element.offset();
1107 this.offset = {
1108 top: this.offset.top - this.margins.top,
1109 left: this.offset.left - this.margins.left
1110 };
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 if(o.containment) {
1131 this._setContainment();
1132 }
1133
1134 //Trigger event + callbacks
1135 if(this._trigger("start", event) === false) {
1136 this._clear();
1137 return false;
1138 }
1139
1140 //Recache the helper size
1141 this._cacheHelperProportions();
1142
1143 //Prepare the droppable offsets
1144 if ($.ui.ddmanager && !o.dropBehaviour) {
1145 $.ui.ddmanager.prepareOffsets(this, event);
1146 }
1147
1148
1149 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
1150
1151 //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
1152 if ( $.ui.ddmanager ) {
1153 $.ui.ddmanager.dragStart(this, event);
1154 }
1155
1156 return true;
1157 },
1158
1159 _mouseDrag: function(event, noPropagation) {
1160
1161 //Compute the helpers position
1162 this.position = this._generatePosition(event);
1163 this.positionAbs = this._convertPositionTo("absolute");
1164
1165 //Call plugins and callbacks and use the resulting position if something is returned
1166 if (!noPropagation) {
1167 var ui = this._uiHash();
1168 if(this._trigger("drag", event, ui) === false) {
1169 this._mouseUp({});
1170 return false;
1171 }
1172 this.position = ui.position;
1173 }
1174
1175 if(!this.options.axis || this.options.axis !== "y") {
1176 this.helper[0].style.left = this.position.left+"px";
1177 }
1178 if(!this.options.axis || this.options.axis !== "x") {
1179 this.helper[0].style.top = this.position.top+"px";
1180 }
1181 if($.ui.ddmanager) {
1182 $.ui.ddmanager.drag(this, event);
1183 }
1184
1185 return false;
1186 },
1187
1188 _mouseStop: function(event) {
1189
1190 //If we are using droppables, inform the manager about the drop
1191 var element,
1192 that = this,
1193 elementInDom = false,
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 element = this.element[0];
1207 while ( element && (element = element.parentNode) ) {
1208 if (element === document ) {
1209 elementInDom = true;
1210 }
1211 }
1212 if ( !elementInDom && this.options.helper === "original" ) {
1213 return false;
1214 }
1215
1216 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))) {
1217 $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
1218 if(that._trigger("stop", event) !== false) {
1219 that._clear();
1220 }
1221 });
1222 } else {
1223 if(this._trigger("stop", event) !== false) {
1224 this._clear();
1225 }
1226 }
1227
1228 return false;
1229 },
1230
1231 _mouseUp: function(event) {
1232 //Remove frame helpers
1233 $("div.ui-draggable-iframeFix").each(function() {
1234 this.parentNode.removeChild(this);
1235 });
1236
1237 //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
1238 if( $.ui.ddmanager ) {
1239 $.ui.ddmanager.dragStop(this, event);
1240 }
1241
1242 return $.ui.mouse.prototype._mouseUp.call(this, event);
1243 },
1244
1245 cancel: function() {
1246
1247 if(this.helper.is(".ui-draggable-dragging")) {
1248 this._mouseUp({});
1249 } else {
1250 this._clear();
1251 }
1252
1253 return this;
1254
1255 },
1256
1257 _getHandle: function(event) {
1258
1259 var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false;
1260 $(this.options.handle, this.element)
1261 .find("*")
1262 .addBack()
1263 .each(function() {
1264 if(this === event.target) {
1265 handle = true;
1266 }
1267 });
1268
1269 return handle;
1270
1271 },
1272
1273 _createHelper: function(event) {
1274
1275 var o = this.options,
1276 helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper === "clone" ? this.element.clone().removeAttr("id") : this.element);
1277
1278 if(!helper.parents("body").length) {
1279 helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo));
1280 }
1281
1282 if(helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) {
1283 helper.css("position", "absolute");
1284 }
1285
1286 return helper;
1287
1288 },
1289
1290 _adjustOffsetFromHelper: function(obj) {
1291 if (typeof obj === "string") {
1292 obj = obj.split(" ");
1293 }
1294 if ($.isArray(obj)) {
1295 obj = {left: +obj[0], top: +obj[1] || 0};
1296 }
1297 if ("left" in obj) {
1298 this.offset.click.left = obj.left + this.margins.left;
1299 }
1300 if ("right" in obj) {
1301 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
1302 }
1303 if ("top" in obj) {
1304 this.offset.click.top = obj.top + this.margins.top;
1305 }
1306 if ("bottom" in obj) {
1307 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
1308 }
1309 },
1310
1311 _getParentOffset: function() {
1312
1313 //Get the offsetParent and cache its position
1314 this.offsetParent = this.helper.offsetParent();
1315 var po = this.offsetParent.offset();
1316
1317 // This is a special case where we need to modify a offset calculated on start, since the following happened:
1318 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
1319 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
1320 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
1321 if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
1322 po.left += this.scrollParent.scrollLeft();
1323 po.top += this.scrollParent.scrollTop();
1324 }
1325
1326 //This needs to be actually done for all browsers, since pageX/pageY includes this information
1327 //Ugly IE fix
1328 if((this.offsetParent[0] === document.body) ||
1329 (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
1330 po = { top: 0, left: 0 };
1331 }
1332
1333 return {
1334 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
1335 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
1336 };
1337
1338 },
1339
1340 _getRelativeOffset: function() {
1341
1342 if(this.cssPosition === "relative") {
1343 var p = this.element.position();
1344 return {
1345 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
1346 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
1347 };
1348 } else {
1349 return { top: 0, left: 0 };
1350 }
1351
1352 },
1353
1354 _cacheMargins: function() {
1355 this.margins = {
1356 left: (parseInt(this.element.css("marginLeft"),10) || 0),
1357 top: (parseInt(this.element.css("marginTop"),10) || 0),
1358 right: (parseInt(this.element.css("marginRight"),10) || 0),
1359 bottom: (parseInt(this.element.css("marginBottom"),10) || 0)
1360 };
1361 },
1362
1363 _cacheHelperProportions: function() {
1364 this.helperProportions = {
1365 width: this.helper.outerWidth(),
1366 height: this.helper.outerHeight()
1367 };
1368 },
1369
1370 _setContainment: function() {
1371
1372 var over, c, ce,
1373 o = this.options;
1374
1375 if(o.containment === "parent") {
1376 o.containment = this.helper[0].parentNode;
1377 }
1378 if(o.containment === "document" || o.containment === "window") {
1379 this.containment = [
1380 o.containment === "document" ? 0 : $(window).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
1381 o.containment === "document" ? 0 : $(window).scrollTop() - this.offset.relative.top - this.offset.parent.top,
1382 (o.containment === "document" ? 0 : $(window).scrollLeft()) + $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left,
1383 (o.containment === "document" ? 0 : $(window).scrollTop()) + ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
1384 ];
1385 }
1386
1387 if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor !== Array) {
1388 c = $(o.containment);
1389 ce = c[0];
1390
1391 if(!ce) {
1392 return;
1393 }
1394
1395 over = ($(ce).css("overflow") !== "hidden");
1396
1397 this.containment = [
1398 (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0),
1399 (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0),
1400 (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 - this.margins.right,
1401 (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 - this.margins.bottom
1402 ];
1403 this.relative_container = c;
1404
1405 } else if(o.containment.constructor === Array) {
1406 this.containment = o.containment;
1407 }
1408
1409 },
1410
1411 _convertPositionTo: function(d, pos) {
1412
1413 if(!pos) {
1414 pos = this.position;
1415 }
1416
1417 var mod = d === "absolute" ? 1 : -1,
1418 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);
1419
1420 return {
1421 top: (
1422 pos.top + // The absolute mouse position
1423 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
1424 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
1425 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
1426 ),
1427 left: (
1428 pos.left + // The absolute mouse position
1429 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
1430 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
1431 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
1432 )
1433 };
1434
1435 },
1436
1437 _generatePosition: function(event) {
1438
1439 var containment, co, top, left,
1440 o = this.options,
1441 scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,
1442 scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName),
1443 pageX = event.pageX,
1444 pageY = event.pageY;
1445
1446 /*
1447 * - Position constraining -
1448 * Constrain the position to a mix of grid, containment.
1449 */
1450
1451 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
1452 if(this.containment) {
1453 if (this.relative_container){
1454 co = this.relative_container.offset();
1455 containment = [ this.containment[0] + co.left,
1456 this.containment[1] + co.top,
1457 this.containment[2] + co.left,
1458 this.containment[3] + co.top ];
1459 }
1460 else {
1461 containment = this.containment;
1462 }
1463
1464 if(event.pageX - this.offset.click.left < containment[0]) {
1465 pageX = containment[0] + this.offset.click.left;
1466 }
1467 if(event.pageY - this.offset.click.top < containment[1]) {
1468 pageY = containment[1] + this.offset.click.top;
1469 }
1470 if(event.pageX - this.offset.click.left > containment[2]) {
1471 pageX = containment[2] + this.offset.click.left;
1472 }
1473 if(event.pageY - this.offset.click.top > containment[3]) {
1474 pageY = containment[3] + this.offset.click.top;
1475 }
1476 }
1477
1478 if(o.grid) {
1479 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
1480 top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
1481 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;
1482
1483 left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
1484 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;
1485 }
1486
1487 }
1488
1489 return {
1490 top: (
1491 pageY - // The absolute mouse position
1492 this.offset.click.top - // Click offset (relative to the element)
1493 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
1494 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
1495 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
1496 ),
1497 left: (
1498 pageX - // The absolute mouse position
1499 this.offset.click.left - // Click offset (relative to the element)
1500 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
1501 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
1502 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
1503 )
1504 };
1505
1506 },
1507
1508 _clear: function() {
1509 this.helper.removeClass("ui-draggable-dragging");
1510 if(this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) {
1511 this.helper.remove();
1512 }
1513 this.helper = null;
1514 this.cancelHelperRemoval = false;
1515 },
1516
1517 // From now on bulk stuff - mainly helpers
1518
1519 _trigger: function(type, event, ui) {
1520 ui = ui || this._uiHash();
1521 $.ui.plugin.call(this, type, [event, ui]);
1522 //The absolute position has to be recalculated after plugins
1523 if(type === "drag") {
1524 this.positionAbs = this._convertPositionTo("absolute");
1525 }
1526 return $.Widget.prototype._trigger.call(this, type, event, ui);
1527 },
1528
1529 plugins: {},
1530
1531 _uiHash: function() {
1532 return {
1533 helper: this.helper,
1534 position: this.position,
1535 originalPosition: this.originalPosition,
1536 offset: this.positionAbs
1537 };
1538 }
1539
1540});
1541
1542$.ui.plugin.add("draggable", "connectToSortable", {
1543 start: function(event, ui) {
1544
1545 var inst = $(this).data("ui-draggable"), o = inst.options,
1546 uiSortable = $.extend({}, ui, { item: inst.element });
1547 inst.sortables = [];
1548 $(o.connectToSortable).each(function() {
1549 var sortable = $.data(this, "ui-sortable");
1550 if (sortable && !sortable.options.disabled) {
1551 inst.sortables.push({
1552 instance: sortable,
1553 shouldRevert: sortable.options.revert
1554 });
1555 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).
1556 sortable._trigger("activate", event, uiSortable);
1557 }
1558 });
1559
1560 },
1561 stop: function(event, ui) {
1562
1563 //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
1564 var inst = $(this).data("ui-draggable"),
1565 uiSortable = $.extend({}, ui, { item: inst.element });
1566
1567 $.each(inst.sortables, function() {
1568 if(this.instance.isOver) {
1569
1570 this.instance.isOver = 0;
1571
1572 inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
1573 this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
1574
1575 //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: "valid/invalid"
1576 if(this.shouldRevert) {
1577 this.instance.options.revert = true;
1578 }
1579
1580 //Trigger the stop of the sortable
1581 this.instance._mouseStop(event);
1582
1583 this.instance.options.helper = this.instance.options._helper;
1584
1585 //If the helper has been the original item, restore properties in the sortable
1586 if(inst.options.helper === "original") {
1587 this.instance.currentItem.css({ top: "auto", left: "auto" });
1588 }
1589
1590 } else {
1591 this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
1592 this.instance._trigger("deactivate", event, uiSortable);
1593 }
1594
1595 });
1596
1597 },
1598 drag: function(event, ui) {
1599
1600 var inst = $(this).data("ui-draggable"), that = this;
1601
1602 $.each(inst.sortables, function() {
1603
1604 var innermostIntersecting = false,
1605 thisSortable = this;
1606
1607 //Copy over some variables to allow calling the sortable's native _intersectsWith
1608 this.instance.positionAbs = inst.positionAbs;
1609 this.instance.helperProportions = inst.helperProportions;
1610 this.instance.offset.click = inst.offset.click;
1611
1612 if(this.instance._intersectsWith(this.instance.containerCache)) {
1613 innermostIntersecting = true;
1614 $.each(inst.sortables, function () {
1615 this.instance.positionAbs = inst.positionAbs;
1616 this.instance.helperProportions = inst.helperProportions;
1617 this.instance.offset.click = inst.offset.click;
1618 if (this !== thisSortable &&
1619 this.instance._intersectsWith(this.instance.containerCache) &&
1620 $.contains(thisSortable.instance.element[0], this.instance.element[0])
1621 ) {
1622 innermostIntersecting = false;
1623 }
1624 return innermostIntersecting;
1625 });
1626 }
1627
1628
1629 if(innermostIntersecting) {
1630 //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
1631 if(!this.instance.isOver) {
1632
1633 this.instance.isOver = 1;
1634 //Now we fake the start of dragging for the sortable instance,
1635 //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
1636 //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)
1637 this.instance.currentItem = $(that).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item", true);
1638 this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
1639 this.instance.options.helper = function() { return ui.helper[0]; };
1640
1641 event.target = this.instance.currentItem[0];
1642 this.instance._mouseCapture(event, true);
1643 this.instance._mouseStart(event, true, true);
1644
1645 //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
1646 this.instance.offset.click.top = inst.offset.click.top;
1647 this.instance.offset.click.left = inst.offset.click.left;
1648 this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
1649 this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
1650
1651 inst._trigger("toSortable", event);
1652 inst.dropped = this.instance.element; //draggable revert needs that
1653 //hack so receive/update callbacks work (mostly)
1654 inst.currentItem = inst.element;
1655 this.instance.fromOutside = inst;
1656
1657 }
1658
1659 //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
1660 if(this.instance.currentItem) {
1661 this.instance._mouseDrag(event);
1662 }
1663
1664 } else {
1665
1666 //If it doesn't intersect with the sortable, and it intersected before,
1667 //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
1668 if(this.instance.isOver) {
1669
1670 this.instance.isOver = 0;
1671 this.instance.cancelHelperRemoval = true;
1672
1673 //Prevent reverting on this forced stop
1674 this.instance.options.revert = false;
1675
1676 // The out event needs to be triggered independently
1677 this.instance._trigger("out", event, this.instance._uiHash(this.instance));
1678
1679 this.instance._mouseStop(event, true);
1680 this.instance.options.helper = this.instance.options._helper;
1681
1682 //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
1683 this.instance.currentItem.remove();
1684 if(this.instance.placeholder) {
1685 this.instance.placeholder.remove();
1686 }
1687
1688 inst._trigger("fromSortable", event);
1689 inst.dropped = false; //draggable revert needs that
1690 }
1691
1692 }
1693
1694 });
1695
1696 }
1697});
1698
1699$.ui.plugin.add("draggable", "cursor", {
1700 start: function() {
1701 var t = $("body"), o = $(this).data("ui-draggable").options;
1702 if (t.css("cursor")) {
1703 o._cursor = t.css("cursor");
1704 }
1705 t.css("cursor", o.cursor);
1706 },
1707 stop: function() {
1708 var o = $(this).data("ui-draggable").options;
1709 if (o._cursor) {
1710 $("body").css("cursor", o._cursor);
1711 }
1712 }
1713});
1714
1715$.ui.plugin.add("draggable", "opacity", {
1716 start: function(event, ui) {
1717 var t = $(ui.helper), o = $(this).data("ui-draggable").options;
1718 if(t.css("opacity")) {
1719 o._opacity = t.css("opacity");
1720 }
1721 t.css("opacity", o.opacity);
1722 },
1723 stop: function(event, ui) {
1724 var o = $(this).data("ui-draggable").options;
1725 if(o._opacity) {
1726 $(ui.helper).css("opacity", o._opacity);
1727 }
1728 }
1729});
1730
1731$.ui.plugin.add("draggable", "scroll", {
1732 start: function() {
1733 var i = $(this).data("ui-draggable");
1734 if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") {
1735 i.overflowOffset = i.scrollParent.offset();
1736 }
1737 },
1738 drag: function( event ) {
1739
1740 var i = $(this).data("ui-draggable"), o = i.options, scrolled = false;
1741
1742 if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") {
1743
1744 if(!o.axis || o.axis !== "x") {
1745 if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
1746 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
1747 } else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) {
1748 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
1749 }
1750 }
1751
1752 if(!o.axis || o.axis !== "y") {
1753 if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
1754 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
1755 } else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) {
1756 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
1757 }
1758 }
1759
1760 } else {
1761
1762 if(!o.axis || o.axis !== "x") {
1763 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
1764 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
1765 } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
1766 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
1767 }
1768 }
1769
1770 if(!o.axis || o.axis !== "y") {
1771 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
1772 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
1773 } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
1774 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
1775 }
1776 }
1777
1778 }
1779
1780 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
1781 $.ui.ddmanager.prepareOffsets(i, event);
1782 }
1783
1784 }
1785});
1786
1787$.ui.plugin.add("draggable", "snap", {
1788 start: function() {
1789
1790 var i = $(this).data("ui-draggable"),
1791 o = i.options;
1792
1793 i.snapElements = [];
1794
1795 $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() {
1796 var $t = $(this),
1797 $o = $t.offset();
1798 if(this !== i.element[0]) {
1799 i.snapElements.push({
1800 item: this,
1801 width: $t.outerWidth(), height: $t.outerHeight(),
1802 top: $o.top, left: $o.left
1803 });
1804 }
1805 });
1806
1807 },
1808 drag: function(event, ui) {
1809
1810 var ts, bs, ls, rs, l, r, t, b, i, first,
1811 inst = $(this).data("ui-draggable"),
1812 o = inst.options,
1813 d = o.snapTolerance,
1814 x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
1815 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
1816
1817 for (i = inst.snapElements.length - 1; i >= 0; i--){
1818
1819 l = inst.snapElements[i].left;
1820 r = l + inst.snapElements[i].width;
1821 t = inst.snapElements[i].top;
1822 b = t + inst.snapElements[i].height;
1823
1824 //Yes, I know, this is insane ;)
1825 if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) {
1826 if(inst.snapElements[i].snapping) {
1827 (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
1828 }
1829 inst.snapElements[i].snapping = false;
1830 continue;
1831 }
1832
1833 if(o.snapMode !== "inner") {
1834 ts = Math.abs(t - y2) <= d;
1835 bs = Math.abs(b - y1) <= d;
1836 ls = Math.abs(l - x2) <= d;
1837 rs = Math.abs(r - x1) <= d;
1838 if(ts) {
1839 ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
1840 }
1841 if(bs) {
1842 ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
1843 }
1844 if(ls) {
1845 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
1846 }
1847 if(rs) {
1848 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
1849 }
1850 }
1851
1852 first = (ts || bs || ls || rs);
1853
1854 if(o.snapMode !== "outer") {
1855 ts = Math.abs(t - y1) <= d;
1856 bs = Math.abs(b - y2) <= d;
1857 ls = Math.abs(l - x1) <= d;
1858 rs = Math.abs(r - x2) <= d;
1859 if(ts) {
1860 ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
1861 }
1862 if(bs) {
1863 ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
1864 }
1865 if(ls) {
1866 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
1867 }
1868 if(rs) {
1869 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
1870 }
1871 }
1872
1873 if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) {
1874 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
1875 }
1876 inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
1877
1878 }
1879
1880 }
1881});
1882
1883$.ui.plugin.add("draggable", "stack", {
1884 start: function() {
1885 var min,
1886 o = this.data("ui-draggable").options,
1887 group = $.makeArray($(o.stack)).sort(function(a,b) {
1888 return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0);
1889 });
1890
1891 if (!group.length) { return; }
1892
1893 min = parseInt($(group[0]).css("zIndex"), 10) || 0;
1894 $(group).each(function(i) {
1895 $(this).css("zIndex", min + i);
1896 });
1897 this.css("zIndex", (min + group.length));
1898 }
1899});
1900
1901$.ui.plugin.add("draggable", "zIndex", {
1902 start: function(event, ui) {
1903 var t = $(ui.helper), o = $(this).data("ui-draggable").options;
1904 if(t.css("zIndex")) {
1905 o._zIndex = t.css("zIndex");
1906 }
1907 t.css("zIndex", o.zIndex);
1908 },
1909 stop: function(event, ui) {
1910 var o = $(this).data("ui-draggable").options;
1911 if(o._zIndex) {
1912 $(ui.helper).css("zIndex", o._zIndex);
1913 }
1914 }
1915});
1916
1917})(jQuery);
1918
1919(function( $, undefined ) {
1920
1921function isOverAxis( x, reference, size ) {
1922 return ( x > reference ) && ( x < ( reference + size ) );
1923}
1924
1925$.widget("ui.droppable", {
1926 version: "1.10.1",
1927 widgetEventPrefix: "drop",
1928 options: {
1929 accept: "*",
1930 activeClass: false,
1931 addClasses: true,
1932 greedy: false,
1933 hoverClass: false,
1934 scope: "default",
1935 tolerance: "intersect",
1936
1937 // callbacks
1938 activate: null,
1939 deactivate: null,
1940 drop: null,
1941 out: null,
1942 over: null
1943 },
1944 _create: function() {
1945
1946 var o = this.options,
1947 accept = o.accept;
1948
1949 this.isover = false;
1950 this.isout = true;
1951
1952 this.accept = $.isFunction(accept) ? accept : function(d) {
1953 return d.is(accept);
1954 };
1955
1956 //Store the droppable's proportions
1957 this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight };
1958
1959 // Add the reference and positions to the manager
1960 $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || [];
1961 $.ui.ddmanager.droppables[o.scope].push(this);
1962
1963 (o.addClasses && this.element.addClass("ui-droppable"));
1964
1965 },
1966
1967 _destroy: function() {
1968 var i = 0,
1969 drop = $.ui.ddmanager.droppables[this.options.scope];
1970
1971 for ( ; i < drop.length; i++ ) {
1972 if ( drop[i] === this ) {
1973 drop.splice(i, 1);
1974 }
1975 }
1976
1977 this.element.removeClass("ui-droppable ui-droppable-disabled");
1978 },
1979
1980 _setOption: function(key, value) {
1981
1982 if(key === "accept") {
1983 this.accept = $.isFunction(value) ? value : function(d) {
1984 return d.is(value);
1985 };
1986 }
1987 $.Widget.prototype._setOption.apply(this, arguments);
1988 },
1989
1990 _activate: function(event) {
1991 var draggable = $.ui.ddmanager.current;
1992 if(this.options.activeClass) {
1993 this.element.addClass(this.options.activeClass);
1994 }
1995 if(draggable){
1996 this._trigger("activate", event, this.ui(draggable));
1997 }
1998 },
1999
2000 _deactivate: function(event) {
2001 var draggable = $.ui.ddmanager.current;
2002 if(this.options.activeClass) {
2003 this.element.removeClass(this.options.activeClass);
2004 }
2005 if(draggable){
2006 this._trigger("deactivate", event, this.ui(draggable));
2007 }
2008 },
2009
2010 _over: function(event) {
2011
2012 var draggable = $.ui.ddmanager.current;
2013
2014 // Bail if draggable and droppable are same element
2015 if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
2016 return;
2017 }
2018
2019 if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
2020 if(this.options.hoverClass) {
2021 this.element.addClass(this.options.hoverClass);
2022 }
2023 this._trigger("over", event, this.ui(draggable));
2024 }
2025
2026 },
2027
2028 _out: function(event) {
2029
2030 var draggable = $.ui.ddmanager.current;
2031
2032 // Bail if draggable and droppable are same element
2033 if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
2034 return;
2035 }
2036
2037 if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
2038 if(this.options.hoverClass) {
2039 this.element.removeClass(this.options.hoverClass);
2040 }
2041 this._trigger("out", event, this.ui(draggable));
2042 }
2043
2044 },
2045
2046 _drop: function(event,custom) {
2047
2048 var draggable = custom || $.ui.ddmanager.current,
2049 childrenIntersection = false;
2050
2051 // Bail if draggable and droppable are same element
2052 if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
2053 return false;
2054 }
2055
2056 this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function() {
2057 var inst = $.data(this, "ui-droppable");
2058 if(
2059 inst.options.greedy &&
2060 !inst.options.disabled &&
2061 inst.options.scope === draggable.options.scope &&
2062 inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) &&
2063 $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)
2064 ) { childrenIntersection = true; return false; }
2065 });
2066 if(childrenIntersection) {
2067 return false;
2068 }
2069
2070 if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
2071 if(this.options.activeClass) {
2072 this.element.removeClass(this.options.activeClass);
2073 }
2074 if(this.options.hoverClass) {
2075 this.element.removeClass(this.options.hoverClass);
2076 }
2077 this._trigger("drop", event, this.ui(draggable));
2078 return this.element;
2079 }
2080
2081 return false;
2082
2083 },
2084
2085 ui: function(c) {
2086 return {
2087 draggable: (c.currentItem || c.element),
2088 helper: c.helper,
2089 position: c.position,
2090 offset: c.positionAbs
2091 };
2092 }
2093
2094});
2095
2096$.ui.intersect = function(draggable, droppable, toleranceMode) {
2097
2098 if (!droppable.offset) {
2099 return false;
2100 }
2101
2102 var draggableLeft, draggableTop,
2103 x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width,
2104 y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height,
2105 l = droppable.offset.left, r = l + droppable.proportions.width,
2106 t = droppable.offset.top, b = t + droppable.proportions.height;
2107
2108 switch (toleranceMode) {
2109 case "fit":
2110 return (l <= x1 && x2 <= r && t <= y1 && y2 <= b);
2111 case "intersect":
2112 return (l < x1 + (draggable.helperProportions.width / 2) && // Right Half
2113 x2 - (draggable.helperProportions.width / 2) < r && // Left Half
2114 t < y1 + (draggable.helperProportions.height / 2) && // Bottom Half
2115 y2 - (draggable.helperProportions.height / 2) < b ); // Top Half
2116 case "pointer":
2117 draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left);
2118 draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top);
2119 return isOverAxis( draggableTop, t, droppable.proportions.height ) && isOverAxis( draggableLeft, l, droppable.proportions.width );
2120 case "touch":
2121 return (
2122 (y1 >= t && y1 <= b) || // Top edge touching
2123 (y2 >= t && y2 <= b) || // Bottom edge touching
2124 (y1 < t && y2 > b) // Surrounded vertically
2125 ) && (
2126 (x1 >= l && x1 <= r) || // Left edge touching
2127 (x2 >= l && x2 <= r) || // Right edge touching
2128 (x1 < l && x2 > r) // Surrounded horizontally
2129 );
2130 default:
2131 return false;
2132 }
2133
2134};
2135
2136/*
2137 This manager tracks offsets of draggables and droppables
2138*/
2139$.ui.ddmanager = {
2140 current: null,
2141 droppables: { "default": [] },
2142 prepareOffsets: function(t, event) {
2143
2144 var i, j,
2145 m = $.ui.ddmanager.droppables[t.options.scope] || [],
2146 type = event ? event.type : null, // workaround for #2317
2147 list = (t.currentItem || t.element).find(":data(ui-droppable)").addBack();
2148
2149 droppablesLoop: for (i = 0; i < m.length; i++) {
2150
2151 //No disabled and non-accepted
2152 if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) {
2153 continue;
2154 }
2155
2156 // Filter out elements in the current dragged item
2157 for (j=0; j < list.length; j++) {
2158 if(list[j] === m[i].element[0]) {
2159 m[i].proportions.height = 0;
2160 continue droppablesLoop;
2161 }
2162 }
2163
2164 m[i].visible = m[i].element.css("display") !== "none";
2165 if(!m[i].visible) {
2166 continue;
2167 }
2168
2169 //Activate the droppable if used directly from draggables
2170 if(type === "mousedown") {
2171 m[i]._activate.call(m[i], event);
2172 }
2173
2174 m[i].offset = m[i].element.offset();
2175 m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight };
2176
2177 }
2178
2179 },
2180 drop: function(draggable, event) {
2181
2182 var dropped = false;
2183 $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
2184
2185 if(!this.options) {
2186 return;
2187 }
2188 if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) {
2189 dropped = this._drop.call(this, event) || dropped;
2190 }
2191
2192 if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
2193 this.isout = true;
2194 this.isover = false;
2195 this._deactivate.call(this, event);
2196 }
2197
2198 });
2199 return dropped;
2200
2201 },
2202 dragStart: function( draggable, event ) {
2203 //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
2204 draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
2205 if( !draggable.options.refreshPositions ) {
2206 $.ui.ddmanager.prepareOffsets( draggable, event );
2207 }
2208 });
2209 },
2210 drag: function(draggable, event) {
2211
2212 //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
2213 if(draggable.options.refreshPositions) {
2214 $.ui.ddmanager.prepareOffsets(draggable, event);
2215 }
2216
2217 //Run through all droppables and check their positions based on specific tolerance options
2218 $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
2219
2220 if(this.options.disabled || this.greedyChild || !this.visible) {
2221 return;
2222 }
2223
2224 var parentInstance, scope, parent,
2225 intersects = $.ui.intersect(draggable, this, this.options.tolerance),
2226 c = !intersects && this.isover ? "isout" : (intersects && !this.isover ? "isover" : null);
2227 if(!c) {
2228 return;
2229 }
2230
2231 if (this.options.greedy) {
2232 // find droppable parents with same scope
2233 scope = this.options.scope;
2234 parent = this.element.parents(":data(ui-droppable)").filter(function () {
2235 return $.data(this, "ui-droppable").options.scope === scope;
2236 });
2237
2238 if (parent.length) {
2239 parentInstance = $.data(parent[0], "ui-droppable");
2240 parentInstance.greedyChild = (c === "isover");
2241 }
2242 }
2243
2244 // we just moved into a greedy child
2245 if (parentInstance && c === "isover") {
2246 parentInstance.isover = false;
2247 parentInstance.isout = true;
2248 parentInstance._out.call(parentInstance, event);
2249 }
2250
2251 this[c] = true;
2252 this[c === "isout" ? "isover" : "isout"] = false;
2253 this[c === "isover" ? "_over" : "_out"].call(this, event);
2254
2255 // we just moved out of a greedy child
2256 if (parentInstance && c === "isout") {
2257 parentInstance.isout = false;
2258 parentInstance.isover = true;
2259 parentInstance._over.call(parentInstance, event);
2260 }
2261 });
2262
2263 },
2264 dragStop: function( draggable, event ) {
2265 draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
2266 //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
2267 if( !draggable.options.refreshPositions ) {
2268 $.ui.ddmanager.prepareOffsets( draggable, event );
2269 }
2270 }
2271};
2272
2273})(jQuery);
2274
2275(function( $, undefined ) {
2276
2277function num(v) {
2278 return parseInt(v, 10) || 0;
2279}
2280
2281function isNumber(value) {
2282 return !isNaN(parseInt(value, 10));
2283}
2284
2285$.widget("ui.resizable", $.ui.mouse, {
2286 version: "1.10.1",
2287 widgetEventPrefix: "resize",
2288 options: {
2289 alsoResize: false,
2290 animate: false,
2291 animateDuration: "slow",
2292 animateEasing: "swing",
2293 aspectRatio: false,
2294 autoHide: false,
2295 containment: false,
2296 ghost: false,
2297 grid: false,
2298 handles: "e,s,se",
2299 helper: false,
2300 maxHeight: null,
2301 maxWidth: null,
2302 minHeight: 10,
2303 minWidth: 10,
2304 // See #7960
2305 zIndex: 90,
2306
2307 // callbacks
2308 resize: null,
2309 start: null,
2310 stop: null
2311 },
2312 _create: function() {
2313
2314 var n, i, handle, axis, hname,
2315 that = this,
2316 o = this.options;
2317 this.element.addClass("ui-resizable");
2318
2319 $.extend(this, {
2320 _aspectRatio: !!(o.aspectRatio),
2321 aspectRatio: o.aspectRatio,
2322 originalElement: this.element,
2323 _proportionallyResizeElements: [],
2324 _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
2325 });
2326
2327 //Wrap the element if it cannot hold child nodes
2328 if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {
2329
2330 //Create a wrapper element and set the wrapper to the new current internal element
2331 this.element.wrap(
2332 $("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({
2333 position: this.element.css("position"),
2334 width: this.element.outerWidth(),
2335 height: this.element.outerHeight(),
2336 top: this.element.css("top"),
2337 left: this.element.css("left")
2338 })
2339 );
2340
2341 //Overwrite the original this.element
2342 this.element = this.element.parent().data(
2343 "ui-resizable", this.element.data("ui-resizable")
2344 );
2345
2346 this.elementIsWrapper = true;
2347
2348 //Move margins to the wrapper
2349 this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") });
2350 this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});
2351
2352 //Prevent Safari textarea resize
2353 this.originalResizeStyle = this.originalElement.css("resize");
2354 this.originalElement.css("resize", "none");
2355
2356 //Push the actual element to our proportionallyResize internal array
2357 this._proportionallyResizeElements.push(this.originalElement.css({ position: "static", zoom: 1, display: "block" }));
2358
2359 // avoid IE jump (hard set the margin)
2360 this.originalElement.css({ margin: this.originalElement.css("margin") });
2361
2362 // fix handlers offset
2363 this._proportionallyResize();
2364
2365 }
2366
2367 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" });
2368 if(this.handles.constructor === String) {
2369
2370 if ( this.handles === "all") {
2371 this.handles = "n,e,s,w,se,sw,ne,nw";
2372 }
2373
2374 n = this.handles.split(",");
2375 this.handles = {};
2376
2377 for(i = 0; i < n.length; i++) {
2378
2379 handle = $.trim(n[i]);
2380 hname = "ui-resizable-"+handle;
2381 axis = $("<div class='ui-resizable-handle " + hname + "'></div>");
2382
2383 // Apply zIndex to all handles - see #7960
2384 axis.css({ zIndex: o.zIndex });
2385
2386 //TODO : What's going on here?
2387 if ("se" === handle) {
2388 axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se");
2389 }
2390
2391 //Insert into internal handles object and append to element
2392 this.handles[handle] = ".ui-resizable-"+handle;
2393 this.element.append(axis);
2394 }
2395
2396 }
2397
2398 this._renderAxis = function(target) {
2399
2400 var i, axis, padPos, padWrapper;
2401
2402 target = target || this.element;
2403
2404 for(i in this.handles) {
2405
2406 if(this.handles[i].constructor === String) {
2407 this.handles[i] = $(this.handles[i], this.element).show();
2408 }
2409
2410 //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)
2411 if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {
2412
2413 axis = $(this.handles[i], this.element);
2414
2415 //Checking the correct pad and border
2416 padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
2417
2418 //The padding type i have to apply...
2419 padPos = [ "padding",
2420 /ne|nw|n/.test(i) ? "Top" :
2421 /se|sw|s/.test(i) ? "Bottom" :
2422 /^e$/.test(i) ? "Right" : "Left" ].join("");
2423
2424 target.css(padPos, padWrapper);
2425
2426 this._proportionallyResize();
2427
2428 }
2429
2430 //TODO: What's that good for? There's not anything to be executed left
2431 if(!$(this.handles[i]).length) {
2432 continue;
2433 }
2434 }
2435 };
2436
2437 //TODO: make renderAxis a prototype function
2438 this._renderAxis(this.element);
2439
2440 this._handles = $(".ui-resizable-handle", this.element)
2441 .disableSelection();
2442
2443 //Matching axis name
2444 this._handles.mouseover(function() {
2445 if (!that.resizing) {
2446 if (this.className) {
2447 axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
2448 }
2449 //Axis, default = se
2450 that.axis = axis && axis[1] ? axis[1] : "se";
2451 }
2452 });
2453
2454 //If we want to auto hide the elements
2455 if (o.autoHide) {
2456 this._handles.hide();
2457 $(this.element)
2458 .addClass("ui-resizable-autohide")
2459 .mouseenter(function() {
2460 if (o.disabled) {
2461 return;
2462 }
2463 $(this).removeClass("ui-resizable-autohide");
2464 that._handles.show();
2465 })
2466 .mouseleave(function(){
2467 if (o.disabled) {
2468 return;
2469 }
2470 if (!that.resizing) {
2471 $(this).addClass("ui-resizable-autohide");
2472 that._handles.hide();
2473 }
2474 });
2475 }
2476
2477 //Initialize the mouse interaction
2478 this._mouseInit();
2479
2480 },
2481
2482 _destroy: function() {
2483
2484 this._mouseDestroy();
2485
2486 var wrapper,
2487 _destroy = function(exp) {
2488 $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
2489 .removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove();
2490 };
2491
2492 //TODO: Unwrap at same DOM position
2493 if (this.elementIsWrapper) {
2494 _destroy(this.element);
2495 wrapper = this.element;
2496 this.originalElement.css({
2497 position: wrapper.css("position"),
2498 width: wrapper.outerWidth(),
2499 height: wrapper.outerHeight(),
2500 top: wrapper.css("top"),
2501 left: wrapper.css("left")
2502 }).insertAfter( wrapper );
2503 wrapper.remove();
2504 }
2505
2506 this.originalElement.css("resize", this.originalResizeStyle);
2507 _destroy(this.originalElement);
2508
2509 return this;
2510 },
2511
2512 _mouseCapture: function(event) {
2513 var i, handle,
2514 capture = false;
2515
2516 for (i in this.handles) {
2517 handle = $(this.handles[i])[0];
2518 if (handle === event.target || $.contains(handle, event.target)) {
2519 capture = true;
2520 }
2521 }
2522
2523 return !this.options.disabled && capture;
2524 },
2525
2526 _mouseStart: function(event) {
2527
2528 var curleft, curtop, cursor,
2529 o = this.options,
2530 iniPos = this.element.position(),
2531 el = this.element;
2532
2533 this.resizing = true;
2534
2535 // bugfix for http://dev.jquery.com/ticket/1749
2536 if ( (/absolute/).test( el.css("position") ) ) {
2537 el.css({ position: "absolute", top: el.css("top"), left: el.css("left") });
2538 } else if (el.is(".ui-draggable")) {
2539 el.css({ position: "absolute", top: iniPos.top, left: iniPos.left });
2540 }
2541
2542 this._renderProxy();
2543
2544 curleft = num(this.helper.css("left"));
2545 curtop = num(this.helper.css("top"));
2546
2547 if (o.containment) {
2548 curleft += $(o.containment).scrollLeft() || 0;
2549 curtop += $(o.containment).scrollTop() || 0;
2550 }
2551
2552 //Store needed variables
2553 this.offset = this.helper.offset();
2554 this.position = { left: curleft, top: curtop };
2555 this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
2556 this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
2557 this.originalPosition = { left: curleft, top: curtop };
2558 this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };
2559 this.originalMousePosition = { left: event.pageX, top: event.pageY };
2560
2561 //Aspect Ratio
2562 this.aspectRatio = (typeof o.aspectRatio === "number") ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1);
2563
2564 cursor = $(".ui-resizable-" + this.axis).css("cursor");
2565 $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor);
2566
2567 el.addClass("ui-resizable-resizing");
2568 this._propagate("start", event);
2569 return true;
2570 },
2571
2572 _mouseDrag: function(event) {
2573
2574 //Increase performance, avoid regex
2575 var data,
2576 el = this.helper, props = {},
2577 smp = this.originalMousePosition,
2578 a = this.axis,
2579 prevTop = this.position.top,
2580 prevLeft = this.position.left,
2581 prevWidth = this.size.width,
2582 prevHeight = this.size.height,
2583 dx = (event.pageX-smp.left)||0,
2584 dy = (event.pageY-smp.top)||0,
2585 trigger = this._change[a];
2586
2587 if (!trigger) {
2588 return false;
2589 }
2590
2591 // Calculate the attrs that will be change
2592 data = trigger.apply(this, [event, dx, dy]);
2593
2594 // Put this in the mouseDrag handler since the user can start pressing shift while resizing
2595 this._updateVirtualBoundaries(event.shiftKey);
2596 if (this._aspectRatio || event.shiftKey) {
2597 data = this._updateRatio(data, event);
2598 }
2599
2600 data = this._respectSize(data, event);
2601
2602 this._updateCache(data);
2603
2604 // plugins callbacks need to be called first
2605 this._propagate("resize", event);
2606
2607 if (this.position.top !== prevTop) {
2608 props.top = this.position.top + "px";
2609 }
2610 if (this.position.left !== prevLeft) {
2611 props.left = this.position.left + "px";
2612 }
2613 if (this.size.width !== prevWidth) {
2614 props.width = this.size.width + "px";
2615 }
2616 if (this.size.height !== prevHeight) {
2617 props.height = this.size.height + "px";
2618 }
2619 el.css(props);
2620
2621 if (!this._helper && this._proportionallyResizeElements.length) {
2622 this._proportionallyResize();
2623 }
2624
2625 // Call the user callback if the element was resized
2626 if ( ! $.isEmptyObject(props) ) {
2627 this._trigger("resize", event, this.ui());
2628 }
2629
2630 return false;
2631 },
2632
2633 _mouseStop: function(event) {
2634
2635 this.resizing = false;
2636 var pr, ista, soffseth, soffsetw, s, left, top,
2637 o = this.options, that = this;
2638
2639 if(this._helper) {
2640
2641 pr = this._proportionallyResizeElements;
2642 ista = pr.length && (/textarea/i).test(pr[0].nodeName);
2643 soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height;
2644 soffsetw = ista ? 0 : that.sizeDiff.width;
2645
2646 s = { width: (that.helper.width() - soffsetw), height: (that.helper.height() - soffseth) };
2647 left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null;
2648 top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null;
2649
2650 if (!o.animate) {
2651 this.element.css($.extend(s, { top: top, left: left }));
2652 }
2653
2654 that.helper.height(that.size.height);
2655 that.helper.width(that.size.width);
2656
2657 if (this._helper && !o.animate) {
2658 this._proportionallyResize();
2659 }
2660 }
2661
2662 $("body").css("cursor", "auto");
2663
2664 this.element.removeClass("ui-resizable-resizing");
2665
2666 this._propagate("stop", event);
2667
2668 if (this._helper) {
2669 this.helper.remove();
2670 }
2671
2672 return false;
2673
2674 },
2675
2676 _updateVirtualBoundaries: function(forceAspectRatio) {
2677 var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
2678 o = this.options;
2679
2680 b = {
2681 minWidth: isNumber(o.minWidth) ? o.minWidth : 0,
2682 maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity,
2683 minHeight: isNumber(o.minHeight) ? o.minHeight : 0,
2684 maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity
2685 };
2686
2687 if(this._aspectRatio || forceAspectRatio) {
2688 // We want to create an enclosing box whose aspect ration is the requested one
2689 // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension
2690 pMinWidth = b.minHeight * this.aspectRatio;
2691 pMinHeight = b.minWidth / this.aspectRatio;
2692 pMaxWidth = b.maxHeight * this.aspectRatio;
2693 pMaxHeight = b.maxWidth / this.aspectRatio;
2694
2695 if(pMinWidth > b.minWidth) {
2696 b.minWidth = pMinWidth;
2697 }
2698 if(pMinHeight > b.minHeight) {
2699 b.minHeight = pMinHeight;
2700 }
2701 if(pMaxWidth < b.maxWidth) {
2702 b.maxWidth = pMaxWidth;
2703 }
2704 if(pMaxHeight < b.maxHeight) {
2705 b.maxHeight = pMaxHeight;
2706 }
2707 }
2708 this._vBoundaries = b;
2709 },
2710
2711 _updateCache: function(data) {
2712 this.offset = this.helper.offset();
2713 if (isNumber(data.left)) {
2714 this.position.left = data.left;
2715 }
2716 if (isNumber(data.top)) {
2717 this.position.top = data.top;
2718 }
2719 if (isNumber(data.height)) {
2720 this.size.height = data.height;
2721 }
2722 if (isNumber(data.width)) {
2723 this.size.width = data.width;
2724 }
2725 },
2726
2727 _updateRatio: function( data ) {
2728
2729 var cpos = this.position,
2730 csize = this.size,
2731 a = this.axis;
2732
2733 if (isNumber(data.height)) {
2734 data.width = (data.height * this.aspectRatio);
2735 } else if (isNumber(data.width)) {
2736 data.height = (data.width / this.aspectRatio);
2737 }
2738
2739 if (a === "sw") {
2740 data.left = cpos.left + (csize.width - data.width);
2741 data.top = null;
2742 }
2743 if (a === "nw") {
2744 data.top = cpos.top + (csize.height - data.height);
2745 data.left = cpos.left + (csize.width - data.width);
2746 }
2747
2748 return data;
2749 },
2750
2751 _respectSize: function( data ) {
2752
2753 var o = this._vBoundaries,
2754 a = this.axis,
2755 ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
2756 isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height),
2757 dw = this.originalPosition.left + this.originalSize.width,
2758 dh = this.position.top + this.size.height,
2759 cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
2760 if (isminw) {
2761 data.width = o.minWidth;
2762 }
2763 if (isminh) {
2764 data.height = o.minHeight;
2765 }
2766 if (ismaxw) {
2767 data.width = o.maxWidth;
2768 }
2769 if (ismaxh) {
2770 data.height = o.maxHeight;
2771 }
2772
2773 if (isminw && cw) {
2774 data.left = dw - o.minWidth;
2775 }
2776 if (ismaxw && cw) {
2777 data.left = dw - o.maxWidth;
2778 }
2779 if (isminh && ch) {
2780 data.top = dh - o.minHeight;
2781 }
2782 if (ismaxh && ch) {
2783 data.top = dh - o.maxHeight;
2784 }
2785
2786 // fixing jump error on top/left - bug #2330
2787 if (!data.width && !data.height && !data.left && data.top) {
2788 data.top = null;
2789 } else if (!data.width && !data.height && !data.top && data.left) {
2790 data.left = null;
2791 }
2792
2793 return data;
2794 },
2795
2796 _proportionallyResize: function() {
2797
2798 if (!this._proportionallyResizeElements.length) {
2799 return;
2800 }
2801
2802 var i, j, borders, paddings, prel,
2803 element = this.helper || this.element;
2804
2805 for ( i=0; i < this._proportionallyResizeElements.length; i++) {
2806
2807 prel = this._proportionallyResizeElements[i];
2808
2809 if (!this.borderDif) {
2810 this.borderDif = [];
2811 borders = [prel.css("borderTopWidth"), prel.css("borderRightWidth"), prel.css("borderBottomWidth"), prel.css("borderLeftWidth")];
2812 paddings = [prel.css("paddingTop"), prel.css("paddingRight"), prel.css("paddingBottom"), prel.css("paddingLeft")];
2813
2814 for ( j = 0; j < borders.length; j++ ) {
2815 this.borderDif[ j ] = ( parseInt( borders[ j ], 10 ) || 0 ) + ( parseInt( paddings[ j ], 10 ) || 0 );
2816 }
2817 }
2818
2819 prel.css({
2820 height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0,
2821 width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0
2822 });
2823
2824 }
2825
2826 },
2827
2828 _renderProxy: function() {
2829
2830 var el = this.element, o = this.options;
2831 this.elementOffset = el.offset();
2832
2833 if(this._helper) {
2834
2835 this.helper = this.helper || $("<div style='overflow:hidden;'></div>");
2836
2837 this.helper.addClass(this._helper).css({
2838 width: this.element.outerWidth() - 1,
2839 height: this.element.outerHeight() - 1,
2840 position: "absolute",
2841 left: this.elementOffset.left +"px",
2842 top: this.elementOffset.top +"px",
2843 zIndex: ++o.zIndex //TODO: Don't modify option
2844 });
2845
2846 this.helper
2847 .appendTo("body")
2848 .disableSelection();
2849
2850 } else {
2851 this.helper = this.element;
2852 }
2853
2854 },
2855
2856 _change: {
2857 e: function(event, dx) {
2858 return { width: this.originalSize.width + dx };
2859 },
2860 w: function(event, dx) {
2861 var cs = this.originalSize, sp = this.originalPosition;
2862 return { left: sp.left + dx, width: cs.width - dx };
2863 },
2864 n: function(event, dx, dy) {
2865 var cs = this.originalSize, sp = this.originalPosition;
2866 return { top: sp.top + dy, height: cs.height - dy };
2867 },
2868 s: function(event, dx, dy) {
2869 return { height: this.originalSize.height + dy };
2870 },
2871 se: function(event, dx, dy) {
2872 return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
2873 },
2874 sw: function(event, dx, dy) {
2875 return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
2876 },
2877 ne: function(event, dx, dy) {
2878 return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
2879 },
2880 nw: function(event, dx, dy) {
2881 return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
2882 }
2883 },
2884
2885 _propagate: function(n, event) {
2886 $.ui.plugin.call(this, n, [event, this.ui()]);
2887 (n !== "resize" && this._trigger(n, event, this.ui()));
2888 },
2889
2890 plugins: {},
2891
2892 ui: function() {
2893 return {
2894 originalElement: this.originalElement,
2895 element: this.element,
2896 helper: this.helper,
2897 position: this.position,
2898 size: this.size,
2899 originalSize: this.originalSize,
2900 originalPosition: this.originalPosition
2901 };
2902 }
2903
2904});
2905
2906/*
2907 * Resizable Extensions
2908 */
2909
2910$.ui.plugin.add("resizable", "animate", {
2911
2912 stop: function( event ) {
2913 var that = $(this).data("ui-resizable"),
2914 o = that.options,
2915 pr = that._proportionallyResizeElements,
2916 ista = pr.length && (/textarea/i).test(pr[0].nodeName),
2917 soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height,
2918 soffsetw = ista ? 0 : that.sizeDiff.width,
2919 style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) },
2920 left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null,
2921 top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null;
2922
2923 that.element.animate(
2924 $.extend(style, top && left ? { top: top, left: left } : {}), {
2925 duration: o.animateDuration,
2926 easing: o.animateEasing,
2927 step: function() {
2928
2929 var data = {
2930 width: parseInt(that.element.css("width"), 10),
2931 height: parseInt(that.element.css("height"), 10),
2932 top: parseInt(that.element.css("top"), 10),
2933 left: parseInt(that.element.css("left"), 10)
2934 };
2935
2936 if (pr && pr.length) {
2937 $(pr[0]).css({ width: data.width, height: data.height });
2938 }
2939
2940 // propagating resize, and updating values for each animation step
2941 that._updateCache(data);
2942 that._propagate("resize", event);
2943
2944 }
2945 }
2946 );
2947 }
2948
2949});
2950
2951$.ui.plugin.add("resizable", "containment", {
2952
2953 start: function() {
2954 var element, p, co, ch, cw, width, height,
2955 that = $(this).data("ui-resizable"),
2956 o = that.options,
2957 el = that.element,
2958 oc = o.containment,
2959 ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc;
2960
2961 if (!ce) {
2962 return;
2963 }
2964
2965 that.containerElement = $(ce);
2966
2967 if (/document/.test(oc) || oc === document) {
2968 that.containerOffset = { left: 0, top: 0 };
2969 that.containerPosition = { left: 0, top: 0 };
2970
2971 that.parentData = {
2972 element: $(document), left: 0, top: 0,
2973 width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight
2974 };
2975 }
2976
2977 // i'm a node, so compute top, left, right, bottom
2978 else {
2979 element = $(ce);
2980 p = [];
2981 $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); });
2982
2983 that.containerOffset = element.offset();
2984 that.containerPosition = element.position();
2985 that.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) };
2986
2987 co = that.containerOffset;
2988 ch = that.containerSize.height;
2989 cw = that.containerSize.width;
2990 width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw );
2991 height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch);
2992
2993 that.parentData = {
2994 element: ce, left: co.left, top: co.top, width: width, height: height
2995 };
2996 }
2997 },
2998
2999 resize: function( event ) {
3000 var woset, hoset, isParent, isOffsetRelative,
3001 that = $(this).data("ui-resizable"),
3002 o = that.options,
3003 co = that.containerOffset, cp = that.position,
3004 pRatio = that._aspectRatio || event.shiftKey,
3005 cop = { top:0, left:0 }, ce = that.containerElement;
3006
3007 if (ce[0] !== document && (/static/).test(ce.css("position"))) {
3008 cop = co;
3009 }
3010
3011 if (cp.left < (that._helper ? co.left : 0)) {
3012 that.size.width = that.size.width + (that._helper ? (that.position.left - co.left) : (that.position.left - cop.left));
3013 if (pRatio) {
3014 that.size.height = that.size.width / that.aspectRatio;
3015 }
3016 that.position.left = o.helper ? co.left : 0;
3017 }
3018
3019 if (cp.top < (that._helper ? co.top : 0)) {
3020 that.size.height = that.size.height + (that._helper ? (that.position.top - co.top) : that.position.top);
3021 if (pRatio) {
3022 that.size.width = that.size.height * that.aspectRatio;
3023 }
3024 that.position.top = that._helper ? co.top : 0;
3025 }
3026
3027 that.offset.left = that.parentData.left+that.position.left;
3028 that.offset.top = that.parentData.top+that.position.top;
3029
3030 woset = Math.abs( (that._helper ? that.offset.left - cop.left : (that.offset.left - cop.left)) + that.sizeDiff.width );
3031 hoset = Math.abs( (that._helper ? that.offset.top - cop.top : (that.offset.top - co.top)) + that.sizeDiff.height );
3032
3033 isParent = that.containerElement.get(0) === that.element.parent().get(0);
3034 isOffsetRelative = /relative|absolute/.test(that.containerElement.css("position"));
3035
3036 if(isParent && isOffsetRelative) {
3037 woset -= that.parentData.left;
3038 }
3039
3040 if (woset + that.size.width >= that.parentData.width) {
3041 that.size.width = that.parentData.width - woset;
3042 if (pRatio) {
3043 that.size.height = that.size.width / that.aspectRatio;
3044 }
3045 }
3046
3047 if (hoset + that.size.height >= that.parentData.height) {
3048 that.size.height = that.parentData.height - hoset;
3049 if (pRatio) {
3050 that.size.width = that.size.height * that.aspectRatio;
3051 }
3052 }
3053 },
3054
3055 stop: function(){
3056 var that = $(this).data("ui-resizable"),
3057 o = that.options,
3058 co = that.containerOffset,
3059 cop = that.containerPosition,
3060 ce = that.containerElement,
3061 helper = $(that.helper),
3062 ho = helper.offset(),
3063 w = helper.outerWidth() - that.sizeDiff.width,
3064 h = helper.outerHeight() - that.sizeDiff.height;
3065
3066 if (that._helper && !o.animate && (/relative/).test(ce.css("position"))) {
3067 $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
3068 }
3069
3070 if (that._helper && !o.animate && (/static/).test(ce.css("position"))) {
3071 $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
3072 }
3073
3074 }
3075});
3076
3077$.ui.plugin.add("resizable", "alsoResize", {
3078
3079 start: function () {
3080 var that = $(this).data("ui-resizable"),
3081 o = that.options,
3082 _store = function (exp) {
3083 $(exp).each(function() {
3084 var el = $(this);
3085 el.data("ui-resizable-alsoresize", {
3086 width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
3087 left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10)
3088 });
3089 });
3090 };
3091
3092 if (typeof(o.alsoResize) === "object" && !o.alsoResize.parentNode) {
3093 if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); }
3094 else { $.each(o.alsoResize, function (exp) { _store(exp); }); }
3095 }else{
3096 _store(o.alsoResize);
3097 }
3098 },
3099
3100 resize: function (event, ui) {
3101 var that = $(this).data("ui-resizable"),
3102 o = that.options,
3103 os = that.originalSize,
3104 op = that.originalPosition,
3105 delta = {
3106 height: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0,
3107 top: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0
3108 },
3109
3110 _alsoResize = function (exp, c) {
3111 $(exp).each(function() {
3112 var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {},
3113 css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ["width", "height"] : ["width", "height", "top", "left"];
3114
3115 $.each(css, function (i, prop) {
3116 var sum = (start[prop]||0) + (delta[prop]||0);
3117 if (sum && sum >= 0) {
3118 style[prop] = sum || null;
3119 }
3120 });
3121
3122 el.css(style);
3123 });
3124 };
3125
3126 if (typeof(o.alsoResize) === "object" && !o.alsoResize.nodeType) {
3127 $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); });
3128 }else{
3129 _alsoResize(o.alsoResize);
3130 }
3131 },
3132
3133 stop: function () {
3134 $(this).removeData("resizable-alsoresize");
3135 }
3136});
3137
3138$.ui.plugin.add("resizable", "ghost", {
3139
3140 start: function() {
3141
3142 var that = $(this).data("ui-resizable"), o = that.options, cs = that.size;
3143
3144 that.ghost = that.originalElement.clone();
3145 that.ghost
3146 .css({ opacity: 0.25, display: "block", position: "relative", height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 })
3147 .addClass("ui-resizable-ghost")
3148 .addClass(typeof o.ghost === "string" ? o.ghost : "");
3149
3150 that.ghost.appendTo(that.helper);
3151
3152 },
3153
3154 resize: function(){
3155 var that = $(this).data("ui-resizable");
3156 if (that.ghost) {
3157 that.ghost.css({ position: "relative", height: that.size.height, width: that.size.width });
3158 }
3159 },
3160
3161 stop: function() {
3162 var that = $(this).data("ui-resizable");
3163 if (that.ghost && that.helper) {
3164 that.helper.get(0).removeChild(that.ghost.get(0));
3165 }
3166 }
3167
3168});
3169
3170$.ui.plugin.add("resizable", "grid", {
3171
3172 resize: function() {
3173 var that = $(this).data("ui-resizable"),
3174 o = that.options,
3175 cs = that.size,
3176 os = that.originalSize,
3177 op = that.originalPosition,
3178 a = that.axis,
3179 grid = typeof o.grid === "number" ? [o.grid, o.grid] : o.grid,
3180 gridX = (grid[0]||1),
3181 gridY = (grid[1]||1),
3182 ox = Math.round((cs.width - os.width) / gridX) * gridX,
3183 oy = Math.round((cs.height - os.height) / gridY) * gridY,
3184 newWidth = os.width + ox,
3185 newHeight = os.height + oy,
3186 isMaxWidth = o.maxWidth && (o.maxWidth < newWidth),
3187 isMaxHeight = o.maxHeight && (o.maxHeight < newHeight),
3188 isMinWidth = o.minWidth && (o.minWidth > newWidth),
3189 isMinHeight = o.minHeight && (o.minHeight > newHeight);
3190
3191 o.grid = grid;
3192
3193 if (isMinWidth) {
3194 newWidth = newWidth + gridX;
3195 }
3196 if (isMinHeight) {
3197 newHeight = newHeight + gridY;
3198 }
3199 if (isMaxWidth) {
3200 newWidth = newWidth - gridX;
3201 }
3202 if (isMaxHeight) {
3203 newHeight = newHeight - gridY;
3204 }
3205
3206 if (/^(se|s|e)$/.test(a)) {
3207 that.size.width = newWidth;
3208 that.size.height = newHeight;
3209 } else if (/^(ne)$/.test(a)) {
3210 that.size.width = newWidth;
3211 that.size.height = newHeight;
3212 that.position.top = op.top - oy;
3213 } else if (/^(sw)$/.test(a)) {
3214 that.size.width = newWidth;
3215 that.size.height = newHeight;
3216 that.position.left = op.left - ox;
3217 } else {
3218 that.size.width = newWidth;
3219 that.size.height = newHeight;
3220 that.position.top = op.top - oy;
3221 that.position.left = op.left - ox;
3222 }
3223 }
3224
3225});
3226
3227})(jQuery);
3228
3229(function( $, undefined ) {
3230
3231$.widget("ui.selectable", $.ui.mouse, {
3232 version: "1.10.1",
3233 options: {
3234 appendTo: "body",
3235 autoRefresh: true,
3236 distance: 0,
3237 filter: "*",
3238 tolerance: "touch",
3239
3240 // callbacks
3241 selected: null,
3242 selecting: null,
3243 start: null,
3244 stop: null,
3245 unselected: null,
3246 unselecting: null
3247 },
3248 _create: function() {
3249 var selectees,
3250 that = this;
3251
3252 this.element.addClass("ui-selectable");
3253
3254 this.dragged = false;
3255
3256 // cache selectee children based on filter
3257 this.refresh = function() {
3258 selectees = $(that.options.filter, that.element[0]);
3259 selectees.addClass("ui-selectee");
3260 selectees.each(function() {
3261 var $this = $(this),
3262 pos = $this.offset();
3263 $.data(this, "selectable-item", {
3264 element: this,
3265 $element: $this,
3266 left: pos.left,
3267 top: pos.top,
3268 right: pos.left + $this.outerWidth(),
3269 bottom: pos.top + $this.outerHeight(),
3270 startselected: false,
3271 selected: $this.hasClass("ui-selected"),
3272 selecting: $this.hasClass("ui-selecting"),
3273 unselecting: $this.hasClass("ui-unselecting")
3274 });
3275 });
3276 };
3277 this.refresh();
3278
3279 this.selectees = selectees.addClass("ui-selectee");
3280
3281 this._mouseInit();
3282
3283 this.helper = $("<div class='ui-selectable-helper'></div>");
3284 },
3285
3286 _destroy: function() {
3287 this.selectees
3288 .removeClass("ui-selectee")
3289 .removeData("selectable-item");
3290 this.element
3291 .removeClass("ui-selectable ui-selectable-disabled");
3292 this._mouseDestroy();
3293 },
3294
3295 _mouseStart: function(event) {
3296 var that = this,
3297 options = this.options;
3298
3299 this.opos = [event.pageX, event.pageY];
3300
3301 if (this.options.disabled) {
3302 return;
3303 }
3304
3305 this.selectees = $(options.filter, this.element[0]);
3306
3307 this._trigger("start", event);
3308
3309 $(options.appendTo).append(this.helper);
3310 // position helper (lasso)
3311 this.helper.css({
3312 "left": event.pageX,
3313 "top": event.pageY,
3314 "width": 0,
3315 "height": 0
3316 });
3317
3318 if (options.autoRefresh) {
3319 this.refresh();
3320 }
3321
3322 this.selectees.filter(".ui-selected").each(function() {
3323 var selectee = $.data(this, "selectable-item");
3324 selectee.startselected = true;
3325 if (!event.metaKey && !event.ctrlKey) {
3326 selectee.$element.removeClass("ui-selected");
3327 selectee.selected = false;
3328 selectee.$element.addClass("ui-unselecting");
3329 selectee.unselecting = true;
3330 // selectable UNSELECTING callback
3331 that._trigger("unselecting", event, {
3332 unselecting: selectee.element
3333 });
3334 }
3335 });
3336
3337 $(event.target).parents().addBack().each(function() {
3338 var doSelect,
3339 selectee = $.data(this, "selectable-item");
3340 if (selectee) {
3341 doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected");
3342 selectee.$element
3343 .removeClass(doSelect ? "ui-unselecting" : "ui-selected")
3344 .addClass(doSelect ? "ui-selecting" : "ui-unselecting");
3345 selectee.unselecting = !doSelect;
3346 selectee.selecting = doSelect;
3347 selectee.selected = doSelect;
3348 // selectable (UN)SELECTING callback
3349 if (doSelect) {
3350 that._trigger("selecting", event, {
3351 selecting: selectee.element
3352 });
3353 } else {
3354 that._trigger("unselecting", event, {
3355 unselecting: selectee.element
3356 });
3357 }
3358 return false;
3359 }
3360 });
3361
3362 },
3363
3364 _mouseDrag: function(event) {
3365
3366 this.dragged = true;
3367
3368 if (this.options.disabled) {
3369 return;
3370 }
3371
3372 var tmp,
3373 that = this,
3374 options = this.options,
3375 x1 = this.opos[0],
3376 y1 = this.opos[1],
3377 x2 = event.pageX,
3378 y2 = event.pageY;
3379
3380 if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; }
3381 if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; }
3382 this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1});
3383
3384 this.selectees.each(function() {
3385 var selectee = $.data(this, "selectable-item"),
3386 hit = false;
3387
3388 //prevent helper from being selected if appendTo: selectable
3389 if (!selectee || selectee.element === that.element[0]) {
3390 return;
3391 }
3392
3393 if (options.tolerance === "touch") {
3394 hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
3395 } else if (options.tolerance === "fit") {
3396 hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
3397 }
3398
3399 if (hit) {
3400 // SELECT
3401 if (selectee.selected) {
3402 selectee.$element.removeClass("ui-selected");
3403 selectee.selected = false;
3404 }
3405 if (selectee.unselecting) {
3406 selectee.$element.removeClass("ui-unselecting");
3407 selectee.unselecting = false;
3408 }
3409 if (!selectee.selecting) {
3410 selectee.$element.addClass("ui-selecting");
3411 selectee.selecting = true;
3412 // selectable SELECTING callback
3413 that._trigger("selecting", event, {
3414 selecting: selectee.element
3415 });
3416 }
3417 } else {
3418 // UNSELECT
3419 if (selectee.selecting) {
3420 if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
3421 selectee.$element.removeClass("ui-selecting");
3422 selectee.selecting = false;
3423 selectee.$element.addClass("ui-selected");
3424 selectee.selected = true;
3425 } else {
3426 selectee.$element.removeClass("ui-selecting");
3427 selectee.selecting = false;
3428 if (selectee.startselected) {
3429 selectee.$element.addClass("ui-unselecting");
3430 selectee.unselecting = true;
3431 }
3432 // selectable UNSELECTING callback
3433 that._trigger("unselecting", event, {
3434 unselecting: selectee.element
3435 });
3436 }
3437 }
3438 if (selectee.selected) {
3439 if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
3440 selectee.$element.removeClass("ui-selected");
3441 selectee.selected = false;
3442
3443 selectee.$element.addClass("ui-unselecting");
3444 selectee.unselecting = true;
3445 // selectable UNSELECTING callback
3446 that._trigger("unselecting", event, {
3447 unselecting: selectee.element
3448 });
3449 }
3450 }
3451 }
3452 });
3453
3454 return false;
3455 },
3456
3457 _mouseStop: function(event) {
3458 var that = this;
3459
3460 this.dragged = false;
3461
3462 $(".ui-unselecting", this.element[0]).each(function() {
3463 var selectee = $.data(this, "selectable-item");
3464 selectee.$element.removeClass("ui-unselecting");
3465 selectee.unselecting = false;
3466 selectee.startselected = false;
3467 that._trigger("unselected", event, {
3468 unselected: selectee.element
3469 });
3470 });
3471 $(".ui-selecting", this.element[0]).each(function() {
3472 var selectee = $.data(this, "selectable-item");
3473 selectee.$element.removeClass("ui-selecting").addClass("ui-selected");
3474 selectee.selecting = false;
3475 selectee.selected = true;
3476 selectee.startselected = true;
3477 that._trigger("selected", event, {
3478 selected: selectee.element
3479 });
3480 });
3481 this._trigger("stop", event);
3482
3483 this.helper.remove();
3484
3485 return false;
3486 }
3487
3488});
3489
3490})(jQuery);
3491
3492(function( $, undefined ) {
3493
3494/*jshint loopfunc: true */
3495
3496function isOverAxis( x, reference, size ) {
3497 return ( x > reference ) && ( x < ( reference + size ) );
3498}
3499
3500$.widget("ui.sortable", $.ui.mouse, {
3501 version: "1.10.1",
3502 widgetEventPrefix: "sort",
3503 ready: false,
3504 options: {
3505 appendTo: "parent",
3506 axis: false,
3507 connectWith: false,
3508 containment: false,
3509 cursor: "auto",
3510 cursorAt: false,
3511 dropOnEmpty: true,
3512 forcePlaceholderSize: false,
3513 forceHelperSize: false,
3514 grid: false,
3515 handle: false,
3516 helper: "original",
3517 items: "> *",
3518 opacity: false,
3519 placeholder: false,
3520 revert: false,
3521 scroll: true,
3522 scrollSensitivity: 20,
3523 scrollSpeed: 20,
3524 scope: "default",
3525 tolerance: "intersect",
3526 zIndex: 1000,
3527
3528 // callbacks
3529 activate: null,
3530 beforeStop: null,
3531 change: null,
3532 deactivate: null,
3533 out: null,
3534 over: null,
3535 receive: null,
3536 remove: null,
3537 sort: null,
3538 start: null,
3539 stop: null,
3540 update: null
3541 },
3542 _create: function() {
3543
3544 var o = this.options;
3545 this.containerCache = {};
3546 this.element.addClass("ui-sortable");
3547
3548 //Get the items
3549 this.refresh();
3550
3551 //Let's determine if the items are being displayed horizontally
3552 this.floating = this.items.length ? o.axis === "x" || (/left|right/).test(this.items[0].item.css("float")) || (/inline|table-cell/).test(this.items[0].item.css("display")) : false;
3553
3554 //Let's determine the parent's offset
3555 this.offset = this.element.offset();
3556
3557 //Initialize mouse events for interaction
3558 this._mouseInit();
3559
3560 //We're ready to go
3561 this.ready = true;
3562
3563 },
3564
3565 _destroy: function() {
3566 this.element
3567 .removeClass("ui-sortable ui-sortable-disabled");
3568 this._mouseDestroy();
3569
3570 for ( var i = this.items.length - 1; i >= 0; i-- ) {
3571 this.items[i].item.removeData(this.widgetName + "-item");
3572 }
3573
3574 return this;
3575 },
3576
3577 _setOption: function(key, value){
3578 if ( key === "disabled" ) {
3579 this.options[ key ] = value;
3580
3581 this.widget().toggleClass( "ui-sortable-disabled", !!value );
3582 } else {
3583 // Don't call widget base _setOption for disable as it adds ui-state-disabled class
3584 $.Widget.prototype._setOption.apply(this, arguments);
3585 }
3586 },
3587
3588 _mouseCapture: function(event, overrideHandle) {
3589 var currentItem = null,
3590 validHandle = false,
3591 that = this;
3592
3593 if (this.reverting) {
3594 return false;
3595 }
3596
3597 if(this.options.disabled || this.options.type === "static") {
3598 return false;
3599 }
3600
3601 //We have to refresh the items data once first
3602 this._refreshItems(event);
3603
3604 //Find out if the clicked node (or one of its parents) is a actual item in this.items
3605 $(event.target).parents().each(function() {
3606 if($.data(this, that.widgetName + "-item") === that) {
3607 currentItem = $(this);
3608 return false;
3609 }
3610 });
3611 if($.data(event.target, that.widgetName + "-item") === that) {
3612 currentItem = $(event.target);
3613 }
3614
3615 if(!currentItem) {
3616 return false;
3617 }
3618 if(this.options.handle && !overrideHandle) {
3619 $(this.options.handle, currentItem).find("*").addBack().each(function() {
3620 if(this === event.target) {
3621 validHandle = true;
3622 }
3623 });
3624 if(!validHandle) {
3625 return false;
3626 }
3627 }
3628
3629 this.currentItem = currentItem;
3630 this._removeCurrentsFromItems();
3631 return true;
3632
3633 },
3634
3635 _mouseStart: function(event, overrideHandle, noActivation) {
3636
3637 var i,
3638 o = this.options;
3639
3640 this.currentContainer = this;
3641
3642 //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
3643 this.refreshPositions();
3644
3645 //Create and append the visible helper
3646 this.helper = this._createHelper(event);
3647
3648 //Cache the helper size
3649 this._cacheHelperProportions();
3650
3651 /*
3652 * - Position generation -
3653 * This block generates everything position related - it's the core of draggables.
3654 */
3655
3656 //Cache the margins of the original element
3657 this._cacheMargins();
3658
3659 //Get the next scrolling parent
3660 this.scrollParent = this.helper.scrollParent();
3661
3662 //The element's absolute position on the page minus margins
3663 this.offset = this.currentItem.offset();
3664 this.offset = {
3665 top: this.offset.top - this.margins.top,
3666 left: this.offset.left - this.margins.left
3667 };
3668
3669 $.extend(this.offset, {
3670 click: { //Where the click happened, relative to the element
3671 left: event.pageX - this.offset.left,
3672 top: event.pageY - this.offset.top
3673 },
3674 parent: this._getParentOffset(),
3675 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
3676 });
3677
3678 // Only after we got the offset, we can change the helper's position to absolute
3679 // TODO: Still need to figure out a way to make relative sorting possible
3680 this.helper.css("position", "absolute");
3681 this.cssPosition = this.helper.css("position");
3682
3683 //Generate the original position
3684 this.originalPosition = this._generatePosition(event);
3685 this.originalPageX = event.pageX;
3686 this.originalPageY = event.pageY;
3687
3688 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
3689 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
3690
3691 //Cache the former DOM position
3692 this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
3693
3694 //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
3695 if(this.helper[0] !== this.currentItem[0]) {
3696 this.currentItem.hide();
3697 }
3698
3699 //Create the placeholder
3700 this._createPlaceholder();
3701
3702 //Set a containment if given in the options
3703 if(o.containment) {
3704 this._setContainment();
3705 }
3706
3707 if(o.cursor) { // cursor option
3708 if ($("body").css("cursor")) {
3709 this._storedCursor = $("body").css("cursor");
3710 }
3711 $("body").css("cursor", o.cursor);
3712 }
3713
3714 if(o.opacity) { // opacity option
3715 if (this.helper.css("opacity")) {
3716 this._storedOpacity = this.helper.css("opacity");
3717 }
3718 this.helper.css("opacity", o.opacity);
3719 }
3720
3721 if(o.zIndex) { // zIndex option
3722 if (this.helper.css("zIndex")) {
3723 this._storedZIndex = this.helper.css("zIndex");
3724 }
3725 this.helper.css("zIndex", o.zIndex);
3726 }
3727
3728 //Prepare scrolling
3729 if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
3730 this.overflowOffset = this.scrollParent.offset();
3731 }
3732
3733 //Call callbacks
3734 this._trigger("start", event, this._uiHash());
3735
3736 //Recache the helper size
3737 if(!this._preserveHelperProportions) {
3738 this._cacheHelperProportions();
3739 }
3740
3741
3742 //Post "activate" events to possible containers
3743 if( !noActivation ) {
3744 for ( i = this.containers.length - 1; i >= 0; i-- ) {
3745 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
3746 }
3747 }
3748
3749 //Prepare possible droppables
3750 if($.ui.ddmanager) {
3751 $.ui.ddmanager.current = this;
3752 }
3753
3754 if ($.ui.ddmanager && !o.dropBehaviour) {
3755 $.ui.ddmanager.prepareOffsets(this, event);
3756 }
3757
3758 this.dragging = true;
3759
3760 this.helper.addClass("ui-sortable-helper");
3761 this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
3762 return true;
3763
3764 },
3765
3766 _mouseDrag: function(event) {
3767 var i, item, itemElement, intersection,
3768 o = this.options,
3769 scrolled = false;
3770
3771 //Compute the helpers position
3772 this.position = this._generatePosition(event);
3773 this.positionAbs = this._convertPositionTo("absolute");
3774
3775 if (!this.lastPositionAbs) {
3776 this.lastPositionAbs = this.positionAbs;
3777 }
3778
3779 //Do scrolling
3780 if(this.options.scroll) {
3781 if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
3782
3783 if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
3784 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
3785 } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
3786 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
3787 }
3788
3789 if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
3790 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
3791 } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
3792 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
3793 }
3794
3795 } else {
3796
3797 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
3798 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
3799 } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
3800 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
3801 }
3802
3803 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
3804 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
3805 } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
3806 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
3807 }
3808
3809 }
3810
3811 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
3812 $.ui.ddmanager.prepareOffsets(this, event);
3813 }
3814 }
3815
3816 //Regenerate the absolute position used for position checks
3817 this.positionAbs = this._convertPositionTo("absolute");
3818
3819 //Set the helper position
3820 if(!this.options.axis || this.options.axis !== "y") {
3821 this.helper[0].style.left = this.position.left+"px";
3822 }
3823 if(!this.options.axis || this.options.axis !== "x") {
3824 this.helper[0].style.top = this.position.top+"px";
3825 }
3826
3827 //Rearrange
3828 for (i = this.items.length - 1; i >= 0; i--) {
3829
3830 //Cache variables and intersection, continue if no intersection
3831 item = this.items[i];
3832 itemElement = item.item[0];
3833 intersection = this._intersectsWithPointer(item);
3834 if (!intersection) {
3835 continue;
3836 }
3837
3838 // Only put the placeholder inside the current Container, skip all
3839 // items form other containers. This works because when moving
3840 // an item from one container to another the
3841 // currentContainer is switched before the placeholder is moved.
3842 //
3843 // Without this moving items in "sub-sortables" can cause the placeholder to jitter
3844 // beetween the outer and inner container.
3845 if (item.instance !== this.currentContainer) {
3846 continue;
3847 }
3848
3849 // cannot intersect with itself
3850 // no useless actions that have been done before
3851 // no action if the item moved is the parent of the item checked
3852 if (itemElement !== this.currentItem[0] &&
3853 this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement &&
3854 !$.contains(this.placeholder[0], itemElement) &&
3855 (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true)
3856 ) {
3857
3858 this.direction = intersection === 1 ? "down" : "up";
3859
3860 if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
3861 this._rearrange(event, item);
3862 } else {
3863 break;
3864 }
3865
3866 this._trigger("change", event, this._uiHash());
3867 break;
3868 }
3869 }
3870
3871 //Post events to containers
3872 this._contactContainers(event);
3873
3874 //Interconnect with droppables
3875 if($.ui.ddmanager) {
3876 $.ui.ddmanager.drag(this, event);
3877 }
3878
3879 //Call callbacks
3880 this._trigger("sort", event, this._uiHash());
3881
3882 this.lastPositionAbs = this.positionAbs;
3883 return false;
3884
3885 },
3886
3887 _mouseStop: function(event, noPropagation) {
3888
3889 if(!event) {
3890 return;
3891 }
3892
3893 //If we are using droppables, inform the manager about the drop
3894 if ($.ui.ddmanager && !this.options.dropBehaviour) {
3895 $.ui.ddmanager.drop(this, event);
3896 }
3897
3898 if(this.options.revert) {
3899 var that = this,
3900 cur = this.placeholder.offset();
3901
3902 this.reverting = true;
3903
3904 $(this.helper).animate({
3905 left: cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft),
3906 top: cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop)
3907 }, parseInt(this.options.revert, 10) || 500, function() {
3908 that._clear(event);
3909 });
3910 } else {
3911 this._clear(event, noPropagation);
3912 }
3913
3914 return false;
3915
3916 },
3917
3918 cancel: function() {
3919
3920 if(this.dragging) {
3921
3922 this._mouseUp({ target: null });
3923
3924 if(this.options.helper === "original") {
3925 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
3926 } else {
3927 this.currentItem.show();
3928 }
3929
3930 //Post deactivating events to containers
3931 for (var i = this.containers.length - 1; i >= 0; i--){
3932 this.containers[i]._trigger("deactivate", null, this._uiHash(this));
3933 if(this.containers[i].containerCache.over) {
3934 this.containers[i]._trigger("out", null, this._uiHash(this));
3935 this.containers[i].containerCache.over = 0;
3936 }
3937 }
3938
3939 }
3940
3941 if (this.placeholder) {
3942 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
3943 if(this.placeholder[0].parentNode) {
3944 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
3945 }
3946 if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) {
3947 this.helper.remove();
3948 }
3949
3950 $.extend(this, {
3951 helper: null,
3952 dragging: false,
3953 reverting: false,
3954 _noFinalSort: null
3955 });
3956
3957 if(this.domPosition.prev) {
3958 $(this.domPosition.prev).after(this.currentItem);
3959 } else {
3960 $(this.domPosition.parent).prepend(this.currentItem);
3961 }
3962 }
3963
3964 return this;
3965
3966 },
3967
3968 serialize: function(o) {
3969
3970 var items = this._getItemsAsjQuery(o && o.connected),
3971 str = [];
3972 o = o || {};
3973
3974 $(items).each(function() {
3975 var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/));
3976 if (res) {
3977 str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2]));
3978 }
3979 });
3980
3981 if(!str.length && o.key) {
3982 str.push(o.key + "=");
3983 }
3984
3985 return str.join("&");
3986
3987 },
3988
3989 toArray: function(o) {
3990
3991 var items = this._getItemsAsjQuery(o && o.connected),
3992 ret = [];
3993
3994 o = o || {};
3995
3996 items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); });
3997 return ret;
3998
3999 },
4000
4001 /* Be careful with the following core functions */
4002 _intersectsWith: function(item) {
4003
4004 var x1 = this.positionAbs.left,
4005 x2 = x1 + this.helperProportions.width,
4006 y1 = this.positionAbs.top,
4007 y2 = y1 + this.helperProportions.height,
4008 l = item.left,
4009 r = l + item.width,
4010 t = item.top,
4011 b = t + item.height,
4012 dyClick = this.offset.click.top,
4013 dxClick = this.offset.click.left,
4014 isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r;
4015
4016 if ( this.options.tolerance === "pointer" ||
4017 this.options.forcePointerForContainers ||
4018 (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"])
4019 ) {
4020 return isOverElement;
4021 } else {
4022
4023 return (l < x1 + (this.helperProportions.width / 2) && // Right Half
4024 x2 - (this.helperProportions.width / 2) < r && // Left Half
4025 t < y1 + (this.helperProportions.height / 2) && // Bottom Half
4026 y2 - (this.helperProportions.height / 2) < b ); // Top Half
4027
4028 }
4029 },
4030
4031 _intersectsWithPointer: function(item) {
4032
4033 var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
4034 isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
4035 isOverElement = isOverElementHeight && isOverElementWidth,
4036 verticalDirection = this._getDragVerticalDirection(),
4037 horizontalDirection = this._getDragHorizontalDirection();
4038
4039 if (!isOverElement) {
4040 return false;
4041 }
4042
4043 return this.floating ?
4044 ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 )
4045 : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) );
4046
4047 },
4048
4049 _intersectsWithSides: function(item) {
4050
4051 var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
4052 isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
4053 verticalDirection = this._getDragVerticalDirection(),
4054 horizontalDirection = this._getDragHorizontalDirection();
4055
4056 if (this.floating && horizontalDirection) {
4057 return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf));
4058 } else {
4059 return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf));
4060 }
4061
4062 },
4063
4064 _getDragVerticalDirection: function() {
4065 var delta = this.positionAbs.top - this.lastPositionAbs.top;
4066 return delta !== 0 && (delta > 0 ? "down" : "up");
4067 },
4068
4069 _getDragHorizontalDirection: function() {
4070 var delta = this.positionAbs.left - this.lastPositionAbs.left;
4071 return delta !== 0 && (delta > 0 ? "right" : "left");
4072 },
4073
4074 refresh: function(event) {
4075 this._refreshItems(event);
4076 this.refreshPositions();
4077 return this;
4078 },
4079
4080 _connectWith: function() {
4081 var options = this.options;
4082 return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith;
4083 },
4084
4085 _getItemsAsjQuery: function(connected) {
4086
4087 var i, j, cur, inst,
4088 items = [],
4089 queries = [],
4090 connectWith = this._connectWith();
4091
4092 if(connectWith && connected) {
4093 for (i = connectWith.length - 1; i >= 0; i--){
4094 cur = $(connectWith[i]);
4095 for ( j = cur.length - 1; j >= 0; j--){
4096 inst = $.data(cur[j], this.widgetFullName);
4097 if(inst && inst !== this && !inst.options.disabled) {
4098 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]);
4099 }
4100 }
4101 }
4102 }
4103
4104 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]);
4105
4106 for (i = queries.length - 1; i >= 0; i--){
4107 queries[i][0].each(function() {
4108 items.push(this);
4109 });
4110 }
4111
4112 return $(items);
4113
4114 },
4115
4116 _removeCurrentsFromItems: function() {
4117
4118 var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
4119
4120 this.items = $.grep(this.items, function (item) {
4121 for (var j=0; j < list.length; j++) {
4122 if(list[j] === item.item[0]) {
4123 return false;
4124 }
4125 }
4126 return true;
4127 });
4128
4129 },
4130
4131 _refreshItems: function(event) {
4132
4133 this.items = [];
4134 this.containers = [this];
4135
4136 var i, j, cur, inst, targetData, _queries, item, queriesLength,
4137 items = this.items,
4138 queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]],
4139 connectWith = this._connectWith();
4140
4141 if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
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[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
4148 this.containers.push(inst);
4149 }
4150 }
4151 }
4152 }
4153
4154 for (i = queries.length - 1; i >= 0; i--) {
4155 targetData = queries[i][1];
4156 _queries = queries[i][0];
4157
4158 for (j=0, queriesLength = _queries.length; j < queriesLength; j++) {
4159 item = $(_queries[j]);
4160
4161 item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager)
4162
4163 items.push({
4164 item: item,
4165 instance: targetData,
4166 width: 0, height: 0,
4167 left: 0, top: 0
4168 });
4169 }
4170 }
4171
4172 },
4173
4174 refreshPositions: function(fast) {
4175
4176 //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
4177 if(this.offsetParent && this.helper) {
4178 this.offset.parent = this._getParentOffset();
4179 }
4180
4181 var i, item, t, p;
4182
4183 for (i = this.items.length - 1; i >= 0; i--){
4184 item = this.items[i];
4185
4186 //We ignore calculating positions of all connected containers when we're not over them
4187 if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) {
4188 continue;
4189 }
4190
4191 t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
4192
4193 if (!fast) {
4194 item.width = t.outerWidth();
4195 item.height = t.outerHeight();
4196 }
4197
4198 p = t.offset();
4199 item.left = p.left;
4200 item.top = p.top;
4201 }
4202
4203 if(this.options.custom && this.options.custom.refreshContainers) {
4204 this.options.custom.refreshContainers.call(this);
4205 } else {
4206 for (i = this.containers.length - 1; i >= 0; i--){
4207 p = this.containers[i].element.offset();
4208 this.containers[i].containerCache.left = p.left;
4209 this.containers[i].containerCache.top = p.top;
4210 this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
4211 this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
4212 }
4213 }
4214
4215 return this;
4216 },
4217
4218 _createPlaceholder: function(that) {
4219 that = that || this;
4220 var className,
4221 o = that.options;
4222
4223 if(!o.placeholder || o.placeholder.constructor === String) {
4224 className = o.placeholder;
4225 o.placeholder = {
4226 element: function() {
4227
4228 var el = $(document.createElement(that.currentItem[0].nodeName))
4229 .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
4230 .removeClass("ui-sortable-helper")[0];
4231
4232 if(!className) {
4233 el.style.visibility = "hidden";
4234 }
4235
4236 return el;
4237 },
4238 update: function(container, p) {
4239
4240 // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
4241 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
4242 if(className && !o.forcePlaceholderSize) {
4243 return;
4244 }
4245
4246 //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
4247 if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); }
4248 if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); }
4249 }
4250 };
4251 }
4252
4253 //Create the placeholder
4254 that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));
4255
4256 //Append it after the actual current item
4257 that.currentItem.after(that.placeholder);
4258
4259 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
4260 o.placeholder.update(that, that.placeholder);
4261
4262 },
4263
4264 _contactContainers: function(event) {
4265 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom,
4266 innermostContainer = null,
4267 innermostIndex = null;
4268
4269 // get innermost container that intersects with item
4270 for (i = this.containers.length - 1; i >= 0; i--) {
4271
4272 // never consider a container that's located within the item itself
4273 if($.contains(this.currentItem[0], this.containers[i].element[0])) {
4274 continue;
4275 }
4276
4277 if(this._intersectsWith(this.containers[i].containerCache)) {
4278
4279 // if we've already found a container and it's more "inner" than this, then continue
4280 if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) {
4281 continue;
4282 }
4283
4284 innermostContainer = this.containers[i];
4285 innermostIndex = i;
4286
4287 } else {
4288 // container doesn't intersect. trigger "out" event if necessary
4289 if(this.containers[i].containerCache.over) {
4290 this.containers[i]._trigger("out", event, this._uiHash(this));
4291 this.containers[i].containerCache.over = 0;
4292 }
4293 }
4294
4295 }
4296
4297 // if no intersecting containers found, return
4298 if(!innermostContainer) {
4299 return;
4300 }
4301
4302 // move the item into the container if it's not there already
4303 if(this.containers.length === 1) {
4304 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
4305 this.containers[innermostIndex].containerCache.over = 1;
4306 } else {
4307
4308 //When entering a new container, we will find the item with the least distance and append our item near it
4309 dist = 10000;
4310 itemWithLeastDistance = null;
4311 posProperty = this.containers[innermostIndex].floating ? "left" : "top";
4312 sizeProperty = this.containers[innermostIndex].floating ? "width" : "height";
4313 base = this.positionAbs[posProperty] + this.offset.click[posProperty];
4314 for (j = this.items.length - 1; j >= 0; j--) {
4315 if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) {
4316 continue;
4317 }
4318 if(this.items[j].item[0] === this.currentItem[0]) {
4319 continue;
4320 }
4321 cur = this.items[j].item.offset()[posProperty];
4322 nearBottom = false;
4323 if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){
4324 nearBottom = true;
4325 cur += this.items[j][sizeProperty];
4326 }
4327
4328 if(Math.abs(cur - base) < dist) {
4329 dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j];
4330 this.direction = nearBottom ? "up": "down";
4331 }
4332 }
4333
4334 //Check if dropOnEmpty is enabled
4335 if(!itemWithLeastDistance && !this.options.dropOnEmpty) {
4336 return;
4337 }
4338
4339 this.currentContainer = this.containers[innermostIndex];
4340 itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
4341 this._trigger("change", event, this._uiHash());
4342 this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
4343
4344 //Update the placeholder
4345 this.options.placeholder.update(this.currentContainer, this.placeholder);
4346
4347 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
4348 this.containers[innermostIndex].containerCache.over = 1;
4349 }
4350
4351
4352 },
4353
4354 _createHelper: function(event) {
4355
4356 var o = this.options,
4357 helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem);
4358
4359 //Add the helper to the DOM if that didn't happen already
4360 if(!helper.parents("body").length) {
4361 $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
4362 }
4363
4364 if(helper[0] === this.currentItem[0]) {
4365 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") };
4366 }
4367
4368 if(!helper[0].style.width || o.forceHelperSize) {
4369 helper.width(this.currentItem.width());
4370 }
4371 if(!helper[0].style.height || o.forceHelperSize) {
4372 helper.height(this.currentItem.height());
4373 }
4374
4375 return helper;
4376
4377 },
4378
4379 _adjustOffsetFromHelper: function(obj) {
4380 if (typeof obj === "string") {
4381 obj = obj.split(" ");
4382 }
4383 if ($.isArray(obj)) {
4384 obj = {left: +obj[0], top: +obj[1] || 0};
4385 }
4386 if ("left" in obj) {
4387 this.offset.click.left = obj.left + this.margins.left;
4388 }
4389 if ("right" in obj) {
4390 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
4391 }
4392 if ("top" in obj) {
4393 this.offset.click.top = obj.top + this.margins.top;
4394 }
4395 if ("bottom" in obj) {
4396 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
4397 }
4398 },
4399
4400 _getParentOffset: function() {
4401
4402
4403 //Get the offsetParent and cache its position
4404 this.offsetParent = this.helper.offsetParent();
4405 var po = this.offsetParent.offset();
4406
4407 // This is a special case where we need to modify a offset calculated on start, since the following happened:
4408 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
4409 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
4410 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
4411 if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
4412 po.left += this.scrollParent.scrollLeft();
4413 po.top += this.scrollParent.scrollTop();
4414 }
4415
4416 // This needs to be actually done for all browsers, since pageX/pageY includes this information
4417 // with an ugly IE fix
4418 if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
4419 po = { top: 0, left: 0 };
4420 }
4421
4422 return {
4423 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
4424 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
4425 };
4426
4427 },
4428
4429 _getRelativeOffset: function() {
4430
4431 if(this.cssPosition === "relative") {
4432 var p = this.currentItem.position();
4433 return {
4434 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
4435 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
4436 };
4437 } else {
4438 return { top: 0, left: 0 };
4439 }
4440
4441 },
4442
4443 _cacheMargins: function() {
4444 this.margins = {
4445 left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
4446 top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
4447 };
4448 },
4449
4450 _cacheHelperProportions: function() {
4451 this.helperProportions = {
4452 width: this.helper.outerWidth(),
4453 height: this.helper.outerHeight()
4454 };
4455 },
4456
4457 _setContainment: function() {
4458
4459 var ce, co, over,
4460 o = this.options;
4461 if(o.containment === "parent") {
4462 o.containment = this.helper[0].parentNode;
4463 }
4464 if(o.containment === "document" || o.containment === "window") {
4465 this.containment = [
4466 0 - this.offset.relative.left - this.offset.parent.left,
4467 0 - this.offset.relative.top - this.offset.parent.top,
4468 $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left,
4469 ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
4470 ];
4471 }
4472
4473 if(!(/^(document|window|parent)$/).test(o.containment)) {
4474 ce = $(o.containment)[0];
4475 co = $(o.containment).offset();
4476 over = ($(ce).css("overflow") !== "hidden");
4477
4478 this.containment = [
4479 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
4480 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
4481 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,
4482 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
4483 ];
4484 }
4485
4486 },
4487
4488 _convertPositionTo: function(d, pos) {
4489
4490 if(!pos) {
4491 pos = this.position;
4492 }
4493 var mod = d === "absolute" ? 1 : -1,
4494 scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,
4495 scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
4496
4497 return {
4498 top: (
4499 pos.top + // The absolute mouse position
4500 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
4501 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
4502 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
4503 ),
4504 left: (
4505 pos.left + // The absolute mouse position
4506 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
4507 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
4508 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
4509 )
4510 };
4511
4512 },
4513
4514 _generatePosition: function(event) {
4515
4516 var top, left,
4517 o = this.options,
4518 pageX = event.pageX,
4519 pageY = event.pageY,
4520 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);
4521
4522 // This is another very weird special case that only happens for relative elements:
4523 // 1. If the css position is relative
4524 // 2. and the scroll parent is the document or similar to the offset parent
4525 // we have to refresh the relative offset during the scroll so there are no jumps
4526 if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) {
4527 this.offset.relative = this._getRelativeOffset();
4528 }
4529
4530 /*
4531 * - Position constraining -
4532 * Constrain the position to a mix of grid, containment.
4533 */
4534
4535 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
4536
4537 if(this.containment) {
4538 if(event.pageX - this.offset.click.left < this.containment[0]) {
4539 pageX = this.containment[0] + this.offset.click.left;
4540 }
4541 if(event.pageY - this.offset.click.top < this.containment[1]) {
4542 pageY = this.containment[1] + this.offset.click.top;
4543 }
4544 if(event.pageX - this.offset.click.left > this.containment[2]) {
4545 pageX = this.containment[2] + this.offset.click.left;
4546 }
4547 if(event.pageY - this.offset.click.top > this.containment[3]) {
4548 pageY = this.containment[3] + this.offset.click.top;
4549 }
4550 }
4551
4552 if(o.grid) {
4553 top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
4554 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;
4555
4556 left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
4557 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;
4558 }
4559
4560 }
4561
4562 return {
4563 top: (
4564 pageY - // The absolute mouse position
4565 this.offset.click.top - // Click offset (relative to the element)
4566 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
4567 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
4568 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
4569 ),
4570 left: (
4571 pageX - // The absolute mouse position
4572 this.offset.click.left - // Click offset (relative to the element)
4573 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
4574 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
4575 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
4576 )
4577 };
4578
4579 },
4580
4581 _rearrange: function(event, i, a, hardRefresh) {
4582
4583 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));
4584
4585 //Various things done here to improve the performance:
4586 // 1. we create a setTimeout, that calls refreshPositions
4587 // 2. on the instance, we have a counter variable, that get's higher after every append
4588 // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
4589 // 4. this lets only the last addition to the timeout stack through
4590 this.counter = this.counter ? ++this.counter : 1;
4591 var counter = this.counter;
4592
4593 this._delay(function() {
4594 if(counter === this.counter) {
4595 this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
4596 }
4597 });
4598
4599 },
4600
4601 _clear: function(event, noPropagation) {
4602
4603 this.reverting = false;
4604 // We delay all events that have to be triggered to after the point where the placeholder has been removed and
4605 // everything else normalized again
4606 var i,
4607 delayedTriggers = [];
4608
4609 // We first have to update the dom position of the actual currentItem
4610 // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
4611 if(!this._noFinalSort && this.currentItem.parent().length) {
4612 this.placeholder.before(this.currentItem);
4613 }
4614 this._noFinalSort = null;
4615
4616 if(this.helper[0] === this.currentItem[0]) {
4617 for(i in this._storedCSS) {
4618 if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") {
4619 this._storedCSS[i] = "";
4620 }
4621 }
4622 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
4623 } else {
4624 this.currentItem.show();
4625 }
4626
4627 if(this.fromOutside && !noPropagation) {
4628 delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
4629 }
4630 if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) {
4631 delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
4632 }
4633
4634 // Check if the items Container has Changed and trigger appropriate
4635 // events.
4636 if (this !== this.currentContainer) {
4637 if(!noPropagation) {
4638 delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
4639 delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
4640 delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
4641 }
4642 }
4643
4644
4645 //Post events to containers
4646 for (i = this.containers.length - 1; i >= 0; i--){
4647 if(!noPropagation) {
4648 delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
4649 }
4650 if(this.containers[i].containerCache.over) {
4651 delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
4652 this.containers[i].containerCache.over = 0;
4653 }
4654 }
4655
4656 //Do what was originally in plugins
4657 if(this._storedCursor) {
4658 $("body").css("cursor", this._storedCursor);
4659 }
4660 if(this._storedOpacity) {
4661 this.helper.css("opacity", this._storedOpacity);
4662 }
4663 if(this._storedZIndex) {
4664 this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex);
4665 }
4666
4667 this.dragging = false;
4668 if(this.cancelHelperRemoval) {
4669 if(!noPropagation) {
4670 this._trigger("beforeStop", event, this._uiHash());
4671 for (i=0; i < delayedTriggers.length; i++) {
4672 delayedTriggers[i].call(this, event);
4673 } //Trigger all delayed events
4674 this._trigger("stop", event, this._uiHash());
4675 }
4676
4677 this.fromOutside = false;
4678 return false;
4679 }
4680
4681 if(!noPropagation) {
4682 this._trigger("beforeStop", event, this._uiHash());
4683 }
4684
4685 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
4686 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
4687
4688 if(this.helper[0] !== this.currentItem[0]) {
4689 this.helper.remove();
4690 }
4691 this.helper = null;
4692
4693 if(!noPropagation) {
4694 for (i=0; i < delayedTriggers.length; i++) {
4695 delayedTriggers[i].call(this, event);
4696 } //Trigger all delayed events
4697 this._trigger("stop", event, this._uiHash());
4698 }
4699
4700 this.fromOutside = false;
4701 return true;
4702
4703 },
4704
4705 _trigger: function() {
4706 if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
4707 this.cancel();
4708 }
4709 },
4710
4711 _uiHash: function(_inst) {
4712 var inst = _inst || this;
4713 return {
4714 helper: inst.helper,
4715 placeholder: inst.placeholder || $([]),
4716 position: inst.position,
4717 originalPosition: inst.originalPosition,
4718 offset: inst.positionAbs,
4719 item: inst.currentItem,
4720 sender: _inst ? _inst.element : null
4721 };
4722 }
4723
4724});
4725
4726})(jQuery);
4727
4728;(jQuery.effects || (function($, undefined) {
4729
4730var dataSpace = "ui-effects-";
4731
4732$.effects = {
4733 effect: {}
4734};
4735
4736/*!
4737 * jQuery Color Animations v2.1.2
4738 * https://github.com/jquery/jquery-color
4739 *
4740 * Copyright 2013 jQuery Foundation and other contributors
4741 * Released under the MIT license.
4742 * http://jquery.org/license
4743 *
4744 * Date: Wed Jan 16 08:47:09 2013 -0600
4745 */
4746(function( jQuery, undefined ) {
4747
4748 var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
4749
4750 // plusequals test for += 100 -= 100
4751 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
4752 // a set of RE's that can match strings and generate color tuples.
4753 stringParsers = [{
4754 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
4755 parse: function( execResult ) {
4756 return [
4757 execResult[ 1 ],
4758 execResult[ 2 ],
4759 execResult[ 3 ],
4760 execResult[ 4 ]
4761 ];
4762 }
4763 }, {
4764 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
4765 parse: function( execResult ) {
4766 return [
4767 execResult[ 1 ] * 2.55,
4768 execResult[ 2 ] * 2.55,
4769 execResult[ 3 ] * 2.55,
4770 execResult[ 4 ]
4771 ];
4772 }
4773 }, {
4774 // this regex ignores A-F because it's compared against an already lowercased string
4775 re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
4776 parse: function( execResult ) {
4777 return [
4778 parseInt( execResult[ 1 ], 16 ),
4779 parseInt( execResult[ 2 ], 16 ),
4780 parseInt( execResult[ 3 ], 16 )
4781 ];
4782 }
4783 }, {
4784 // this regex ignores A-F because it's compared against an already lowercased string
4785 re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
4786 parse: function( execResult ) {
4787 return [
4788 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
4789 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
4790 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
4791 ];
4792 }
4793 }, {
4794 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
4795 space: "hsla",
4796 parse: function( execResult ) {
4797 return [
4798 execResult[ 1 ],
4799 execResult[ 2 ] / 100,
4800 execResult[ 3 ] / 100,
4801 execResult[ 4 ]
4802 ];
4803 }
4804 }],
4805
4806 // jQuery.Color( )
4807 color = jQuery.Color = function( color, green, blue, alpha ) {
4808 return new jQuery.Color.fn.parse( color, green, blue, alpha );
4809 },
4810 spaces = {
4811 rgba: {
4812 props: {
4813 red: {
4814 idx: 0,
4815 type: "byte"
4816 },
4817 green: {
4818 idx: 1,
4819 type: "byte"
4820 },
4821 blue: {
4822 idx: 2,
4823 type: "byte"
4824 }
4825 }
4826 },
4827
4828 hsla: {
4829 props: {
4830 hue: {
4831 idx: 0,
4832 type: "degrees"
4833 },
4834 saturation: {
4835 idx: 1,
4836 type: "percent"
4837 },
4838 lightness: {
4839 idx: 2,
4840 type: "percent"
4841 }
4842 }
4843 }
4844 },
4845 propTypes = {
4846 "byte": {
4847 floor: true,
4848 max: 255
4849 },
4850 "percent": {
4851 max: 1
4852 },
4853 "degrees": {
4854 mod: 360,
4855 floor: true
4856 }
4857 },
4858 support = color.support = {},
4859
4860 // element for support tests
4861 supportElem = jQuery( "<p>" )[ 0 ],
4862
4863 // colors = jQuery.Color.names
4864 colors,
4865
4866 // local aliases of functions called often
4867 each = jQuery.each;
4868
4869// determine rgba support immediately
4870supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
4871support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
4872
4873// define cache name and alpha properties
4874// for rgba and hsla spaces
4875each( spaces, function( spaceName, space ) {
4876 space.cache = "_" + spaceName;
4877 space.props.alpha = {
4878 idx: 3,
4879 type: "percent",
4880 def: 1
4881 };
4882});
4883
4884function clamp( value, prop, allowEmpty ) {
4885 var type = propTypes[ prop.type ] || {};
4886
4887 if ( value == null ) {
4888 return (allowEmpty || !prop.def) ? null : prop.def;
4889 }
4890
4891 // ~~ is an short way of doing floor for positive numbers
4892 value = type.floor ? ~~value : parseFloat( value );
4893
4894 // IE will pass in empty strings as value for alpha,
4895 // which will hit this case
4896 if ( isNaN( value ) ) {
4897 return prop.def;
4898 }
4899
4900 if ( type.mod ) {
4901 // we add mod before modding to make sure that negatives values
4902 // get converted properly: -10 -> 350
4903 return (value + type.mod) % type.mod;
4904 }
4905
4906 // for now all property types without mod have min and max
4907 return 0 > value ? 0 : type.max < value ? type.max : value;
4908}
4909
4910function stringParse( string ) {
4911 var inst = color(),
4912 rgba = inst._rgba = [];
4913
4914 string = string.toLowerCase();
4915
4916 each( stringParsers, function( i, parser ) {
4917 var parsed,
4918 match = parser.re.exec( string ),
4919 values = match && parser.parse( match ),
4920 spaceName = parser.space || "rgba";
4921
4922 if ( values ) {
4923 parsed = inst[ spaceName ]( values );
4924
4925 // if this was an rgba parse the assignment might happen twice
4926 // oh well....
4927 inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
4928 rgba = inst._rgba = parsed._rgba;
4929
4930 // exit each( stringParsers ) here because we matched
4931 return false;
4932 }
4933 });
4934
4935 // Found a stringParser that handled it
4936 if ( rgba.length ) {
4937
4938 // if this came from a parsed string, force "transparent" when alpha is 0
4939 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
4940 if ( rgba.join() === "0,0,0,0" ) {
4941 jQuery.extend( rgba, colors.transparent );
4942 }
4943 return inst;
4944 }
4945
4946 // named colors
4947 return colors[ string ];
4948}
4949
4950color.fn = jQuery.extend( color.prototype, {
4951 parse: function( red, green, blue, alpha ) {
4952 if ( red === undefined ) {
4953 this._rgba = [ null, null, null, null ];
4954 return this;
4955 }
4956 if ( red.jquery || red.nodeType ) {
4957 red = jQuery( red ).css( green );
4958 green = undefined;
4959 }
4960
4961 var inst = this,
4962 type = jQuery.type( red ),
4963 rgba = this._rgba = [];
4964
4965 // more than 1 argument specified - assume ( red, green, blue, alpha )
4966 if ( green !== undefined ) {
4967 red = [ red, green, blue, alpha ];
4968 type = "array";
4969 }
4970
4971 if ( type === "string" ) {
4972 return this.parse( stringParse( red ) || colors._default );
4973 }
4974
4975 if ( type === "array" ) {
4976 each( spaces.rgba.props, function( key, prop ) {
4977 rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
4978 });
4979 return this;
4980 }
4981
4982 if ( type === "object" ) {
4983 if ( red instanceof color ) {
4984 each( spaces, function( spaceName, space ) {
4985 if ( red[ space.cache ] ) {
4986 inst[ space.cache ] = red[ space.cache ].slice();
4987 }
4988 });
4989 } else {
4990 each( spaces, function( spaceName, space ) {
4991 var cache = space.cache;
4992 each( space.props, function( key, prop ) {
4993
4994 // if the cache doesn't exist, and we know how to convert
4995 if ( !inst[ cache ] && space.to ) {
4996
4997 // if the value was null, we don't need to copy it
4998 // if the key was alpha, we don't need to copy it either
4999 if ( key === "alpha" || red[ key ] == null ) {
5000 return;
5001 }
5002 inst[ cache ] = space.to( inst._rgba );
5003 }
5004
5005 // this is the only case where we allow nulls for ALL properties.
5006 // call clamp with alwaysAllowEmpty
5007 inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
5008 });
5009
5010 // everything defined but alpha?
5011 if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
5012 // use the default of 1
5013 inst[ cache ][ 3 ] = 1;
5014 if ( space.from ) {
5015 inst._rgba = space.from( inst[ cache ] );
5016 }
5017 }
5018 });
5019 }
5020 return this;
5021 }
5022 },
5023 is: function( compare ) {
5024 var is = color( compare ),
5025 same = true,
5026 inst = this;
5027
5028 each( spaces, function( _, space ) {
5029 var localCache,
5030 isCache = is[ space.cache ];
5031 if (isCache) {
5032 localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
5033 each( space.props, function( _, prop ) {
5034 if ( isCache[ prop.idx ] != null ) {
5035 same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
5036 return same;
5037 }
5038 });
5039 }
5040 return same;
5041 });
5042 return same;
5043 },
5044 _space: function() {
5045 var used = [],
5046 inst = this;
5047 each( spaces, function( spaceName, space ) {
5048 if ( inst[ space.cache ] ) {
5049 used.push( spaceName );
5050 }
5051 });
5052 return used.pop();
5053 },
5054 transition: function( other, distance ) {
5055 var end = color( other ),
5056 spaceName = end._space(),
5057 space = spaces[ spaceName ],
5058 startColor = this.alpha() === 0 ? color( "transparent" ) : this,
5059 start = startColor[ space.cache ] || space.to( startColor._rgba ),
5060 result = start.slice();
5061
5062 end = end[ space.cache ];
5063 each( space.props, function( key, prop ) {
5064 var index = prop.idx,
5065 startValue = start[ index ],
5066 endValue = end[ index ],
5067 type = propTypes[ prop.type ] || {};
5068
5069 // if null, don't override start value
5070 if ( endValue === null ) {
5071 return;
5072 }
5073 // if null - use end
5074 if ( startValue === null ) {
5075 result[ index ] = endValue;
5076 } else {
5077 if ( type.mod ) {
5078 if ( endValue - startValue > type.mod / 2 ) {
5079 startValue += type.mod;
5080 } else if ( startValue - endValue > type.mod / 2 ) {
5081 startValue -= type.mod;
5082 }
5083 }
5084 result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
5085 }
5086 });
5087 return this[ spaceName ]( result );
5088 },
5089 blend: function( opaque ) {
5090 // if we are already opaque - return ourself
5091 if ( this._rgba[ 3 ] === 1 ) {
5092 return this;
5093 }
5094
5095 var rgb = this._rgba.slice(),
5096 a = rgb.pop(),
5097 blend = color( opaque )._rgba;
5098
5099 return color( jQuery.map( rgb, function( v, i ) {
5100 return ( 1 - a ) * blend[ i ] + a * v;
5101 }));
5102 },
5103 toRgbaString: function() {
5104 var prefix = "rgba(",
5105 rgba = jQuery.map( this._rgba, function( v, i ) {
5106 return v == null ? ( i > 2 ? 1 : 0 ) : v;
5107 });
5108
5109 if ( rgba[ 3 ] === 1 ) {
5110 rgba.pop();
5111 prefix = "rgb(";
5112 }
5113
5114 return prefix + rgba.join() + ")";
5115 },
5116 toHslaString: function() {
5117 var prefix = "hsla(",
5118 hsla = jQuery.map( this.hsla(), function( v, i ) {
5119 if ( v == null ) {
5120 v = i > 2 ? 1 : 0;
5121 }
5122
5123 // catch 1 and 2
5124 if ( i && i < 3 ) {
5125 v = Math.round( v * 100 ) + "%";
5126 }
5127 return v;
5128 });
5129
5130 if ( hsla[ 3 ] === 1 ) {
5131 hsla.pop();
5132 prefix = "hsl(";
5133 }
5134 return prefix + hsla.join() + ")";
5135 },
5136 toHexString: function( includeAlpha ) {
5137 var rgba = this._rgba.slice(),
5138 alpha = rgba.pop();
5139
5140 if ( includeAlpha ) {
5141 rgba.push( ~~( alpha * 255 ) );
5142 }
5143
5144 return "#" + jQuery.map( rgba, function( v ) {
5145
5146 // default to 0 when nulls exist
5147 v = ( v || 0 ).toString( 16 );
5148 return v.length === 1 ? "0" + v : v;
5149 }).join("");
5150 },
5151 toString: function() {
5152 return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
5153 }
5154});
5155color.fn.parse.prototype = color.fn;
5156
5157// hsla conversions adapted from:
5158// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
5159
5160function hue2rgb( p, q, h ) {
5161 h = ( h + 1 ) % 1;
5162 if ( h * 6 < 1 ) {
5163 return p + (q - p) * h * 6;
5164 }
5165 if ( h * 2 < 1) {
5166 return q;
5167 }
5168 if ( h * 3 < 2 ) {
5169 return p + (q - p) * ((2/3) - h) * 6;
5170 }
5171 return p;
5172}
5173
5174spaces.hsla.to = function ( rgba ) {
5175 if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
5176 return [ null, null, null, rgba[ 3 ] ];
5177 }
5178 var r = rgba[ 0 ] / 255,
5179 g = rgba[ 1 ] / 255,
5180 b = rgba[ 2 ] / 255,
5181 a = rgba[ 3 ],
5182 max = Math.max( r, g, b ),
5183 min = Math.min( r, g, b ),
5184 diff = max - min,
5185 add = max + min,
5186 l = add * 0.5,
5187 h, s;
5188
5189 if ( min === max ) {
5190 h = 0;
5191 } else if ( r === max ) {
5192 h = ( 60 * ( g - b ) / diff ) + 360;
5193 } else if ( g === max ) {
5194 h = ( 60 * ( b - r ) / diff ) + 120;
5195 } else {
5196 h = ( 60 * ( r - g ) / diff ) + 240;
5197 }
5198
5199 // chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
5200 // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
5201 if ( diff === 0 ) {
5202 s = 0;
5203 } else if ( l <= 0.5 ) {
5204 s = diff / add;
5205 } else {
5206 s = diff / ( 2 - add );
5207 }
5208 return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
5209};
5210
5211spaces.hsla.from = function ( hsla ) {
5212 if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
5213 return [ null, null, null, hsla[ 3 ] ];
5214 }
5215 var h = hsla[ 0 ] / 360,
5216 s = hsla[ 1 ],
5217 l = hsla[ 2 ],
5218 a = hsla[ 3 ],
5219 q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
5220 p = 2 * l - q;
5221
5222 return [
5223 Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
5224 Math.round( hue2rgb( p, q, h ) * 255 ),
5225 Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
5226 a
5227 ];
5228};
5229
5230
5231each( spaces, function( spaceName, space ) {
5232 var props = space.props,
5233 cache = space.cache,
5234 to = space.to,
5235 from = space.from;
5236
5237 // makes rgba() and hsla()
5238 color.fn[ spaceName ] = function( value ) {
5239
5240 // generate a cache for this space if it doesn't exist
5241 if ( to && !this[ cache ] ) {
5242 this[ cache ] = to( this._rgba );
5243 }
5244 if ( value === undefined ) {
5245 return this[ cache ].slice();
5246 }
5247
5248 var ret,
5249 type = jQuery.type( value ),
5250 arr = ( type === "array" || type === "object" ) ? value : arguments,
5251 local = this[ cache ].slice();
5252
5253 each( props, function( key, prop ) {
5254 var val = arr[ type === "object" ? key : prop.idx ];
5255 if ( val == null ) {
5256 val = local[ prop.idx ];
5257 }
5258 local[ prop.idx ] = clamp( val, prop );
5259 });
5260
5261 if ( from ) {
5262 ret = color( from( local ) );
5263 ret[ cache ] = local;
5264 return ret;
5265 } else {
5266 return color( local );
5267 }
5268 };
5269
5270 // makes red() green() blue() alpha() hue() saturation() lightness()
5271 each( props, function( key, prop ) {
5272 // alpha is included in more than one space
5273 if ( color.fn[ key ] ) {
5274 return;
5275 }
5276 color.fn[ key ] = function( value ) {
5277 var vtype = jQuery.type( value ),
5278 fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
5279 local = this[ fn ](),
5280 cur = local[ prop.idx ],
5281 match;
5282
5283 if ( vtype === "undefined" ) {
5284 return cur;
5285 }
5286
5287 if ( vtype === "function" ) {
5288 value = value.call( this, cur );
5289 vtype = jQuery.type( value );
5290 }
5291 if ( value == null && prop.empty ) {
5292 return this;
5293 }
5294 if ( vtype === "string" ) {
5295 match = rplusequals.exec( value );
5296 if ( match ) {
5297 value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
5298 }
5299 }
5300 local[ prop.idx ] = value;
5301 return this[ fn ]( local );
5302 };
5303 });
5304});
5305
5306// add cssHook and .fx.step function for each named hook.
5307// accept a space separated string of properties
5308color.hook = function( hook ) {
5309 var hooks = hook.split( " " );
5310 each( hooks, function( i, hook ) {
5311 jQuery.cssHooks[ hook ] = {
5312 set: function( elem, value ) {
5313 var parsed, curElem,
5314 backgroundColor = "";
5315
5316 if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
5317 value = color( parsed || value );
5318 if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
5319 curElem = hook === "backgroundColor" ? elem.parentNode : elem;
5320 while (
5321 (backgroundColor === "" || backgroundColor === "transparent") &&
5322 curElem && curElem.style
5323 ) {
5324 try {
5325 backgroundColor = jQuery.css( curElem, "backgroundColor" );
5326 curElem = curElem.parentNode;
5327 } catch ( e ) {
5328 }
5329 }
5330
5331 value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
5332 backgroundColor :
5333 "_default" );
5334 }
5335
5336 value = value.toRgbaString();
5337 }
5338 try {
5339 elem.style[ hook ] = value;
5340 } catch( e ) {
5341 // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
5342 }
5343 }
5344 };
5345 jQuery.fx.step[ hook ] = function( fx ) {
5346 if ( !fx.colorInit ) {
5347 fx.start = color( fx.elem, hook );
5348 fx.end = color( fx.end );
5349 fx.colorInit = true;
5350 }
5351 jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
5352 };
5353 });
5354
5355};
5356
5357color.hook( stepHooks );
5358
5359jQuery.cssHooks.borderColor = {
5360 expand: function( value ) {
5361 var expanded = {};
5362
5363 each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
5364 expanded[ "border" + part + "Color" ] = value;
5365 });
5366 return expanded;
5367 }
5368};
5369
5370// Basic color names only.
5371// Usage of any of the other color names requires adding yourself or including
5372// jquery.color.svg-names.js.
5373colors = jQuery.Color.names = {
5374 // 4.1. Basic color keywords
5375 aqua: "#00ffff",
5376 black: "#000000",
5377 blue: "#0000ff",
5378 fuchsia: "#ff00ff",
5379 gray: "#808080",
5380 green: "#008000",
5381 lime: "#00ff00",
5382 maroon: "#800000",
5383 navy: "#000080",
5384 olive: "#808000",
5385 purple: "#800080",
5386 red: "#ff0000",
5387 silver: "#c0c0c0",
5388 teal: "#008080",
5389 white: "#ffffff",
5390 yellow: "#ffff00",
5391
5392 // 4.2.3. "transparent" color keyword
5393 transparent: [ null, null, null, 0 ],
5394
5395 _default: "#ffffff"
5396};
5397
5398})( jQuery );
5399
5400
5401/******************************************************************************/
5402/****************************** CLASS ANIMATIONS ******************************/
5403/******************************************************************************/
5404(function() {
5405
5406var classAnimationActions = [ "add", "remove", "toggle" ],
5407 shorthandStyles = {
5408 border: 1,
5409 borderBottom: 1,
5410 borderColor: 1,
5411 borderLeft: 1,
5412 borderRight: 1,
5413 borderTop: 1,
5414 borderWidth: 1,
5415 margin: 1,
5416 padding: 1
5417 };
5418
5419$.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) {
5420 $.fx.step[ prop ] = function( fx ) {
5421 if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
5422 jQuery.style( fx.elem, prop, fx.end );
5423 fx.setAttr = true;
5424 }
5425 };
5426});
5427
5428function getElementStyles( elem ) {
5429 var key, len,
5430 style = elem.ownerDocument.defaultView ?
5431 elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
5432 elem.currentStyle,
5433 styles = {};
5434
5435 if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
5436 len = style.length;
5437 while ( len-- ) {
5438 key = style[ len ];
5439 if ( typeof style[ key ] === "string" ) {
5440 styles[ $.camelCase( key ) ] = style[ key ];
5441 }
5442 }
5443 // support: Opera, IE <9
5444 } else {
5445 for ( key in style ) {
5446 if ( typeof style[ key ] === "string" ) {
5447 styles[ key ] = style[ key ];
5448 }
5449 }
5450 }
5451
5452 return styles;
5453}
5454
5455
5456function styleDifference( oldStyle, newStyle ) {
5457 var diff = {},
5458 name, value;
5459
5460 for ( name in newStyle ) {
5461 value = newStyle[ name ];
5462 if ( oldStyle[ name ] !== value ) {
5463 if ( !shorthandStyles[ name ] ) {
5464 if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
5465 diff[ name ] = value;
5466 }
5467 }
5468 }
5469 }
5470
5471 return diff;
5472}
5473
5474// support: jQuery <1.8
5475if ( !$.fn.addBack ) {
5476 $.fn.addBack = function( selector ) {
5477 return this.add( selector == null ?
5478 this.prevObject : this.prevObject.filter( selector )
5479 );
5480 };
5481}
5482
5483$.effects.animateClass = function( value, duration, easing, callback ) {
5484 var o = $.speed( duration, easing, callback );
5485
5486 return this.queue( function() {
5487 var animated = $( this ),
5488 baseClass = animated.attr( "class" ) || "",
5489 applyClassChange,
5490 allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
5491
5492 // map the animated objects to store the original styles.
5493 allAnimations = allAnimations.map(function() {
5494 var el = $( this );
5495 return {
5496 el: el,
5497 start: getElementStyles( this )
5498 };
5499 });
5500
5501 // apply class change
5502 applyClassChange = function() {
5503 $.each( classAnimationActions, function(i, action) {
5504 if ( value[ action ] ) {
5505 animated[ action + "Class" ]( value[ action ] );
5506 }
5507 });
5508 };
5509 applyClassChange();
5510
5511 // map all animated objects again - calculate new styles and diff
5512 allAnimations = allAnimations.map(function() {
5513 this.end = getElementStyles( this.el[ 0 ] );
5514 this.diff = styleDifference( this.start, this.end );
5515 return this;
5516 });
5517
5518 // apply original class
5519 animated.attr( "class", baseClass );
5520
5521 // map all animated objects again - this time collecting a promise
5522 allAnimations = allAnimations.map(function() {
5523 var styleInfo = this,
5524 dfd = $.Deferred(),
5525 opts = $.extend({}, o, {
5526 queue: false,
5527 complete: function() {
5528 dfd.resolve( styleInfo );
5529 }
5530 });
5531
5532 this.el.animate( this.diff, opts );
5533 return dfd.promise();
5534 });
5535
5536 // once all animations have completed:
5537 $.when.apply( $, allAnimations.get() ).done(function() {
5538
5539 // set the final class
5540 applyClassChange();
5541
5542 // for each animated element,
5543 // clear all css properties that were animated
5544 $.each( arguments, function() {
5545 var el = this.el;
5546 $.each( this.diff, function(key) {
5547 el.css( key, "" );
5548 });
5549 });
5550
5551 // this is guarnteed to be there if you use jQuery.speed()
5552 // it also handles dequeuing the next anim...
5553 o.complete.call( animated[ 0 ] );
5554 });
5555 });
5556};
5557
5558$.fn.extend({
5559 _addClass: $.fn.addClass,
5560 addClass: function( classNames, speed, easing, callback ) {
5561 return speed ?
5562 $.effects.animateClass.call( this,
5563 { add: classNames }, speed, easing, callback ) :
5564 this._addClass( classNames );
5565 },
5566
5567 _removeClass: $.fn.removeClass,
5568 removeClass: function( classNames, speed, easing, callback ) {
5569 return arguments.length > 1 ?
5570 $.effects.animateClass.call( this,
5571 { remove: classNames }, speed, easing, callback ) :
5572 this._removeClass.apply( this, arguments );
5573 },
5574
5575 _toggleClass: $.fn.toggleClass,
5576 toggleClass: function( classNames, force, speed, easing, callback ) {
5577 if ( typeof force === "boolean" || force === undefined ) {
5578 if ( !speed ) {
5579 // without speed parameter
5580 return this._toggleClass( classNames, force );
5581 } else {
5582 return $.effects.animateClass.call( this,
5583 (force ? { add: classNames } : { remove: classNames }),
5584 speed, easing, callback );
5585 }
5586 } else {
5587 // without force parameter
5588 return $.effects.animateClass.call( this,
5589 { toggle: classNames }, force, speed, easing );
5590 }
5591 },
5592
5593 switchClass: function( remove, add, speed, easing, callback) {
5594 return $.effects.animateClass.call( this, {
5595 add: add,
5596 remove: remove
5597 }, speed, easing, callback );
5598 }
5599});
5600
5601})();
5602
5603/******************************************************************************/
5604/*********************************** EFFECTS **********************************/
5605/******************************************************************************/
5606
5607(function() {
5608
5609$.extend( $.effects, {
5610 version: "1.10.1",
5611
5612 // Saves a set of properties in a data storage
5613 save: function( element, set ) {
5614 for( var i=0; i < set.length; i++ ) {
5615 if ( set[ i ] !== null ) {
5616 element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
5617 }
5618 }
5619 },
5620
5621 // Restores a set of previously saved properties from a data storage
5622 restore: function( element, set ) {
5623 var val, i;
5624 for( i=0; i < set.length; i++ ) {
5625 if ( set[ i ] !== null ) {
5626 val = element.data( dataSpace + set[ i ] );
5627 // support: jQuery 1.6.2
5628 // http://bugs.jquery.com/ticket/9917
5629 // jQuery 1.6.2 incorrectly returns undefined for any falsy value.
5630 // We can't differentiate between "" and 0 here, so we just assume
5631 // empty string since it's likely to be a more common value...
5632 if ( val === undefined ) {
5633 val = "";
5634 }
5635 element.css( set[ i ], val );
5636 }
5637 }
5638 },
5639
5640 setMode: function( el, mode ) {
5641 if (mode === "toggle") {
5642 mode = el.is( ":hidden" ) ? "show" : "hide";
5643 }
5644 return mode;
5645 },
5646
5647 // Translates a [top,left] array into a baseline value
5648 // this should be a little more flexible in the future to handle a string & hash
5649 getBaseline: function( origin, original ) {
5650 var y, x;
5651 switch ( origin[ 0 ] ) {
5652 case "top": y = 0; break;
5653 case "middle": y = 0.5; break;
5654 case "bottom": y = 1; break;
5655 default: y = origin[ 0 ] / original.height;
5656 }
5657 switch ( origin[ 1 ] ) {
5658 case "left": x = 0; break;
5659 case "center": x = 0.5; break;
5660 case "right": x = 1; break;
5661 default: x = origin[ 1 ] / original.width;
5662 }
5663 return {
5664 x: x,
5665 y: y
5666 };
5667 },
5668
5669 // Wraps the element around a wrapper that copies position properties
5670 createWrapper: function( element ) {
5671
5672 // if the element is already wrapped, return it
5673 if ( element.parent().is( ".ui-effects-wrapper" )) {
5674 return element.parent();
5675 }
5676
5677 // wrap the element
5678 var props = {
5679 width: element.outerWidth(true),
5680 height: element.outerHeight(true),
5681 "float": element.css( "float" )
5682 },
5683 wrapper = $( "<div></div>" )
5684 .addClass( "ui-effects-wrapper" )
5685 .css({
5686 fontSize: "100%",
5687 background: "transparent",
5688 border: "none",
5689 margin: 0,
5690 padding: 0
5691 }),
5692 // Store the size in case width/height are defined in % - Fixes #5245
5693 size = {
5694 width: element.width(),
5695 height: element.height()
5696 },
5697 active = document.activeElement;
5698
5699 // support: Firefox
5700 // Firefox incorrectly exposes anonymous content
5701 // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
5702 try {
5703 active.id;
5704 } catch( e ) {
5705 active = document.body;
5706 }
5707
5708 element.wrap( wrapper );
5709
5710 // Fixes #7595 - Elements lose focus when wrapped.
5711 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
5712 $( active ).focus();
5713 }
5714
5715 wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element
5716
5717 // transfer positioning properties to the wrapper
5718 if ( element.css( "position" ) === "static" ) {
5719 wrapper.css({ position: "relative" });
5720 element.css({ position: "relative" });
5721 } else {
5722 $.extend( props, {
5723 position: element.css( "position" ),
5724 zIndex: element.css( "z-index" )
5725 });
5726 $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
5727 props[ pos ] = element.css( pos );
5728 if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
5729 props[ pos ] = "auto";
5730 }
5731 });
5732 element.css({
5733 position: "relative",
5734 top: 0,
5735 left: 0,
5736 right: "auto",
5737 bottom: "auto"
5738 });
5739 }
5740 element.css(size);
5741
5742 return wrapper.css( props ).show();
5743 },
5744
5745 removeWrapper: function( element ) {
5746 var active = document.activeElement;
5747
5748 if ( element.parent().is( ".ui-effects-wrapper" ) ) {
5749 element.parent().replaceWith( element );
5750
5751 // Fixes #7595 - Elements lose focus when wrapped.
5752 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
5753 $( active ).focus();
5754 }
5755 }
5756
5757
5758 return element;
5759 },
5760
5761 setTransition: function( element, list, factor, value ) {
5762 value = value || {};
5763 $.each( list, function( i, x ) {
5764 var unit = element.cssUnit( x );
5765 if ( unit[ 0 ] > 0 ) {
5766 value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
5767 }
5768 });
5769 return value;
5770 }
5771});
5772
5773// return an effect options object for the given parameters:
5774function _normalizeArguments( effect, options, speed, callback ) {
5775
5776 // allow passing all options as the first parameter
5777 if ( $.isPlainObject( effect ) ) {
5778 options = effect;
5779 effect = effect.effect;
5780 }
5781
5782 // convert to an object
5783 effect = { effect: effect };
5784
5785 // catch (effect, null, ...)
5786 if ( options == null ) {
5787 options = {};
5788 }
5789
5790 // catch (effect, callback)
5791 if ( $.isFunction( options ) ) {
5792 callback = options;
5793 speed = null;
5794 options = {};
5795 }
5796
5797 // catch (effect, speed, ?)
5798 if ( typeof options === "number" || $.fx.speeds[ options ] ) {
5799 callback = speed;
5800 speed = options;
5801 options = {};
5802 }
5803
5804 // catch (effect, options, callback)
5805 if ( $.isFunction( speed ) ) {
5806 callback = speed;
5807 speed = null;
5808 }
5809
5810 // add options to effect
5811 if ( options ) {
5812 $.extend( effect, options );
5813 }
5814
5815 speed = speed || options.duration;
5816 effect.duration = $.fx.off ? 0 :
5817 typeof speed === "number" ? speed :
5818 speed in $.fx.speeds ? $.fx.speeds[ speed ] :
5819 $.fx.speeds._default;
5820
5821 effect.complete = callback || options.complete;
5822
5823 return effect;
5824}
5825
5826function standardSpeed( speed ) {
5827 // valid standard speeds
5828 if ( !speed || typeof speed === "number" || $.fx.speeds[ speed ] ) {
5829 return true;
5830 }
5831
5832 // invalid strings - treat as "normal" speed
5833 return typeof speed === "string" && !$.effects.effect[ speed ];
5834}
5835
5836$.fn.extend({
5837 effect: function( /* effect, options, speed, callback */ ) {
5838 var args = _normalizeArguments.apply( this, arguments ),
5839 mode = args.mode,
5840 queue = args.queue,
5841 effectMethod = $.effects.effect[ args.effect ];
5842
5843 if ( $.fx.off || !effectMethod ) {
5844 // delegate to the original method (e.g., .show()) if possible
5845 if ( mode ) {
5846 return this[ mode ]( args.duration, args.complete );
5847 } else {
5848 return this.each( function() {
5849 if ( args.complete ) {
5850 args.complete.call( this );
5851 }
5852 });
5853 }
5854 }
5855
5856 function run( next ) {
5857 var elem = $( this ),
5858 complete = args.complete,
5859 mode = args.mode;
5860
5861 function done() {
5862 if ( $.isFunction( complete ) ) {
5863 complete.call( elem[0] );
5864 }
5865 if ( $.isFunction( next ) ) {
5866 next();
5867 }
5868 }
5869
5870 // if the element is hiddden and mode is hide,
5871 // or element is visible and mode is show
5872 if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
5873 done();
5874 } else {
5875 effectMethod.call( elem[0], args, done );
5876 }
5877 }
5878
5879 return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
5880 },
5881
5882 _show: $.fn.show,
5883 show: function( speed ) {
5884 if ( standardSpeed( speed ) ) {
5885 return this._show.apply( this, arguments );
5886 } else {
5887 var args = _normalizeArguments.apply( this, arguments );
5888 args.mode = "show";
5889 return this.effect.call( this, args );
5890 }
5891 },
5892
5893 _hide: $.fn.hide,
5894 hide: function( speed ) {
5895 if ( standardSpeed( speed ) ) {
5896 return this._hide.apply( this, arguments );
5897 } else {
5898 var args = _normalizeArguments.apply( this, arguments );
5899 args.mode = "hide";
5900 return this.effect.call( this, args );
5901 }
5902 },
5903
5904 // jQuery core overloads toggle and creates _toggle
5905 __toggle: $.fn.toggle,
5906 toggle: function( speed ) {
5907 if ( standardSpeed( speed ) || typeof speed === "boolean" || $.isFunction( speed ) ) {
5908 return this.__toggle.apply( this, arguments );
5909 } else {
5910 var args = _normalizeArguments.apply( this, arguments );
5911 args.mode = "toggle";
5912 return this.effect.call( this, args );
5913 }
5914 },
5915
5916 // helper functions
5917 cssUnit: function(key) {
5918 var style = this.css( key ),
5919 val = [];
5920
5921 $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
5922 if ( style.indexOf( unit ) > 0 ) {
5923 val = [ parseFloat( style ), unit ];
5924 }
5925 });
5926 return val;
5927 }
5928});
5929
5930})();
5931
5932/******************************************************************************/
5933/*********************************** EASING ***********************************/
5934/******************************************************************************/
5935
5936(function() {
5937
5938// based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
5939
5940var baseEasings = {};
5941
5942$.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
5943 baseEasings[ name ] = function( p ) {
5944 return Math.pow( p, i + 2 );
5945 };
5946});
5947
5948$.extend( baseEasings, {
5949 Sine: function ( p ) {
5950 return 1 - Math.cos( p * Math.PI / 2 );
5951 },
5952 Circ: function ( p ) {
5953 return 1 - Math.sqrt( 1 - p * p );
5954 },
5955 Elastic: function( p ) {
5956 return p === 0 || p === 1 ? p :
5957 -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 );
5958 },
5959 Back: function( p ) {
5960 return p * p * ( 3 * p - 2 );
5961 },
5962 Bounce: function ( p ) {
5963 var pow2,
5964 bounce = 4;
5965
5966 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
5967 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
5968 }
5969});
5970
5971$.each( baseEasings, function( name, easeIn ) {
5972 $.easing[ "easeIn" + name ] = easeIn;
5973 $.easing[ "easeOut" + name ] = function( p ) {
5974 return 1 - easeIn( 1 - p );
5975 };
5976 $.easing[ "easeInOut" + name ] = function( p ) {
5977 return p < 0.5 ?
5978 easeIn( p * 2 ) / 2 :
5979 1 - easeIn( p * -2 + 2 ) / 2;
5980 };
5981});
5982
5983})();
5984
5985})(jQuery));
5986
5987(function( $, undefined ) {
5988
5989var uid = 0,
5990 hideProps = {},
5991 showProps = {};
5992
5993hideProps.height = hideProps.paddingTop = hideProps.paddingBottom =
5994 hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide";
5995showProps.height = showProps.paddingTop = showProps.paddingBottom =
5996 showProps.borderTopWidth = showProps.borderBottomWidth = "show";
5997
5998$.widget( "ui.accordion", {
5999 version: "1.10.1",
6000 options: {
6001 active: 0,
6002 animate: {},
6003 collapsible: false,
6004 event: "click",
6005 header: "> li > :first-child,> :not(li):even",
6006 heightStyle: "auto",
6007 icons: {
6008 activeHeader: "ui-icon-triangle-1-s",
6009 header: "ui-icon-triangle-1-e"
6010 },
6011
6012 // callbacks
6013 activate: null,
6014 beforeActivate: null
6015 },
6016
6017 _create: function() {
6018 var options = this.options;
6019 this.prevShow = this.prevHide = $();
6020 this.element.addClass( "ui-accordion ui-widget ui-helper-reset" )
6021 // ARIA
6022 .attr( "role", "tablist" );
6023
6024 // don't allow collapsible: false and active: false / null
6025 if ( !options.collapsible && (options.active === false || options.active == null) ) {
6026 options.active = 0;
6027 }
6028
6029 this._processPanels();
6030 // handle negative values
6031 if ( options.active < 0 ) {
6032 options.active += this.headers.length;
6033 }
6034 this._refresh();
6035 },
6036
6037 _getCreateEventData: function() {
6038 return {
6039 header: this.active,
6040 panel: !this.active.length ? $() : this.active.next(),
6041 content: !this.active.length ? $() : this.active.next()
6042 };
6043 },
6044
6045 _createIcons: function() {
6046 var icons = this.options.icons;
6047 if ( icons ) {
6048 $( "<span>" )
6049 .addClass( "ui-accordion-header-icon ui-icon " + icons.header )
6050 .prependTo( this.headers );
6051 this.active.children( ".ui-accordion-header-icon" )
6052 .removeClass( icons.header )
6053 .addClass( icons.activeHeader );
6054 this.headers.addClass( "ui-accordion-icons" );
6055 }
6056 },
6057
6058 _destroyIcons: function() {
6059 this.headers
6060 .removeClass( "ui-accordion-icons" )
6061 .children( ".ui-accordion-header-icon" )
6062 .remove();
6063 },
6064
6065 _destroy: function() {
6066 var contents;
6067
6068 // clean up main element
6069 this.element
6070 .removeClass( "ui-accordion ui-widget ui-helper-reset" )
6071 .removeAttr( "role" );
6072
6073 // clean up headers
6074 this.headers
6075 .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" )
6076 .removeAttr( "role" )
6077 .removeAttr( "aria-selected" )
6078 .removeAttr( "aria-controls" )
6079 .removeAttr( "tabIndex" )
6080 .each(function() {
6081 if ( /^ui-accordion/.test( this.id ) ) {
6082 this.removeAttribute( "id" );
6083 }
6084 });
6085 this._destroyIcons();
6086
6087 // clean up content panels
6088 contents = this.headers.next()
6089 .css( "display", "" )
6090 .removeAttr( "role" )
6091 .removeAttr( "aria-expanded" )
6092 .removeAttr( "aria-hidden" )
6093 .removeAttr( "aria-labelledby" )
6094 .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" )
6095 .each(function() {
6096 if ( /^ui-accordion/.test( this.id ) ) {
6097 this.removeAttribute( "id" );
6098 }
6099 });
6100 if ( this.options.heightStyle !== "content" ) {
6101 contents.css( "height", "" );
6102 }
6103 },
6104
6105 _setOption: function( key, value ) {
6106 if ( key === "active" ) {
6107 // _activate() will handle invalid values and update this.options
6108 this._activate( value );
6109 return;
6110 }
6111
6112 if ( key === "event" ) {
6113 if ( this.options.event ) {
6114 this._off( this.headers, this.options.event );
6115 }
6116 this._setupEvents( value );
6117 }
6118
6119 this._super( key, value );
6120
6121 // setting collapsible: false while collapsed; open first panel
6122 if ( key === "collapsible" && !value && this.options.active === false ) {
6123 this._activate( 0 );
6124 }
6125
6126 if ( key === "icons" ) {
6127 this._destroyIcons();
6128 if ( value ) {
6129 this._createIcons();
6130 }
6131 }
6132
6133 // #5332 - opacity doesn't cascade to positioned elements in IE
6134 // so we need to add the disabled class to the headers and panels
6135 if ( key === "disabled" ) {
6136 this.headers.add( this.headers.next() )
6137 .toggleClass( "ui-state-disabled", !!value );
6138 }
6139 },
6140
6141 _keydown: function( event ) {
6142 /*jshint maxcomplexity:15*/
6143 if ( event.altKey || event.ctrlKey ) {
6144 return;
6145 }
6146
6147 var keyCode = $.ui.keyCode,
6148 length = this.headers.length,
6149 currentIndex = this.headers.index( event.target ),
6150 toFocus = false;
6151
6152 switch ( event.keyCode ) {
6153 case keyCode.RIGHT:
6154 case keyCode.DOWN:
6155 toFocus = this.headers[ ( currentIndex + 1 ) % length ];
6156 break;
6157 case keyCode.LEFT:
6158 case keyCode.UP:
6159 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
6160 break;
6161 case keyCode.SPACE:
6162 case keyCode.ENTER:
6163 this._eventHandler( event );
6164 break;
6165 case keyCode.HOME:
6166 toFocus = this.headers[ 0 ];
6167 break;
6168 case keyCode.END:
6169 toFocus = this.headers[ length - 1 ];
6170 break;
6171 }
6172
6173 if ( toFocus ) {
6174 $( event.target ).attr( "tabIndex", -1 );
6175 $( toFocus ).attr( "tabIndex", 0 );
6176 toFocus.focus();
6177 event.preventDefault();
6178 }
6179 },
6180
6181 _panelKeyDown : function( event ) {
6182 if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
6183 $( event.currentTarget ).prev().focus();
6184 }
6185 },
6186
6187 refresh: function() {
6188 var options = this.options;
6189 this._processPanels();
6190
6191 // was collapsed or no panel
6192 if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) {
6193 options.active = false;
6194 this.active = $();
6195 // active false only when collapsible is true
6196 } if ( options.active === false ) {
6197 this._activate( 0 );
6198 // was active, but active panel is gone
6199 } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
6200 // all remaining panel are disabled
6201 if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) {
6202 options.active = false;
6203 this.active = $();
6204 // activate previous panel
6205 } else {
6206 this._activate( Math.max( 0, options.active - 1 ) );
6207 }
6208 // was active, active panel still exists
6209 } else {
6210 // make sure active index is correct
6211 options.active = this.headers.index( this.active );
6212 }
6213
6214 this._destroyIcons();
6215
6216 this._refresh();
6217 },
6218
6219 _processPanels: function() {
6220 this.headers = this.element.find( this.options.header )
6221 .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" );
6222
6223 this.headers.next()
6224 .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
6225 .filter(":not(.ui-accordion-content-active)")
6226 .hide();
6227 },
6228
6229 _refresh: function() {
6230 var maxHeight,
6231 options = this.options,
6232 heightStyle = options.heightStyle,
6233 parent = this.element.parent(),
6234 accordionId = this.accordionId = "ui-accordion-" +
6235 (this.element.attr( "id" ) || ++uid);
6236
6237 this.active = this._findActive( options.active )
6238 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" )
6239 .removeClass( "ui-corner-all" );
6240 this.active.next()
6241 .addClass( "ui-accordion-content-active" )
6242 .show();
6243
6244 this.headers
6245 .attr( "role", "tab" )
6246 .each(function( i ) {
6247 var header = $( this ),
6248 headerId = header.attr( "id" ),
6249 panel = header.next(),
6250 panelId = panel.attr( "id" );
6251 if ( !headerId ) {
6252 headerId = accordionId + "-header-" + i;
6253 header.attr( "id", headerId );
6254 }
6255 if ( !panelId ) {
6256 panelId = accordionId + "-panel-" + i;
6257 panel.attr( "id", panelId );
6258 }
6259 header.attr( "aria-controls", panelId );
6260 panel.attr( "aria-labelledby", headerId );
6261 })
6262 .next()
6263 .attr( "role", "tabpanel" );
6264
6265 this.headers
6266 .not( this.active )
6267 .attr({
6268 "aria-selected": "false",
6269 tabIndex: -1
6270 })
6271 .next()
6272 .attr({
6273 "aria-expanded": "false",
6274 "aria-hidden": "true"
6275 })
6276 .hide();
6277
6278 // make sure at least one header is in the tab order
6279 if ( !this.active.length ) {
6280 this.headers.eq( 0 ).attr( "tabIndex", 0 );
6281 } else {
6282 this.active.attr({
6283 "aria-selected": "true",
6284 tabIndex: 0
6285 })
6286 .next()
6287 .attr({
6288 "aria-expanded": "true",
6289 "aria-hidden": "false"
6290 });
6291 }
6292
6293 this._createIcons();
6294
6295 this._setupEvents( options.event );
6296
6297 if ( heightStyle === "fill" ) {
6298 maxHeight = parent.height();
6299 this.element.siblings( ":visible" ).each(function() {
6300 var elem = $( this ),
6301 position = elem.css( "position" );
6302
6303 if ( position === "absolute" || position === "fixed" ) {
6304 return;
6305 }
6306 maxHeight -= elem.outerHeight( true );
6307 });
6308
6309 this.headers.each(function() {
6310 maxHeight -= $( this ).outerHeight( true );
6311 });
6312
6313 this.headers.next()
6314 .each(function() {
6315 $( this ).height( Math.max( 0, maxHeight -
6316 $( this ).innerHeight() + $( this ).height() ) );
6317 })
6318 .css( "overflow", "auto" );
6319 } else if ( heightStyle === "auto" ) {
6320 maxHeight = 0;
6321 this.headers.next()
6322 .each(function() {
6323 maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
6324 })
6325 .height( maxHeight );
6326 }
6327 },
6328
6329 _activate: function( index ) {
6330 var active = this._findActive( index )[ 0 ];
6331
6332 // trying to activate the already active panel
6333 if ( active === this.active[ 0 ] ) {
6334 return;
6335 }
6336
6337 // trying to collapse, simulate a click on the currently active header
6338 active = active || this.active[ 0 ];
6339
6340 this._eventHandler({
6341 target: active,
6342 currentTarget: active,
6343 preventDefault: $.noop
6344 });
6345 },
6346
6347 _findActive: function( selector ) {
6348 return typeof selector === "number" ? this.headers.eq( selector ) : $();
6349 },
6350
6351 _setupEvents: function( event ) {
6352 var events = {
6353 keydown: "_keydown"
6354 };
6355 if ( event ) {
6356 $.each( event.split(" "), function( index, eventName ) {
6357 events[ eventName ] = "_eventHandler";
6358 });
6359 }
6360
6361 this._off( this.headers.add( this.headers.next() ) );
6362 this._on( this.headers, events );
6363 this._on( this.headers.next(), { keydown: "_panelKeyDown" });
6364 this._hoverable( this.headers );
6365 this._focusable( this.headers );
6366 },
6367
6368 _eventHandler: function( event ) {
6369 var options = this.options,
6370 active = this.active,
6371 clicked = $( event.currentTarget ),
6372 clickedIsActive = clicked[ 0 ] === active[ 0 ],
6373 collapsing = clickedIsActive && options.collapsible,
6374 toShow = collapsing ? $() : clicked.next(),
6375 toHide = active.next(),
6376 eventData = {
6377 oldHeader: active,
6378 oldPanel: toHide,
6379 newHeader: collapsing ? $() : clicked,
6380 newPanel: toShow
6381 };
6382
6383 event.preventDefault();
6384
6385 if (
6386 // click on active header, but not collapsible
6387 ( clickedIsActive && !options.collapsible ) ||
6388 // allow canceling activation
6389 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
6390 return;
6391 }
6392
6393 options.active = collapsing ? false : this.headers.index( clicked );
6394
6395 // when the call to ._toggle() comes after the class changes
6396 // it causes a very odd bug in IE 8 (see #6720)
6397 this.active = clickedIsActive ? $() : clicked;
6398 this._toggle( eventData );
6399
6400 // switch classes
6401 // corner classes on the previously active header stay after the animation
6402 active.removeClass( "ui-accordion-header-active ui-state-active" );
6403 if ( options.icons ) {
6404 active.children( ".ui-accordion-header-icon" )
6405 .removeClass( options.icons.activeHeader )
6406 .addClass( options.icons.header );
6407 }
6408
6409 if ( !clickedIsActive ) {
6410 clicked
6411 .removeClass( "ui-corner-all" )
6412 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" );
6413 if ( options.icons ) {
6414 clicked.children( ".ui-accordion-header-icon" )
6415 .removeClass( options.icons.header )
6416 .addClass( options.icons.activeHeader );
6417 }
6418
6419 clicked
6420 .next()
6421 .addClass( "ui-accordion-content-active" );
6422 }
6423 },
6424
6425 _toggle: function( data ) {
6426 var toShow = data.newPanel,
6427 toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
6428
6429 // handle activating a panel during the animation for another activation
6430 this.prevShow.add( this.prevHide ).stop( true, true );
6431 this.prevShow = toShow;
6432 this.prevHide = toHide;
6433
6434 if ( this.options.animate ) {
6435 this._animate( toShow, toHide, data );
6436 } else {
6437 toHide.hide();
6438 toShow.show();
6439 this._toggleComplete( data );
6440 }
6441
6442 toHide.attr({
6443 "aria-expanded": "false",
6444 "aria-hidden": "true"
6445 });
6446 toHide.prev().attr( "aria-selected", "false" );
6447 // if we're switching panels, remove the old header from the tab order
6448 // if we're opening from collapsed state, remove the previous header from the tab order
6449 // if we're collapsing, then keep the collapsing header in the tab order
6450 if ( toShow.length && toHide.length ) {
6451 toHide.prev().attr( "tabIndex", -1 );
6452 } else if ( toShow.length ) {
6453 this.headers.filter(function() {
6454 return $( this ).attr( "tabIndex" ) === 0;
6455 })
6456 .attr( "tabIndex", -1 );
6457 }
6458
6459 toShow
6460 .attr({
6461 "aria-expanded": "true",
6462 "aria-hidden": "false"
6463 })
6464 .prev()
6465 .attr({
6466 "aria-selected": "true",
6467 tabIndex: 0
6468 });
6469 },
6470
6471 _animate: function( toShow, toHide, data ) {
6472 var total, easing, duration,
6473 that = this,
6474 adjust = 0,
6475 down = toShow.length &&
6476 ( !toHide.length || ( toShow.index() < toHide.index() ) ),
6477 animate = this.options.animate || {},
6478 options = down && animate.down || animate,
6479 complete = function() {
6480 that._toggleComplete( data );
6481 };
6482
6483 if ( typeof options === "number" ) {
6484 duration = options;
6485 }
6486 if ( typeof options === "string" ) {
6487 easing = options;
6488 }
6489 // fall back from options to animation in case of partial down settings
6490 easing = easing || options.easing || animate.easing;
6491 duration = duration || options.duration || animate.duration;
6492
6493 if ( !toHide.length ) {
6494 return toShow.animate( showProps, duration, easing, complete );
6495 }
6496 if ( !toShow.length ) {
6497 return toHide.animate( hideProps, duration, easing, complete );
6498 }
6499
6500 total = toShow.show().outerHeight();
6501 toHide.animate( hideProps, {
6502 duration: duration,
6503 easing: easing,
6504 step: function( now, fx ) {
6505 fx.now = Math.round( now );
6506 }
6507 });
6508 toShow
6509 .hide()
6510 .animate( showProps, {
6511 duration: duration,
6512 easing: easing,
6513 complete: complete,
6514 step: function( now, fx ) {
6515 fx.now = Math.round( now );
6516 if ( fx.prop !== "height" ) {
6517 adjust += fx.now;
6518 } else if ( that.options.heightStyle !== "content" ) {
6519 fx.now = Math.round( total - toHide.outerHeight() - adjust );
6520 adjust = 0;
6521 }
6522 }
6523 });
6524 },
6525
6526 _toggleComplete: function( data ) {
6527 var toHide = data.oldPanel;
6528
6529 toHide
6530 .removeClass( "ui-accordion-content-active" )
6531 .prev()
6532 .removeClass( "ui-corner-top" )
6533 .addClass( "ui-corner-all" );
6534
6535 // Work around for rendering bug in IE (#5421)
6536 if ( toHide.length ) {
6537 toHide.parent()[0].className = toHide.parent()[0].className;
6538 }
6539
6540 this._trigger( "activate", null, data );
6541 }
6542});
6543
6544})( jQuery );
6545
6546(function( $, undefined ) {
6547
6548// used to prevent race conditions with remote data sources
6549var requestIndex = 0;
6550
6551$.widget( "ui.autocomplete", {
6552 version: "1.10.1",
6553 defaultElement: "<input>",
6554 options: {
6555 appendTo: null,
6556 autoFocus: false,
6557 delay: 300,
6558 minLength: 1,
6559 position: {
6560 my: "left top",
6561 at: "left bottom",
6562 collision: "none"
6563 },
6564 source: null,
6565
6566 // callbacks
6567 change: null,
6568 close: null,
6569 focus: null,
6570 open: null,
6571 response: null,
6572 search: null,
6573 select: null
6574 },
6575
6576 pending: 0,
6577
6578 _create: function() {
6579 // Some browsers only repeat keydown events, not keypress events,
6580 // so we use the suppressKeyPress flag to determine if we've already
6581 // handled the keydown event. #7269
6582 // Unfortunately the code for & in keypress is the same as the up arrow,
6583 // so we use the suppressKeyPressRepeat flag to avoid handling keypress
6584 // events when we know the keydown event was used to modify the
6585 // search term. #7799
6586 var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
6587 nodeName = this.element[0].nodeName.toLowerCase(),
6588 isTextarea = nodeName === "textarea",
6589 isInput = nodeName === "input";
6590
6591 this.isMultiLine =
6592 // Textareas are always multi-line
6593 isTextarea ? true :
6594 // Inputs are always single-line, even if inside a contentEditable element
6595 // IE also treats inputs as contentEditable
6596 isInput ? false :
6597 // All other element types are determined by whether or not they're contentEditable
6598 this.element.prop( "isContentEditable" );
6599
6600 this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
6601 this.isNewMenu = true;
6602
6603 this.element
6604 .addClass( "ui-autocomplete-input" )
6605 .attr( "autocomplete", "off" );
6606
6607 this._on( this.element, {
6608 keydown: function( event ) {
6609 /*jshint maxcomplexity:15*/
6610 if ( this.element.prop( "readOnly" ) ) {
6611 suppressKeyPress = true;
6612 suppressInput = true;
6613 suppressKeyPressRepeat = true;
6614 return;
6615 }
6616
6617 suppressKeyPress = false;
6618 suppressInput = false;
6619 suppressKeyPressRepeat = false;
6620 var keyCode = $.ui.keyCode;
6621 switch( event.keyCode ) {
6622 case keyCode.PAGE_UP:
6623 suppressKeyPress = true;
6624 this._move( "previousPage", event );
6625 break;
6626 case keyCode.PAGE_DOWN:
6627 suppressKeyPress = true;
6628 this._move( "nextPage", event );
6629 break;
6630 case keyCode.UP:
6631 suppressKeyPress = true;
6632 this._keyEvent( "previous", event );
6633 break;
6634 case keyCode.DOWN:
6635 suppressKeyPress = true;
6636 this._keyEvent( "next", event );
6637 break;
6638 case keyCode.ENTER:
6639 case keyCode.NUMPAD_ENTER:
6640 // when menu is open and has focus
6641 if ( this.menu.active ) {
6642 // #6055 - Opera still allows the keypress to occur
6643 // which causes forms to submit
6644 suppressKeyPress = true;
6645 event.preventDefault();
6646 this.menu.select( event );
6647 }
6648 break;
6649 case keyCode.TAB:
6650 if ( this.menu.active ) {
6651 this.menu.select( event );
6652 }
6653 break;
6654 case keyCode.ESCAPE:
6655 if ( this.menu.element.is( ":visible" ) ) {
6656 this._value( this.term );
6657 this.close( event );
6658 // Different browsers have different default behavior for escape
6659 // Single press can mean undo or clear
6660 // Double press in IE means clear the whole form
6661 event.preventDefault();
6662 }
6663 break;
6664 default:
6665 suppressKeyPressRepeat = true;
6666 // search timeout should be triggered before the input value is changed
6667 this._searchTimeout( event );
6668 break;
6669 }
6670 },
6671 keypress: function( event ) {
6672 if ( suppressKeyPress ) {
6673 suppressKeyPress = false;
6674 event.preventDefault();
6675 return;
6676 }
6677 if ( suppressKeyPressRepeat ) {
6678 return;
6679 }
6680
6681 // replicate some key handlers to allow them to repeat in Firefox and Opera
6682 var keyCode = $.ui.keyCode;
6683 switch( event.keyCode ) {
6684 case keyCode.PAGE_UP:
6685 this._move( "previousPage", event );
6686 break;
6687 case keyCode.PAGE_DOWN:
6688 this._move( "nextPage", event );
6689 break;
6690 case keyCode.UP:
6691 this._keyEvent( "previous", event );
6692 break;
6693 case keyCode.DOWN:
6694 this._keyEvent( "next", event );
6695 break;
6696 }
6697 },
6698 input: function( event ) {
6699 if ( suppressInput ) {
6700 suppressInput = false;
6701 event.preventDefault();
6702 return;
6703 }
6704 this._searchTimeout( event );
6705 },
6706 focus: function() {
6707 this.selectedItem = null;
6708 this.previous = this._value();
6709 },
6710 blur: function( event ) {
6711 if ( this.cancelBlur ) {
6712 delete this.cancelBlur;
6713 return;
6714 }
6715
6716 clearTimeout( this.searching );
6717 this.close( event );
6718 this._change( event );
6719 }
6720 });
6721
6722 this._initSource();
6723 this.menu = $( "<ul>" )
6724 .addClass( "ui-autocomplete ui-front" )
6725 .appendTo( this._appendTo() )
6726 .menu({
6727 // custom key handling for now
6728 input: $(),
6729 // disable ARIA support, the live region takes care of that
6730 role: null
6731 })
6732 .hide()
6733 .data( "ui-menu" );
6734
6735 this._on( this.menu.element, {
6736 mousedown: function( event ) {
6737 // prevent moving focus out of the text field
6738 event.preventDefault();
6739
6740 // IE doesn't prevent moving focus even with event.preventDefault()
6741 // so we set a flag to know when we should ignore the blur event
6742 this.cancelBlur = true;
6743 this._delay(function() {
6744 delete this.cancelBlur;
6745 });
6746
6747 // clicking on the scrollbar causes focus to shift to the body
6748 // but we can't detect a mouseup or a click immediately afterward
6749 // so we have to track the next mousedown and close the menu if
6750 // the user clicks somewhere outside of the autocomplete
6751 var menuElement = this.menu.element[ 0 ];
6752 if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
6753 this._delay(function() {
6754 var that = this;
6755 this.document.one( "mousedown", function( event ) {
6756 if ( event.target !== that.element[ 0 ] &&
6757 event.target !== menuElement &&
6758 !$.contains( menuElement, event.target ) ) {
6759 that.close();
6760 }
6761 });
6762 });
6763 }
6764 },
6765 menufocus: function( event, ui ) {
6766 // #7024 - Prevent accidental activation of menu items in Firefox
6767 if ( this.isNewMenu ) {
6768 this.isNewMenu = false;
6769 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
6770 this.menu.blur();
6771
6772 this.document.one( "mousemove", function() {
6773 $( event.target ).trigger( event.originalEvent );
6774 });
6775
6776 return;
6777 }
6778 }
6779
6780 var item = ui.item.data( "ui-autocomplete-item" );
6781 if ( false !== this._trigger( "focus", event, { item: item } ) ) {
6782 // use value to match what will end up in the input, if it was a key event
6783 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
6784 this._value( item.value );
6785 }
6786 } else {
6787 // Normally the input is populated with the item's value as the
6788 // menu is navigated, causing screen readers to notice a change and
6789 // announce the item. Since the focus event was canceled, this doesn't
6790 // happen, so we update the live region so that screen readers can
6791 // still notice the change and announce it.
6792 this.liveRegion.text( item.value );
6793 }
6794 },
6795 menuselect: function( event, ui ) {
6796 var item = ui.item.data( "ui-autocomplete-item" ),
6797 previous = this.previous;
6798
6799 // only trigger when focus was lost (click on menu)
6800 if ( this.element[0] !== this.document[0].activeElement ) {
6801 this.element.focus();
6802 this.previous = previous;
6803 // #6109 - IE triggers two focus events and the second
6804 // is asynchronous, so we need to reset the previous
6805 // term synchronously and asynchronously :-(
6806 this._delay(function() {
6807 this.previous = previous;
6808 this.selectedItem = item;
6809 });
6810 }
6811
6812 if ( false !== this._trigger( "select", event, { item: item } ) ) {
6813 this._value( item.value );
6814 }
6815 // reset the term after the select event
6816 // this allows custom select handling to work properly
6817 this.term = this._value();
6818
6819 this.close( event );
6820 this.selectedItem = item;
6821 }
6822 });
6823
6824 this.liveRegion = $( "<span>", {
6825 role: "status",
6826 "aria-live": "polite"
6827 })
6828 .addClass( "ui-helper-hidden-accessible" )
6829 .insertAfter( this.element );
6830
6831 // turning off autocomplete prevents the browser from remembering the
6832 // value when navigating through history, so we re-enable autocomplete
6833 // if the page is unloaded before the widget is destroyed. #7790
6834 this._on( this.window, {
6835 beforeunload: function() {
6836 this.element.removeAttr( "autocomplete" );
6837 }
6838 });
6839 },
6840
6841 _destroy: function() {
6842 clearTimeout( this.searching );
6843 this.element
6844 .removeClass( "ui-autocomplete-input" )
6845 .removeAttr( "autocomplete" );
6846 this.menu.element.remove();
6847 this.liveRegion.remove();
6848 },
6849
6850 _setOption: function( key, value ) {
6851 this._super( key, value );
6852 if ( key === "source" ) {
6853 this._initSource();
6854 }
6855 if ( key === "appendTo" ) {
6856 this.menu.element.appendTo( this._appendTo() );
6857 }
6858 if ( key === "disabled" && value && this.xhr ) {
6859 this.xhr.abort();
6860 }
6861 },
6862
6863 _appendTo: function() {
6864 var element = this.options.appendTo;
6865
6866 if ( element ) {
6867 element = element.jquery || element.nodeType ?
6868 $( element ) :
6869 this.document.find( element ).eq( 0 );
6870 }
6871
6872 if ( !element ) {
6873 element = this.element.closest( ".ui-front" );
6874 }
6875
6876 if ( !element.length ) {
6877 element = this.document[0].body;
6878 }
6879
6880 return element;
6881 },
6882
6883 _initSource: function() {
6884 var array, url,
6885 that = this;
6886 if ( $.isArray(this.options.source) ) {
6887 array = this.options.source;
6888 this.source = function( request, response ) {
6889 response( $.ui.autocomplete.filter( array, request.term ) );
6890 };
6891 } else if ( typeof this.options.source === "string" ) {
6892 url = this.options.source;
6893 this.source = function( request, response ) {
6894 if ( that.xhr ) {
6895 that.xhr.abort();
6896 }
6897 that.xhr = $.ajax({
6898 url: url,
6899 data: request,
6900 dataType: "json",
6901 success: function( data ) {
6902 response( data );
6903 },
6904 error: function() {
6905 response( [] );
6906 }
6907 });
6908 };
6909 } else {
6910 this.source = this.options.source;
6911 }
6912 },
6913
6914 _searchTimeout: function( event ) {
6915 clearTimeout( this.searching );
6916 this.searching = this._delay(function() {
6917 // only search if the value has changed
6918 if ( this.term !== this._value() ) {
6919 this.selectedItem = null;
6920 this.search( null, event );
6921 }
6922 }, this.options.delay );
6923 },
6924
6925 search: function( value, event ) {
6926 value = value != null ? value : this._value();
6927
6928 // always save the actual value, not the one passed as an argument
6929 this.term = this._value();
6930
6931 if ( value.length < this.options.minLength ) {
6932 return this.close( event );
6933 }
6934
6935 if ( this._trigger( "search", event ) === false ) {
6936 return;
6937 }
6938
6939 return this._search( value );
6940 },
6941
6942 _search: function( value ) {
6943 this.pending++;
6944 this.element.addClass( "ui-autocomplete-loading" );
6945 this.cancelSearch = false;
6946
6947 this.source( { term: value }, this._response() );
6948 },
6949
6950 _response: function() {
6951 var that = this,
6952 index = ++requestIndex;
6953
6954 return function( content ) {
6955 if ( index === requestIndex ) {
6956 that.__response( content );
6957 }
6958
6959 that.pending--;
6960 if ( !that.pending ) {
6961 that.element.removeClass( "ui-autocomplete-loading" );
6962 }
6963 };
6964 },
6965
6966 __response: function( content ) {
6967 if ( content ) {
6968 content = this._normalize( content );
6969 }
6970 this._trigger( "response", null, { content: content } );
6971 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
6972 this._suggest( content );
6973 this._trigger( "open" );
6974 } else {
6975 // use ._close() instead of .close() so we don't cancel future searches
6976 this._close();
6977 }
6978 },
6979
6980 close: function( event ) {
6981 this.cancelSearch = true;
6982 this._close( event );
6983 },
6984
6985 _close: function( event ) {
6986 if ( this.menu.element.is( ":visible" ) ) {
6987 this.menu.element.hide();
6988 this.menu.blur();
6989 this.isNewMenu = true;
6990 this._trigger( "close", event );
6991 }
6992 },
6993
6994 _change: function( event ) {
6995 if ( this.previous !== this._value() ) {
6996 this._trigger( "change", event, { item: this.selectedItem } );
6997 }
6998 },
6999
7000 _normalize: function( items ) {
7001 // assume all items have the right format when the first item is complete
7002 if ( items.length && items[0].label && items[0].value ) {
7003 return items;
7004 }
7005 return $.map( items, function( item ) {
7006 if ( typeof item === "string" ) {
7007 return {
7008 label: item,
7009 value: item
7010 };
7011 }
7012 return $.extend({
7013 label: item.label || item.value,
7014 value: item.value || item.label
7015 }, item );
7016 });
7017 },
7018
7019 _suggest: function( items ) {
7020 var ul = this.menu.element.empty();
7021 this._renderMenu( ul, items );
7022 this.menu.refresh();
7023
7024 // size and position menu
7025 ul.show();
7026 this._resizeMenu();
7027 ul.position( $.extend({
7028 of: this.element
7029 }, this.options.position ));
7030
7031 if ( this.options.autoFocus ) {
7032 this.menu.next();
7033 }
7034 },
7035
7036 _resizeMenu: function() {
7037 var ul = this.menu.element;
7038 ul.outerWidth( Math.max(
7039 // Firefox wraps long text (possibly a rounding bug)
7040 // so we add 1px to avoid the wrapping (#7513)
7041 ul.width( "" ).outerWidth() + 1,
7042 this.element.outerWidth()
7043 ) );
7044 },
7045
7046 _renderMenu: function( ul, items ) {
7047 var that = this;
7048 $.each( items, function( index, item ) {
7049 that._renderItemData( ul, item );
7050 });
7051 },
7052
7053 _renderItemData: function( ul, item ) {
7054 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
7055 },
7056
7057 _renderItem: function( ul, item ) {
7058 return $( "<li>" )
7059 .append( $( "<a>" ).text( item.label ) )
7060 .appendTo( ul );
7061 },
7062
7063 _move: function( direction, event ) {
7064 if ( !this.menu.element.is( ":visible" ) ) {
7065 this.search( null, event );
7066 return;
7067 }
7068 if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
7069 this.menu.isLastItem() && /^next/.test( direction ) ) {
7070 this._value( this.term );
7071 this.menu.blur();
7072 return;
7073 }
7074 this.menu[ direction ]( event );
7075 },
7076
7077 widget: function() {
7078 return this.menu.element;
7079 },
7080
7081 _value: function() {
7082 return this.valueMethod.apply( this.element, arguments );
7083 },
7084
7085 _keyEvent: function( keyEvent, event ) {
7086 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
7087 this._move( keyEvent, event );
7088
7089 // prevents moving cursor to beginning/end of the text field in some browsers
7090 event.preventDefault();
7091 }
7092 }
7093});
7094
7095$.extend( $.ui.autocomplete, {
7096 escapeRegex: function( value ) {
7097 return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
7098 },
7099 filter: function(array, term) {
7100 var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
7101 return $.grep( array, function(value) {
7102 return matcher.test( value.label || value.value || value );
7103 });
7104 }
7105});
7106
7107
7108// live region extension, adding a `messages` option
7109// NOTE: This is an experimental API. We are still investigating
7110// a full solution for string manipulation and internationalization.
7111$.widget( "ui.autocomplete", $.ui.autocomplete, {
7112 options: {
7113 messages: {
7114 noResults: "No search results.",
7115 results: function( amount ) {
7116 return amount + ( amount > 1 ? " results are" : " result is" ) +
7117 " available, use up and down arrow keys to navigate.";
7118 }
7119 }
7120 },
7121
7122 __response: function( content ) {
7123 var message;
7124 this._superApply( arguments );
7125 if ( this.options.disabled || this.cancelSearch ) {
7126 return;
7127 }
7128 if ( content && content.length ) {
7129 message = this.options.messages.results( content.length );
7130 } else {
7131 message = this.options.messages.noResults;
7132 }
7133 this.liveRegion.text( message );
7134 }
7135});
7136
7137}( jQuery ));
7138
7139(function( $, undefined ) {
7140
7141var lastActive, startXPos, startYPos, clickDragged,
7142 baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
7143 stateClasses = "ui-state-hover ui-state-active ",
7144 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",
7145 formResetHandler = function() {
7146 var buttons = $( this ).find( ":ui-button" );
7147 setTimeout(function() {
7148 buttons.button( "refresh" );
7149 }, 1 );
7150 },
7151 radioGroup = function( radio ) {
7152 var name = radio.name,
7153 form = radio.form,
7154 radios = $( [] );
7155 if ( name ) {
7156 name = name.replace( /'/g, "\\'" );
7157 if ( form ) {
7158 radios = $( form ).find( "[name='" + name + "']" );
7159 } else {
7160 radios = $( "[name='" + name + "']", radio.ownerDocument )
7161 .filter(function() {
7162 return !this.form;
7163 });
7164 }
7165 }
7166 return radios;
7167 };
7168
7169$.widget( "ui.button", {
7170 version: "1.10.1",
7171 defaultElement: "<button>",
7172 options: {
7173 disabled: null,
7174 text: true,
7175 label: null,
7176 icons: {
7177 primary: null,
7178 secondary: null
7179 }
7180 },
7181 _create: function() {
7182 this.element.closest( "form" )
7183 .unbind( "reset" + this.eventNamespace )
7184 .bind( "reset" + this.eventNamespace, formResetHandler );
7185
7186 if ( typeof this.options.disabled !== "boolean" ) {
7187 this.options.disabled = !!this.element.prop( "disabled" );
7188 } else {
7189 this.element.prop( "disabled", this.options.disabled );
7190 }
7191
7192 this._determineButtonType();
7193 this.hasTitle = !!this.buttonElement.attr( "title" );
7194
7195 var that = this,
7196 options = this.options,
7197 toggleButton = this.type === "checkbox" || this.type === "radio",
7198 activeClass = !toggleButton ? "ui-state-active" : "",
7199 focusClass = "ui-state-focus";
7200
7201 if ( options.label === null ) {
7202 options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html());
7203 }
7204
7205 this._hoverable( this.buttonElement );
7206
7207 this.buttonElement
7208 .addClass( baseClasses )
7209 .attr( "role", "button" )
7210 .bind( "mouseenter" + this.eventNamespace, function() {
7211 if ( options.disabled ) {
7212 return;
7213 }
7214 if ( this === lastActive ) {
7215 $( this ).addClass( "ui-state-active" );
7216 }
7217 })
7218 .bind( "mouseleave" + this.eventNamespace, function() {
7219 if ( options.disabled ) {
7220 return;
7221 }
7222 $( this ).removeClass( activeClass );
7223 })
7224 .bind( "click" + this.eventNamespace, function( event ) {
7225 if ( options.disabled ) {
7226 event.preventDefault();
7227 event.stopImmediatePropagation();
7228 }
7229 });
7230
7231 this.element
7232 .bind( "focus" + this.eventNamespace, function() {
7233 // no need to check disabled, focus won't be triggered anyway
7234 that.buttonElement.addClass( focusClass );
7235 })
7236 .bind( "blur" + this.eventNamespace, function() {
7237 that.buttonElement.removeClass( focusClass );
7238 });
7239
7240 if ( toggleButton ) {
7241 this.element.bind( "change" + this.eventNamespace, function() {
7242 if ( clickDragged ) {
7243 return;
7244 }
7245 that.refresh();
7246 });
7247 // if mouse moves between mousedown and mouseup (drag) set clickDragged flag
7248 // prevents issue where button state changes but checkbox/radio checked state
7249 // does not in Firefox (see ticket #6970)
7250 this.buttonElement
7251 .bind( "mousedown" + this.eventNamespace, function( event ) {
7252 if ( options.disabled ) {
7253 return;
7254 }
7255 clickDragged = false;
7256 startXPos = event.pageX;
7257 startYPos = event.pageY;
7258 })
7259 .bind( "mouseup" + this.eventNamespace, function( event ) {
7260 if ( options.disabled ) {
7261 return;
7262 }
7263 if ( startXPos !== event.pageX || startYPos !== event.pageY ) {
7264 clickDragged = true;
7265 }
7266 });
7267 }
7268
7269 if ( this.type === "checkbox" ) {
7270 this.buttonElement.bind( "click" + this.eventNamespace, function() {
7271 if ( options.disabled || clickDragged ) {
7272 return false;
7273 }
7274 });
7275 } else if ( this.type === "radio" ) {
7276 this.buttonElement.bind( "click" + this.eventNamespace, function() {
7277 if ( options.disabled || clickDragged ) {
7278 return false;
7279 }
7280 $( this ).addClass( "ui-state-active" );
7281 that.buttonElement.attr( "aria-pressed", "true" );
7282
7283 var radio = that.element[ 0 ];
7284 radioGroup( radio )
7285 .not( radio )
7286 .map(function() {
7287 return $( this ).button( "widget" )[ 0 ];
7288 })
7289 .removeClass( "ui-state-active" )
7290 .attr( "aria-pressed", "false" );
7291 });
7292 } else {
7293 this.buttonElement
7294 .bind( "mousedown" + this.eventNamespace, function() {
7295 if ( options.disabled ) {
7296 return false;
7297 }
7298 $( this ).addClass( "ui-state-active" );
7299 lastActive = this;
7300 that.document.one( "mouseup", function() {
7301 lastActive = null;
7302 });
7303 })
7304 .bind( "mouseup" + this.eventNamespace, function() {
7305 if ( options.disabled ) {
7306 return false;
7307 }
7308 $( this ).removeClass( "ui-state-active" );
7309 })
7310 .bind( "keydown" + this.eventNamespace, function(event) {
7311 if ( options.disabled ) {
7312 return false;
7313 }
7314 if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) {
7315 $( this ).addClass( "ui-state-active" );
7316 }
7317 })
7318 // see #8559, we bind to blur here in case the button element loses
7319 // focus between keydown and keyup, it would be left in an "active" state
7320 .bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() {
7321 $( this ).removeClass( "ui-state-active" );
7322 });
7323
7324 if ( this.buttonElement.is("a") ) {
7325 this.buttonElement.keyup(function(event) {
7326 if ( event.keyCode === $.ui.keyCode.SPACE ) {
7327 // TODO pass through original event correctly (just as 2nd argument doesn't work)
7328 $( this ).click();
7329 }
7330 });
7331 }
7332 }
7333
7334 // TODO: pull out $.Widget's handling for the disabled option into
7335 // $.Widget.prototype._setOptionDisabled so it's easy to proxy and can
7336 // be overridden by individual plugins
7337 this._setOption( "disabled", options.disabled );
7338 this._resetButton();
7339 },
7340
7341 _determineButtonType: function() {
7342 var ancestor, labelSelector, checked;
7343
7344 if ( this.element.is("[type=checkbox]") ) {
7345 this.type = "checkbox";
7346 } else if ( this.element.is("[type=radio]") ) {
7347 this.type = "radio";
7348 } else if ( this.element.is("input") ) {
7349 this.type = "input";
7350 } else {
7351 this.type = "button";
7352 }
7353
7354 if ( this.type === "checkbox" || this.type === "radio" ) {
7355 // we don't search against the document in case the element
7356 // is disconnected from the DOM
7357 ancestor = this.element.parents().last();
7358 labelSelector = "label[for='" + this.element.attr("id") + "']";
7359 this.buttonElement = ancestor.find( labelSelector );
7360 if ( !this.buttonElement.length ) {
7361 ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
7362 this.buttonElement = ancestor.filter( labelSelector );
7363 if ( !this.buttonElement.length ) {
7364 this.buttonElement = ancestor.find( labelSelector );
7365 }
7366 }
7367 this.element.addClass( "ui-helper-hidden-accessible" );
7368
7369 checked = this.element.is( ":checked" );
7370 if ( checked ) {
7371 this.buttonElement.addClass( "ui-state-active" );
7372 }
7373 this.buttonElement.prop( "aria-pressed", checked );
7374 } else {
7375 this.buttonElement = this.element;
7376 }
7377 },
7378
7379 widget: function() {
7380 return this.buttonElement;
7381 },
7382
7383 _destroy: function() {
7384 this.element
7385 .removeClass( "ui-helper-hidden-accessible" );
7386 this.buttonElement
7387 .removeClass( baseClasses + " " + stateClasses + " " + typeClasses )
7388 .removeAttr( "role" )
7389 .removeAttr( "aria-pressed" )
7390 .html( this.buttonElement.find(".ui-button-text").html() );
7391
7392 if ( !this.hasTitle ) {
7393 this.buttonElement.removeAttr( "title" );
7394 }
7395 },
7396
7397 _setOption: function( key, value ) {
7398 this._super( key, value );
7399 if ( key === "disabled" ) {
7400 if ( value ) {
7401 this.element.prop( "disabled", true );
7402 } else {
7403 this.element.prop( "disabled", false );
7404 }
7405 return;
7406 }
7407 this._resetButton();
7408 },
7409
7410 refresh: function() {
7411 //See #8237 & #8828
7412 var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" );
7413
7414 if ( isDisabled !== this.options.disabled ) {
7415 this._setOption( "disabled", isDisabled );
7416 }
7417 if ( this.type === "radio" ) {
7418 radioGroup( this.element[0] ).each(function() {
7419 if ( $( this ).is( ":checked" ) ) {
7420 $( this ).button( "widget" )
7421 .addClass( "ui-state-active" )
7422 .attr( "aria-pressed", "true" );
7423 } else {
7424 $( this ).button( "widget" )
7425 .removeClass( "ui-state-active" )
7426 .attr( "aria-pressed", "false" );
7427 }
7428 });
7429 } else if ( this.type === "checkbox" ) {
7430 if ( this.element.is( ":checked" ) ) {
7431 this.buttonElement
7432 .addClass( "ui-state-active" )
7433 .attr( "aria-pressed", "true" );
7434 } else {
7435 this.buttonElement
7436 .removeClass( "ui-state-active" )
7437 .attr( "aria-pressed", "false" );
7438 }
7439 }
7440 },
7441
7442 _resetButton: function() {
7443 if ( this.type === "input" ) {
7444 if ( this.options.label ) {
7445 this.element.val( this.options.label );
7446 }
7447 return;
7448 }
7449 var buttonElement = this.buttonElement.removeClass( typeClasses ),
7450 buttonText = $( "<span></span>", this.document[0] )
7451 .addClass( "ui-button-text" )
7452 .html( this.options.label )
7453 .appendTo( buttonElement.empty() )
7454 .text(),
7455 icons = this.options.icons,
7456 multipleIcons = icons.primary && icons.secondary,
7457 buttonClasses = [];
7458
7459 if ( icons.primary || icons.secondary ) {
7460 if ( this.options.text ) {
7461 buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
7462 }
7463
7464 if ( icons.primary ) {
7465 buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
7466 }
7467
7468 if ( icons.secondary ) {
7469 buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
7470 }
7471
7472 if ( !this.options.text ) {
7473 buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );
7474
7475 if ( !this.hasTitle ) {
7476 buttonElement.attr( "title", $.trim( buttonText ) );
7477 }
7478 }
7479 } else {
7480 buttonClasses.push( "ui-button-text-only" );
7481 }
7482 buttonElement.addClass( buttonClasses.join( " " ) );
7483 }
7484});
7485
7486$.widget( "ui.buttonset", {
7487 version: "1.10.1",
7488 options: {
7489 items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"
7490 },
7491
7492 _create: function() {
7493 this.element.addClass( "ui-buttonset" );
7494 },
7495
7496 _init: function() {
7497 this.refresh();
7498 },
7499
7500 _setOption: function( key, value ) {
7501 if ( key === "disabled" ) {
7502 this.buttons.button( "option", key, value );
7503 }
7504
7505 this._super( key, value );
7506 },
7507
7508 refresh: function() {
7509 var rtl = this.element.css( "direction" ) === "rtl";
7510
7511 this.buttons = this.element.find( this.options.items )
7512 .filter( ":ui-button" )
7513 .button( "refresh" )
7514 .end()
7515 .not( ":ui-button" )
7516 .button()
7517 .end()
7518 .map(function() {
7519 return $( this ).button( "widget" )[ 0 ];
7520 })
7521 .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
7522 .filter( ":first" )
7523 .addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
7524 .end()
7525 .filter( ":last" )
7526 .addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
7527 .end()
7528 .end();
7529 },
7530
7531 _destroy: function() {
7532 this.element.removeClass( "ui-buttonset" );
7533 this.buttons
7534 .map(function() {
7535 return $( this ).button( "widget" )[ 0 ];
7536 })
7537 .removeClass( "ui-corner-left ui-corner-right" )
7538 .end()
7539 .button( "destroy" );
7540 }
7541});
7542
7543}( jQuery ) );
7544
7545(function( $, undefined ) {
7546
7547$.extend($.ui, { datepicker: { version: "1.10.1" } });
7548
7549var PROP_NAME = "datepicker",
7550 dpuuid = new Date().getTime(),
7551 instActive;
7552
7553/* Date picker manager.
7554 Use the singleton instance of this class, $.datepicker, to interact with the date picker.
7555 Settings for (groups of) date pickers are maintained in an instance object,
7556 allowing multiple different settings on the same page. */
7557
7558function Datepicker() {
7559 this._curInst = null; // The current instance in use
7560 this._keyEvent = false; // If the last event was a key event
7561 this._disabledInputs = []; // List of date picker inputs that have been disabled
7562 this._datepickerShowing = false; // True if the popup picker is showing , false if not
7563 this._inDialog = false; // True if showing within a "dialog", false if not
7564 this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
7565 this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
7566 this._appendClass = "ui-datepicker-append"; // The name of the append marker class
7567 this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
7568 this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
7569 this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
7570 this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
7571 this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
7572 this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
7573 this.regional = []; // Available regional settings, indexed by language code
7574 this.regional[""] = { // Default regional settings
7575 closeText: "Done", // Display text for close link
7576 prevText: "Prev", // Display text for previous month link
7577 nextText: "Next", // Display text for next month link
7578 currentText: "Today", // Display text for current month link
7579 monthNames: ["January","February","March","April","May","June",
7580 "July","August","September","October","November","December"], // Names of months for drop-down and formatting
7581 monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
7582 dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
7583 dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
7584 dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
7585 weekHeader: "Wk", // Column header for week of the year
7586 dateFormat: "mm/dd/yy", // See format options on parseDate
7587 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
7588 isRTL: false, // True if right-to-left language, false if left-to-right
7589 showMonthAfterYear: false, // True if the year select precedes month, false for month then year
7590 yearSuffix: "" // Additional text to append to the year in the month headers
7591 };
7592 this._defaults = { // Global defaults for all the date picker instances
7593 showOn: "focus", // "focus" for popup on focus,
7594 // "button" for trigger button, or "both" for either
7595 showAnim: "fadeIn", // Name of jQuery animation for popup
7596 showOptions: {}, // Options for enhanced animations
7597 defaultDate: null, // Used when field is blank: actual date,
7598 // +/-number for offset from today, null for today
7599 appendText: "", // Display text following the input box, e.g. showing the format
7600 buttonText: "...", // Text for trigger button
7601 buttonImage: "", // URL for trigger button image
7602 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
7603 hideIfNoPrevNext: false, // True to hide next/previous month links
7604 // if not applicable, false to just disable them
7605 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
7606 gotoCurrent: false, // True if today link goes back to current selection instead
7607 changeMonth: false, // True if month can be selected directly, false if only prev/next
7608 changeYear: false, // True if year can be selected directly, false if only prev/next
7609 yearRange: "c-10:c+10", // Range of years to display in drop-down,
7610 // either relative to today's year (-nn:+nn), relative to currently displayed year
7611 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
7612 showOtherMonths: false, // True to show dates in other months, false to leave blank
7613 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
7614 showWeek: false, // True to show week of the year, false to not show it
7615 calculateWeek: this.iso8601Week, // How to calculate the week of the year,
7616 // takes a Date and returns the number of the week for it
7617 shortYearCutoff: "+10", // Short year values < this are in the current century,
7618 // > this are in the previous century,
7619 // string value starting with "+" for current year + value
7620 minDate: null, // The earliest selectable date, or null for no limit
7621 maxDate: null, // The latest selectable date, or null for no limit
7622 duration: "fast", // Duration of display/closure
7623 beforeShowDay: null, // Function that takes a date and returns an array with
7624 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
7625 // [2] = cell title (optional), e.g. $.datepicker.noWeekends
7626 beforeShow: null, // Function that takes an input field and
7627 // returns a set of custom settings for the date picker
7628 onSelect: null, // Define a callback function when a date is selected
7629 onChangeMonthYear: null, // Define a callback function when the month or year is changed
7630 onClose: null, // Define a callback function when the datepicker is closed
7631 numberOfMonths: 1, // Number of months to show at a time
7632 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
7633 stepMonths: 1, // Number of months to step back/forward
7634 stepBigMonths: 12, // Number of months to step back/forward for the big links
7635 altField: "", // Selector for an alternate field to store selected dates into
7636 altFormat: "", // The date format to use for the alternate field
7637 constrainInput: true, // The input is constrained by the current date format
7638 showButtonPanel: false, // True to show button panel, false to not show it
7639 autoSize: false, // True to size the input for the date format, false to leave as is
7640 disabled: false // The initial disabled state
7641 };
7642 $.extend(this._defaults, this.regional[""]);
7643 this.dpDiv = bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
7644}
7645
7646$.extend(Datepicker.prototype, {
7647 /* Class name added to elements to indicate already configured with a date picker. */
7648 markerClassName: "hasDatepicker",
7649
7650 //Keep track of the maximum number of rows displayed (see #7043)
7651 maxRows: 4,
7652
7653 // TODO rename to "widget" when switching to widget factory
7654 _widgetDatepicker: function() {
7655 return this.dpDiv;
7656 },
7657
7658 /* Override the default settings for all instances of the date picker.
7659 * @param settings object - the new settings to use as defaults (anonymous object)
7660 * @return the manager object
7661 */
7662 setDefaults: function(settings) {
7663 extendRemove(this._defaults, settings || {});
7664 return this;
7665 },
7666
7667 /* Attach the date picker to a jQuery selection.
7668 * @param target element - the target input field or division or span
7669 * @param settings object - the new settings to use for this date picker instance (anonymous)
7670 */
7671 _attachDatepicker: function(target, settings) {
7672 var nodeName, inline, inst;
7673 nodeName = target.nodeName.toLowerCase();
7674 inline = (nodeName === "div" || nodeName === "span");
7675 if (!target.id) {
7676 this.uuid += 1;
7677 target.id = "dp" + this.uuid;
7678 }
7679 inst = this._newInst($(target), inline);
7680 inst.settings = $.extend({}, settings || {});
7681 if (nodeName === "input") {
7682 this._connectDatepicker(target, inst);
7683 } else if (inline) {
7684 this._inlineDatepicker(target, inst);
7685 }
7686 },
7687
7688 /* Create a new instance object. */
7689 _newInst: function(target, inline) {
7690 var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
7691 return {id: id, input: target, // associated target
7692 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
7693 drawMonth: 0, drawYear: 0, // month being drawn
7694 inline: inline, // is datepicker inline or not
7695 dpDiv: (!inline ? this.dpDiv : // presentation div
7696 bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
7697 },
7698
7699 /* Attach the date picker to an input field. */
7700 _connectDatepicker: function(target, inst) {
7701 var input = $(target);
7702 inst.append = $([]);
7703 inst.trigger = $([]);
7704 if (input.hasClass(this.markerClassName)) {
7705 return;
7706 }
7707 this._attachments(input, inst);
7708 input.addClass(this.markerClassName).keydown(this._doKeyDown).
7709 keypress(this._doKeyPress).keyup(this._doKeyUp);
7710 this._autoSize(inst);
7711 $.data(target, PROP_NAME, inst);
7712 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
7713 if( inst.settings.disabled ) {
7714 this._disableDatepicker( target );
7715 }
7716 },
7717
7718 /* Make attachments based on settings. */
7719 _attachments: function(input, inst) {
7720 var showOn, buttonText, buttonImage,
7721 appendText = this._get(inst, "appendText"),
7722 isRTL = this._get(inst, "isRTL");
7723
7724 if (inst.append) {
7725 inst.append.remove();
7726 }
7727 if (appendText) {
7728 inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
7729 input[isRTL ? "before" : "after"](inst.append);
7730 }
7731
7732 input.unbind("focus", this._showDatepicker);
7733
7734 if (inst.trigger) {
7735 inst.trigger.remove();
7736 }
7737
7738 showOn = this._get(inst, "showOn");
7739 if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
7740 input.focus(this._showDatepicker);
7741 }
7742 if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
7743 buttonText = this._get(inst, "buttonText");
7744 buttonImage = this._get(inst, "buttonImage");
7745 inst.trigger = $(this._get(inst, "buttonImageOnly") ?
7746 $("<img/>").addClass(this._triggerClass).
7747 attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
7748 $("<button type='button'></button>").addClass(this._triggerClass).
7749 html(!buttonImage ? buttonText : $("<img/>").attr(
7750 { src:buttonImage, alt:buttonText, title:buttonText })));
7751 input[isRTL ? "before" : "after"](inst.trigger);
7752 inst.trigger.click(function() {
7753 if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
7754 $.datepicker._hideDatepicker();
7755 } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
7756 $.datepicker._hideDatepicker();
7757 $.datepicker._showDatepicker(input[0]);
7758 } else {
7759 $.datepicker._showDatepicker(input[0]);
7760 }
7761 return false;
7762 });
7763 }
7764 },
7765
7766 /* Apply the maximum length for the date format. */
7767 _autoSize: function(inst) {
7768 if (this._get(inst, "autoSize") && !inst.inline) {
7769 var findMax, max, maxI, i,
7770 date = new Date(2009, 12 - 1, 20), // Ensure double digits
7771 dateFormat = this._get(inst, "dateFormat");
7772
7773 if (dateFormat.match(/[DM]/)) {
7774 findMax = function(names) {
7775 max = 0;
7776 maxI = 0;
7777 for (i = 0; i < names.length; i++) {
7778 if (names[i].length > max) {
7779 max = names[i].length;
7780 maxI = i;
7781 }
7782 }
7783 return maxI;
7784 };
7785 date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
7786 "monthNames" : "monthNamesShort"))));
7787 date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
7788 "dayNames" : "dayNamesShort"))) + 20 - date.getDay());
7789 }
7790 inst.input.attr("size", this._formatDate(inst, date).length);
7791 }
7792 },
7793
7794 /* Attach an inline date picker to a div. */
7795 _inlineDatepicker: function(target, inst) {
7796 var divSpan = $(target);
7797 if (divSpan.hasClass(this.markerClassName)) {
7798 return;
7799 }
7800 divSpan.addClass(this.markerClassName).append(inst.dpDiv);
7801 $.data(target, PROP_NAME, inst);
7802 this._setDate(inst, this._getDefaultDate(inst), true);
7803 this._updateDatepicker(inst);
7804 this._updateAlternate(inst);
7805 //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
7806 if( inst.settings.disabled ) {
7807 this._disableDatepicker( target );
7808 }
7809 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
7810 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
7811 inst.dpDiv.css( "display", "block" );
7812 },
7813
7814 /* Pop-up the date picker in a "dialog" box.
7815 * @param input element - ignored
7816 * @param date string or Date - the initial date to display
7817 * @param onSelect function - the function to call when a date is selected
7818 * @param settings object - update the dialog date picker instance's settings (anonymous object)
7819 * @param pos int[2] - coordinates for the dialog's position within the screen or
7820 * event - with x/y coordinates or
7821 * leave empty for default (screen centre)
7822 * @return the manager object
7823 */
7824 _dialogDatepicker: function(input, date, onSelect, settings, pos) {
7825 var id, browserWidth, browserHeight, scrollX, scrollY,
7826 inst = this._dialogInst; // internal instance
7827
7828 if (!inst) {
7829 this.uuid += 1;
7830 id = "dp" + this.uuid;
7831 this._dialogInput = $("<input type='text' id='" + id +
7832 "' style='position: absolute; top: -100px; width: 0px;'/>");
7833 this._dialogInput.keydown(this._doKeyDown);
7834 $("body").append(this._dialogInput);
7835 inst = this._dialogInst = this._newInst(this._dialogInput, false);
7836 inst.settings = {};
7837 $.data(this._dialogInput[0], PROP_NAME, inst);
7838 }
7839 extendRemove(inst.settings, settings || {});
7840 date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
7841 this._dialogInput.val(date);
7842
7843 this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
7844 if (!this._pos) {
7845 browserWidth = document.documentElement.clientWidth;
7846 browserHeight = document.documentElement.clientHeight;
7847 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
7848 scrollY = document.documentElement.scrollTop || document.body.scrollTop;
7849 this._pos = // should use actual width/height below
7850 [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
7851 }
7852
7853 // move input on screen for focus, but hidden behind dialog
7854 this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
7855 inst.settings.onSelect = onSelect;
7856 this._inDialog = true;
7857 this.dpDiv.addClass(this._dialogClass);
7858 this._showDatepicker(this._dialogInput[0]);
7859 if ($.blockUI) {
7860 $.blockUI(this.dpDiv);
7861 }
7862 $.data(this._dialogInput[0], PROP_NAME, inst);
7863 return this;
7864 },
7865
7866 /* Detach a datepicker from its control.
7867 * @param target element - the target input field or division or span
7868 */
7869 _destroyDatepicker: function(target) {
7870 var nodeName,
7871 $target = $(target),
7872 inst = $.data(target, PROP_NAME);
7873
7874 if (!$target.hasClass(this.markerClassName)) {
7875 return;
7876 }
7877
7878 nodeName = target.nodeName.toLowerCase();
7879 $.removeData(target, PROP_NAME);
7880 if (nodeName === "input") {
7881 inst.append.remove();
7882 inst.trigger.remove();
7883 $target.removeClass(this.markerClassName).
7884 unbind("focus", this._showDatepicker).
7885 unbind("keydown", this._doKeyDown).
7886 unbind("keypress", this._doKeyPress).
7887 unbind("keyup", this._doKeyUp);
7888 } else if (nodeName === "div" || nodeName === "span") {
7889 $target.removeClass(this.markerClassName).empty();
7890 }
7891 },
7892
7893 /* Enable the date picker to a jQuery selection.
7894 * @param target element - the target input field or division or span
7895 */
7896 _enableDatepicker: function(target) {
7897 var nodeName, inline,
7898 $target = $(target),
7899 inst = $.data(target, PROP_NAME);
7900
7901 if (!$target.hasClass(this.markerClassName)) {
7902 return;
7903 }
7904
7905 nodeName = target.nodeName.toLowerCase();
7906 if (nodeName === "input") {
7907 target.disabled = false;
7908 inst.trigger.filter("button").
7909 each(function() { this.disabled = false; }).end().
7910 filter("img").css({opacity: "1.0", cursor: ""});
7911 } else if (nodeName === "div" || nodeName === "span") {
7912 inline = $target.children("." + this._inlineClass);
7913 inline.children().removeClass("ui-state-disabled");
7914 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
7915 prop("disabled", false);
7916 }
7917 this._disabledInputs = $.map(this._disabledInputs,
7918 function(value) { return (value === target ? null : value); }); // delete entry
7919 },
7920
7921 /* Disable the date picker to a jQuery selection.
7922 * @param target element - the target input field or division or span
7923 */
7924 _disableDatepicker: function(target) {
7925 var nodeName, inline,
7926 $target = $(target),
7927 inst = $.data(target, PROP_NAME);
7928
7929 if (!$target.hasClass(this.markerClassName)) {
7930 return;
7931 }
7932
7933 nodeName = target.nodeName.toLowerCase();
7934 if (nodeName === "input") {
7935 target.disabled = true;
7936 inst.trigger.filter("button").
7937 each(function() { this.disabled = true; }).end().
7938 filter("img").css({opacity: "0.5", cursor: "default"});
7939 } else if (nodeName === "div" || nodeName === "span") {
7940 inline = $target.children("." + this._inlineClass);
7941 inline.children().addClass("ui-state-disabled");
7942 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
7943 prop("disabled", true);
7944 }
7945 this._disabledInputs = $.map(this._disabledInputs,
7946 function(value) { return (value === target ? null : value); }); // delete entry
7947 this._disabledInputs[this._disabledInputs.length] = target;
7948 },
7949
7950 /* Is the first field in a jQuery collection disabled as a datepicker?
7951 * @param target element - the target input field or division or span
7952 * @return boolean - true if disabled, false if enabled
7953 */
7954 _isDisabledDatepicker: function(target) {
7955 if (!target) {
7956 return false;
7957 }
7958 for (var i = 0; i < this._disabledInputs.length; i++) {
7959 if (this._disabledInputs[i] === target) {
7960 return true;
7961 }
7962 }
7963 return false;
7964 },
7965
7966 /* Retrieve the instance data for the target control.
7967 * @param target element - the target input field or division or span
7968 * @return object - the associated instance data
7969 * @throws error if a jQuery problem getting data
7970 */
7971 _getInst: function(target) {
7972 try {
7973 return $.data(target, PROP_NAME);
7974 }
7975 catch (err) {
7976 throw "Missing instance data for this datepicker";
7977 }
7978 },
7979
7980 /* Update or retrieve the settings for a date picker attached to an input field or division.
7981 * @param target element - the target input field or division or span
7982 * @param name object - the new settings to update or
7983 * string - the name of the setting to change or retrieve,
7984 * when retrieving also "all" for all instance settings or
7985 * "defaults" for all global defaults
7986 * @param value any - the new value for the setting
7987 * (omit if above is an object or to retrieve a value)
7988 */
7989 _optionDatepicker: function(target, name, value) {
7990 var settings, date, minDate, maxDate,
7991 inst = this._getInst(target);
7992
7993 if (arguments.length === 2 && typeof name === "string") {
7994 return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
7995 (inst ? (name === "all" ? $.extend({}, inst.settings) :
7996 this._get(inst, name)) : null));
7997 }
7998
7999 settings = name || {};
8000 if (typeof name === "string") {
8001 settings = {};
8002 settings[name] = value;
8003 }
8004
8005 if (inst) {
8006 if (this._curInst === inst) {
8007 this._hideDatepicker();
8008 }
8009
8010 date = this._getDateDatepicker(target, true);
8011 minDate = this._getMinMaxDate(inst, "min");
8012 maxDate = this._getMinMaxDate(inst, "max");
8013 extendRemove(inst.settings, settings);
8014 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
8015 if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
8016 inst.settings.minDate = this._formatDate(inst, minDate);
8017 }
8018 if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
8019 inst.settings.maxDate = this._formatDate(inst, maxDate);
8020 }
8021 if ( "disabled" in settings ) {
8022 if ( settings.disabled ) {
8023 this._disableDatepicker(target);
8024 } else {
8025 this._enableDatepicker(target);
8026 }
8027 }
8028 this._attachments($(target), inst);
8029 this._autoSize(inst);
8030 this._setDate(inst, date);
8031 this._updateAlternate(inst);
8032 this._updateDatepicker(inst);
8033 }
8034 },
8035
8036 // change method deprecated
8037 _changeDatepicker: function(target, name, value) {
8038 this._optionDatepicker(target, name, value);
8039 },
8040
8041 /* Redraw the date picker attached to an input field or division.
8042 * @param target element - the target input field or division or span
8043 */
8044 _refreshDatepicker: function(target) {
8045 var inst = this._getInst(target);
8046 if (inst) {
8047 this._updateDatepicker(inst);
8048 }
8049 },
8050
8051 /* Set the dates for a jQuery selection.
8052 * @param target element - the target input field or division or span
8053 * @param date Date - the new date
8054 */
8055 _setDateDatepicker: function(target, date) {
8056 var inst = this._getInst(target);
8057 if (inst) {
8058 this._setDate(inst, date);
8059 this._updateDatepicker(inst);
8060 this._updateAlternate(inst);
8061 }
8062 },
8063
8064 /* Get the date(s) for the first entry in a jQuery selection.
8065 * @param target element - the target input field or division or span
8066 * @param noDefault boolean - true if no default date is to be used
8067 * @return Date - the current date
8068 */
8069 _getDateDatepicker: function(target, noDefault) {
8070 var inst = this._getInst(target);
8071 if (inst && !inst.inline) {
8072 this._setDateFromField(inst, noDefault);
8073 }
8074 return (inst ? this._getDate(inst) : null);
8075 },
8076
8077 /* Handle keystrokes. */
8078 _doKeyDown: function(event) {
8079 var onSelect, dateStr, sel,
8080 inst = $.datepicker._getInst(event.target),
8081 handled = true,
8082 isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
8083
8084 inst._keyEvent = true;
8085 if ($.datepicker._datepickerShowing) {
8086 switch (event.keyCode) {
8087 case 9: $.datepicker._hideDatepicker();
8088 handled = false;
8089 break; // hide on tab out
8090 case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
8091 $.datepicker._currentClass + ")", inst.dpDiv);
8092 if (sel[0]) {
8093 $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
8094 }
8095
8096 onSelect = $.datepicker._get(inst, "onSelect");
8097 if (onSelect) {
8098 dateStr = $.datepicker._formatDate(inst);
8099
8100 // trigger custom callback
8101 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
8102 } else {
8103 $.datepicker._hideDatepicker();
8104 }
8105
8106 return false; // don't submit the form
8107 case 27: $.datepicker._hideDatepicker();
8108 break; // hide on escape
8109 case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
8110 -$.datepicker._get(inst, "stepBigMonths") :
8111 -$.datepicker._get(inst, "stepMonths")), "M");
8112 break; // previous month/year on page up/+ ctrl
8113 case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
8114 +$.datepicker._get(inst, "stepBigMonths") :
8115 +$.datepicker._get(inst, "stepMonths")), "M");
8116 break; // next month/year on page down/+ ctrl
8117 case 35: if (event.ctrlKey || event.metaKey) {
8118 $.datepicker._clearDate(event.target);
8119 }
8120 handled = event.ctrlKey || event.metaKey;
8121 break; // clear on ctrl or command +end
8122 case 36: if (event.ctrlKey || event.metaKey) {
8123 $.datepicker._gotoToday(event.target);
8124 }
8125 handled = event.ctrlKey || event.metaKey;
8126 break; // current on ctrl or command +home
8127 case 37: if (event.ctrlKey || event.metaKey) {
8128 $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
8129 }
8130 handled = event.ctrlKey || event.metaKey;
8131 // -1 day on ctrl or command +left
8132 if (event.originalEvent.altKey) {
8133 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
8134 -$.datepicker._get(inst, "stepBigMonths") :
8135 -$.datepicker._get(inst, "stepMonths")), "M");
8136 }
8137 // next month/year on alt +left on Mac
8138 break;
8139 case 38: if (event.ctrlKey || event.metaKey) {
8140 $.datepicker._adjustDate(event.target, -7, "D");
8141 }
8142 handled = event.ctrlKey || event.metaKey;
8143 break; // -1 week on ctrl or command +up
8144 case 39: if (event.ctrlKey || event.metaKey) {
8145 $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
8146 }
8147 handled = event.ctrlKey || event.metaKey;
8148 // +1 day on ctrl or command +right
8149 if (event.originalEvent.altKey) {
8150 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
8151 +$.datepicker._get(inst, "stepBigMonths") :
8152 +$.datepicker._get(inst, "stepMonths")), "M");
8153 }
8154 // next month/year on alt +right
8155 break;
8156 case 40: if (event.ctrlKey || event.metaKey) {
8157 $.datepicker._adjustDate(event.target, +7, "D");
8158 }
8159 handled = event.ctrlKey || event.metaKey;
8160 break; // +1 week on ctrl or command +down
8161 default: handled = false;
8162 }
8163 } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
8164 $.datepicker._showDatepicker(this);
8165 } else {
8166 handled = false;
8167 }
8168
8169 if (handled) {
8170 event.preventDefault();
8171 event.stopPropagation();
8172 }
8173 },
8174
8175 /* Filter entered characters - based on date format. */
8176 _doKeyPress: function(event) {
8177 var chars, chr,
8178 inst = $.datepicker._getInst(event.target);
8179
8180 if ($.datepicker._get(inst, "constrainInput")) {
8181 chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
8182 chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
8183 return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
8184 }
8185 },
8186
8187 /* Synchronise manual entry and field/alternate field. */
8188 _doKeyUp: function(event) {
8189 var date,
8190 inst = $.datepicker._getInst(event.target);
8191
8192 if (inst.input.val() !== inst.lastVal) {
8193 try {
8194 date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
8195 (inst.input ? inst.input.val() : null),
8196 $.datepicker._getFormatConfig(inst));
8197
8198 if (date) { // only if valid
8199 $.datepicker._setDateFromField(inst);
8200 $.datepicker._updateAlternate(inst);
8201 $.datepicker._updateDatepicker(inst);
8202 }
8203 }
8204 catch (err) {
8205 }
8206 }
8207 return true;
8208 },
8209
8210 /* Pop-up the date picker for a given input field.
8211 * If false returned from beforeShow event handler do not show.
8212 * @param input element - the input field attached to the date picker or
8213 * event - if triggered by focus
8214 */
8215 _showDatepicker: function(input) {
8216 input = input.target || input;
8217 if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
8218 input = $("input", input.parentNode)[0];
8219 }
8220
8221 if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
8222 return;
8223 }
8224
8225 var inst, beforeShow, beforeShowSettings, isFixed,
8226 offset, showAnim, duration;
8227
8228 inst = $.datepicker._getInst(input);
8229 if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
8230 $.datepicker._curInst.dpDiv.stop(true, true);
8231 if ( inst && $.datepicker._datepickerShowing ) {
8232 $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
8233 }
8234 }
8235
8236 beforeShow = $.datepicker._get(inst, "beforeShow");
8237 beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
8238 if(beforeShowSettings === false){
8239 return;
8240 }
8241 extendRemove(inst.settings, beforeShowSettings);
8242
8243 inst.lastVal = null;
8244 $.datepicker._lastInput = input;
8245 $.datepicker._setDateFromField(inst);
8246
8247 if ($.datepicker._inDialog) { // hide cursor
8248 input.value = "";
8249 }
8250 if (!$.datepicker._pos) { // position below input
8251 $.datepicker._pos = $.datepicker._findPos(input);
8252 $.datepicker._pos[1] += input.offsetHeight; // add the height
8253 }
8254
8255 isFixed = false;
8256 $(input).parents().each(function() {
8257 isFixed |= $(this).css("position") === "fixed";
8258 return !isFixed;
8259 });
8260
8261 offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
8262 $.datepicker._pos = null;
8263 //to avoid flashes on Firefox
8264 inst.dpDiv.empty();
8265 // determine sizing offscreen
8266 inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
8267 $.datepicker._updateDatepicker(inst);
8268 // fix width for dynamic number of date pickers
8269 // and adjust position before showing
8270 offset = $.datepicker._checkOffset(inst, offset, isFixed);
8271 inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
8272 "static" : (isFixed ? "fixed" : "absolute")), display: "none",
8273 left: offset.left + "px", top: offset.top + "px"});
8274
8275 if (!inst.inline) {
8276 showAnim = $.datepicker._get(inst, "showAnim");
8277 duration = $.datepicker._get(inst, "duration");
8278 inst.dpDiv.zIndex($(input).zIndex()+1);
8279 $.datepicker._datepickerShowing = true;
8280
8281 if ( $.effects && $.effects.effect[ showAnim ] ) {
8282 inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
8283 } else {
8284 inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
8285 }
8286
8287 if (inst.input.is(":visible") && !inst.input.is(":disabled")) {
8288 inst.input.focus();
8289 }
8290 $.datepicker._curInst = inst;
8291 }
8292 },
8293
8294 /* Generate the date picker content. */
8295 _updateDatepicker: function(inst) {
8296 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
8297 instActive = inst; // for delegate hover events
8298 inst.dpDiv.empty().append(this._generateHTML(inst));
8299 this._attachHandlers(inst);
8300 inst.dpDiv.find("." + this._dayOverClass + " a").mouseover();
8301
8302 var origyearshtml,
8303 numMonths = this._getNumberOfMonths(inst),
8304 cols = numMonths[1],
8305 width = 17;
8306
8307 inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
8308 if (cols > 1) {
8309 inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
8310 }
8311 inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
8312 "Class"]("ui-datepicker-multi");
8313 inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
8314 "Class"]("ui-datepicker-rtl");
8315
8316 // #6694 - don't focus the input if it's already focused
8317 // this breaks the change event in IE
8318 if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && inst.input &&
8319 inst.input.is(":visible") && !inst.input.is(":disabled") && inst.input[0] !== document.activeElement) {
8320 inst.input.focus();
8321 }
8322
8323 // deffered render of the years select (to avoid flashes on Firefox)
8324 if( inst.yearshtml ){
8325 origyearshtml = inst.yearshtml;
8326 setTimeout(function(){
8327 //assure that inst.yearshtml didn't change.
8328 if( origyearshtml === inst.yearshtml && inst.yearshtml ){
8329 inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
8330 }
8331 origyearshtml = inst.yearshtml = null;
8332 }, 0);
8333 }
8334 },
8335
8336 /* Retrieve the size of left and top borders for an element.
8337 * @param elem (jQuery object) the element of interest
8338 * @return (number[2]) the left and top borders
8339 */
8340 _getBorders: function(elem) {
8341 var convert = function(value) {
8342 return {thin: 1, medium: 2, thick: 3}[value] || value;
8343 };
8344 return [parseFloat(convert(elem.css("border-left-width"))),
8345 parseFloat(convert(elem.css("border-top-width")))];
8346 },
8347
8348 /* Check positioning to remain on screen. */
8349 _checkOffset: function(inst, offset, isFixed) {
8350 var dpWidth = inst.dpDiv.outerWidth(),
8351 dpHeight = inst.dpDiv.outerHeight(),
8352 inputWidth = inst.input ? inst.input.outerWidth() : 0,
8353 inputHeight = inst.input ? inst.input.outerHeight() : 0,
8354 viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
8355 viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
8356
8357 offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
8358 offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
8359 offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
8360
8361 // now check if datepicker is showing outside window viewport - move to a better place if so.
8362 offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
8363 Math.abs(offset.left + dpWidth - viewWidth) : 0);
8364 offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
8365 Math.abs(dpHeight + inputHeight) : 0);
8366
8367 return offset;
8368 },
8369
8370 /* Find an object's position on the screen. */
8371 _findPos: function(obj) {
8372 var position,
8373 inst = this._getInst(obj),
8374 isRTL = this._get(inst, "isRTL");
8375
8376 while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
8377 obj = obj[isRTL ? "previousSibling" : "nextSibling"];
8378 }
8379
8380 position = $(obj).offset();
8381 return [position.left, position.top];
8382 },
8383
8384 /* Hide the date picker from view.
8385 * @param input element - the input field attached to the date picker
8386 */
8387 _hideDatepicker: function(input) {
8388 var showAnim, duration, postProcess, onClose,
8389 inst = this._curInst;
8390
8391 if (!inst || (input && inst !== $.data(input, PROP_NAME))) {
8392 return;
8393 }
8394
8395 if (this._datepickerShowing) {
8396 showAnim = this._get(inst, "showAnim");
8397 duration = this._get(inst, "duration");
8398 postProcess = function() {
8399 $.datepicker._tidyDialog(inst);
8400 };
8401
8402 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
8403 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
8404 inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
8405 } else {
8406 inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
8407 (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
8408 }
8409
8410 if (!showAnim) {
8411 postProcess();
8412 }
8413 this._datepickerShowing = false;
8414
8415 onClose = this._get(inst, "onClose");
8416 if (onClose) {
8417 onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
8418 }
8419
8420 this._lastInput = null;
8421 if (this._inDialog) {
8422 this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
8423 if ($.blockUI) {
8424 $.unblockUI();
8425 $("body").append(this.dpDiv);
8426 }
8427 }
8428 this._inDialog = false;
8429 }
8430 },
8431
8432 /* Tidy up after a dialog display. */
8433 _tidyDialog: function(inst) {
8434 inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");
8435 },
8436
8437 /* Close date picker if clicked elsewhere. */
8438 _checkExternalClick: function(event) {
8439 if (!$.datepicker._curInst) {
8440 return;
8441 }
8442
8443 var $target = $(event.target),
8444 inst = $.datepicker._getInst($target[0]);
8445
8446 if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
8447 $target.parents("#" + $.datepicker._mainDivId).length === 0 &&
8448 !$target.hasClass($.datepicker.markerClassName) &&
8449 !$target.closest("." + $.datepicker._triggerClass).length &&
8450 $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
8451 ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
8452 $.datepicker._hideDatepicker();
8453 }
8454 },
8455
8456 /* Adjust one of the date sub-fields. */
8457 _adjustDate: function(id, offset, period) {
8458 var target = $(id),
8459 inst = this._getInst(target[0]);
8460
8461 if (this._isDisabledDatepicker(target[0])) {
8462 return;
8463 }
8464 this._adjustInstDate(inst, offset +
8465 (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
8466 period);
8467 this._updateDatepicker(inst);
8468 },
8469
8470 /* Action for current link. */
8471 _gotoToday: function(id) {
8472 var date,
8473 target = $(id),
8474 inst = this._getInst(target[0]);
8475
8476 if (this._get(inst, "gotoCurrent") && inst.currentDay) {
8477 inst.selectedDay = inst.currentDay;
8478 inst.drawMonth = inst.selectedMonth = inst.currentMonth;
8479 inst.drawYear = inst.selectedYear = inst.currentYear;
8480 } else {
8481 date = new Date();
8482 inst.selectedDay = date.getDate();
8483 inst.drawMonth = inst.selectedMonth = date.getMonth();
8484 inst.drawYear = inst.selectedYear = date.getFullYear();
8485 }
8486 this._notifyChange(inst);
8487 this._adjustDate(target);
8488 },
8489
8490 /* Action for selecting a new month/year. */
8491 _selectMonthYear: function(id, select, period) {
8492 var target = $(id),
8493 inst = this._getInst(target[0]);
8494
8495 inst["selected" + (period === "M" ? "Month" : "Year")] =
8496 inst["draw" + (period === "M" ? "Month" : "Year")] =
8497 parseInt(select.options[select.selectedIndex].value,10);
8498
8499 this._notifyChange(inst);
8500 this._adjustDate(target);
8501 },
8502
8503 /* Action for selecting a day. */
8504 _selectDay: function(id, month, year, td) {
8505 var inst,
8506 target = $(id);
8507
8508 if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
8509 return;
8510 }
8511
8512 inst = this._getInst(target[0]);
8513 inst.selectedDay = inst.currentDay = $("a", td).html();
8514 inst.selectedMonth = inst.currentMonth = month;
8515 inst.selectedYear = inst.currentYear = year;
8516 this._selectDate(id, this._formatDate(inst,
8517 inst.currentDay, inst.currentMonth, inst.currentYear));
8518 },
8519
8520 /* Erase the input field and hide the date picker. */
8521 _clearDate: function(id) {
8522 var target = $(id);
8523 this._selectDate(target, "");
8524 },
8525
8526 /* Update the input field with the selected date. */
8527 _selectDate: function(id, dateStr) {
8528 var onSelect,
8529 target = $(id),
8530 inst = this._getInst(target[0]);
8531
8532 dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
8533 if (inst.input) {
8534 inst.input.val(dateStr);
8535 }
8536 this._updateAlternate(inst);
8537
8538 onSelect = this._get(inst, "onSelect");
8539 if (onSelect) {
8540 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
8541 } else if (inst.input) {
8542 inst.input.trigger("change"); // fire the change event
8543 }
8544
8545 if (inst.inline){
8546 this._updateDatepicker(inst);
8547 } else {
8548 this._hideDatepicker();
8549 this._lastInput = inst.input[0];
8550 if (typeof(inst.input[0]) !== "object") {
8551 inst.input.focus(); // restore focus
8552 }
8553 this._lastInput = null;
8554 }
8555 },
8556
8557 /* Update any alternate field to synchronise with the main field. */
8558 _updateAlternate: function(inst) {
8559 var altFormat, date, dateStr,
8560 altField = this._get(inst, "altField");
8561
8562 if (altField) { // update alternate field too
8563 altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
8564 date = this._getDate(inst);
8565 dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
8566 $(altField).each(function() { $(this).val(dateStr); });
8567 }
8568 },
8569
8570 /* Set as beforeShowDay function to prevent selection of weekends.
8571 * @param date Date - the date to customise
8572 * @return [boolean, string] - is this date selectable?, what is its CSS class?
8573 */
8574 noWeekends: function(date) {
8575 var day = date.getDay();
8576 return [(day > 0 && day < 6), ""];
8577 },
8578
8579 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
8580 * @param date Date - the date to get the week for
8581 * @return number - the number of the week within the year that contains this date
8582 */
8583 iso8601Week: function(date) {
8584 var time,
8585 checkDate = new Date(date.getTime());
8586
8587 // Find Thursday of this week starting on Monday
8588 checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
8589
8590 time = checkDate.getTime();
8591 checkDate.setMonth(0); // Compare with Jan 1
8592 checkDate.setDate(1);
8593 return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
8594 },
8595
8596 /* Parse a string value into a date object.
8597 * See formatDate below for the possible formats.
8598 *
8599 * @param format string - the expected format of the date
8600 * @param value string - the date in the above format
8601 * @param settings Object - attributes include:
8602 * shortYearCutoff number - the cutoff year for determining the century (optional)
8603 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
8604 * dayNames string[7] - names of the days from Sunday (optional)
8605 * monthNamesShort string[12] - abbreviated names of the months (optional)
8606 * monthNames string[12] - names of the months (optional)
8607 * @return Date - the extracted date value or null if value is blank
8608 */
8609 parseDate: function (format, value, settings) {
8610 if (format == null || value == null) {
8611 throw "Invalid arguments";
8612 }
8613
8614 value = (typeof value === "object" ? value.toString() : value + "");
8615 if (value === "") {
8616 return null;
8617 }
8618
8619 var iFormat, dim, extra,
8620 iValue = 0,
8621 shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
8622 shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
8623 new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
8624 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
8625 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
8626 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
8627 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
8628 year = -1,
8629 month = -1,
8630 day = -1,
8631 doy = -1,
8632 literal = false,
8633 date,
8634 // Check whether a format character is doubled
8635 lookAhead = function(match) {
8636 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
8637 if (matches) {
8638 iFormat++;
8639 }
8640 return matches;
8641 },
8642 // Extract a number from the string value
8643 getNumber = function(match) {
8644 var isDoubled = lookAhead(match),
8645 size = (match === "@" ? 14 : (match === "!" ? 20 :
8646 (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
8647 digits = new RegExp("^\\d{1," + size + "}"),
8648 num = value.substring(iValue).match(digits);
8649 if (!num) {
8650 throw "Missing number at position " + iValue;
8651 }
8652 iValue += num[0].length;
8653 return parseInt(num[0], 10);
8654 },
8655 // Extract a name from the string value and convert to an index
8656 getName = function(match, shortNames, longNames) {
8657 var index = -1,
8658 names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
8659 return [ [k, v] ];
8660 }).sort(function (a, b) {
8661 return -(a[1].length - b[1].length);
8662 });
8663
8664 $.each(names, function (i, pair) {
8665 var name = pair[1];
8666 if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
8667 index = pair[0];
8668 iValue += name.length;
8669 return false;
8670 }
8671 });
8672 if (index !== -1) {
8673 return index + 1;
8674 } else {
8675 throw "Unknown name at position " + iValue;
8676 }
8677 },
8678 // Confirm that a literal character matches the string value
8679 checkLiteral = function() {
8680 if (value.charAt(iValue) !== format.charAt(iFormat)) {
8681 throw "Unexpected literal at position " + iValue;
8682 }
8683 iValue++;
8684 };
8685
8686 for (iFormat = 0; iFormat < format.length; iFormat++) {
8687 if (literal) {
8688 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
8689 literal = false;
8690 } else {
8691 checkLiteral();
8692 }
8693 } else {
8694 switch (format.charAt(iFormat)) {
8695 case "d":
8696 day = getNumber("d");
8697 break;
8698 case "D":
8699 getName("D", dayNamesShort, dayNames);
8700 break;
8701 case "o":
8702 doy = getNumber("o");
8703 break;
8704 case "m":
8705 month = getNumber("m");
8706 break;
8707 case "M":
8708 month = getName("M", monthNamesShort, monthNames);
8709 break;
8710 case "y":
8711 year = getNumber("y");
8712 break;
8713 case "@":
8714 date = new Date(getNumber("@"));
8715 year = date.getFullYear();
8716 month = date.getMonth() + 1;
8717 day = date.getDate();
8718 break;
8719 case "!":
8720 date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
8721 year = date.getFullYear();
8722 month = date.getMonth() + 1;
8723 day = date.getDate();
8724 break;
8725 case "'":
8726 if (lookAhead("'")){
8727 checkLiteral();
8728 } else {
8729 literal = true;
8730 }
8731 break;
8732 default:
8733 checkLiteral();
8734 }
8735 }
8736 }
8737
8738 if (iValue < value.length){
8739 extra = value.substr(iValue);
8740 if (!/^\s+/.test(extra)) {
8741 throw "Extra/unparsed characters found in date: " + extra;
8742 }
8743 }
8744
8745 if (year === -1) {
8746 year = new Date().getFullYear();
8747 } else if (year < 100) {
8748 year += new Date().getFullYear() - new Date().getFullYear() % 100 +
8749 (year <= shortYearCutoff ? 0 : -100);
8750 }
8751
8752 if (doy > -1) {
8753 month = 1;
8754 day = doy;
8755 do {
8756 dim = this._getDaysInMonth(year, month - 1);
8757 if (day <= dim) {
8758 break;
8759 }
8760 month++;
8761 day -= dim;
8762 } while (true);
8763 }
8764
8765 date = this._daylightSavingAdjust(new Date(year, month - 1, day));
8766 if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
8767 throw "Invalid date"; // E.g. 31/02/00
8768 }
8769 return date;
8770 },
8771
8772 /* Standard date formats. */
8773 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
8774 COOKIE: "D, dd M yy",
8775 ISO_8601: "yy-mm-dd",
8776 RFC_822: "D, d M y",
8777 RFC_850: "DD, dd-M-y",
8778 RFC_1036: "D, d M y",
8779 RFC_1123: "D, d M yy",
8780 RFC_2822: "D, d M yy",
8781 RSS: "D, d M y", // RFC 822
8782 TICKS: "!",
8783 TIMESTAMP: "@",
8784 W3C: "yy-mm-dd", // ISO 8601
8785
8786 _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
8787 Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
8788
8789 /* Format a date object into a string value.
8790 * The format can be combinations of the following:
8791 * d - day of month (no leading zero)
8792 * dd - day of month (two digit)
8793 * o - day of year (no leading zeros)
8794 * oo - day of year (three digit)
8795 * D - day name short
8796 * DD - day name long
8797 * m - month of year (no leading zero)
8798 * mm - month of year (two digit)
8799 * M - month name short
8800 * MM - month name long
8801 * y - year (two digit)
8802 * yy - year (four digit)
8803 * @ - Unix timestamp (ms since 01/01/1970)
8804 * ! - Windows ticks (100ns since 01/01/0001)
8805 * "..." - literal text
8806 * '' - single quote
8807 *
8808 * @param format string - the desired format of the date
8809 * @param date Date - the date value to format
8810 * @param settings Object - attributes include:
8811 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
8812 * dayNames string[7] - names of the days from Sunday (optional)
8813 * monthNamesShort string[12] - abbreviated names of the months (optional)
8814 * monthNames string[12] - names of the months (optional)
8815 * @return string - the date in the above format
8816 */
8817 formatDate: function (format, date, settings) {
8818 if (!date) {
8819 return "";
8820 }
8821
8822 var iFormat,
8823 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
8824 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
8825 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
8826 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
8827 // Check whether a format character is doubled
8828 lookAhead = function(match) {
8829 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
8830 if (matches) {
8831 iFormat++;
8832 }
8833 return matches;
8834 },
8835 // Format a number, with leading zero if necessary
8836 formatNumber = function(match, value, len) {
8837 var num = "" + value;
8838 if (lookAhead(match)) {
8839 while (num.length < len) {
8840 num = "0" + num;
8841 }
8842 }
8843 return num;
8844 },
8845 // Format a name, short or long as requested
8846 formatName = function(match, value, shortNames, longNames) {
8847 return (lookAhead(match) ? longNames[value] : shortNames[value]);
8848 },
8849 output = "",
8850 literal = false;
8851
8852 if (date) {
8853 for (iFormat = 0; iFormat < format.length; iFormat++) {
8854 if (literal) {
8855 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
8856 literal = false;
8857 } else {
8858 output += format.charAt(iFormat);
8859 }
8860 } else {
8861 switch (format.charAt(iFormat)) {
8862 case "d":
8863 output += formatNumber("d", date.getDate(), 2);
8864 break;
8865 case "D":
8866 output += formatName("D", date.getDay(), dayNamesShort, dayNames);
8867 break;
8868 case "o":
8869 output += formatNumber("o",
8870 Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
8871 break;
8872 case "m":
8873 output += formatNumber("m", date.getMonth() + 1, 2);
8874 break;
8875 case "M":
8876 output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
8877 break;
8878 case "y":
8879 output += (lookAhead("y") ? date.getFullYear() :
8880 (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
8881 break;
8882 case "@":
8883 output += date.getTime();
8884 break;
8885 case "!":
8886 output += date.getTime() * 10000 + this._ticksTo1970;
8887 break;
8888 case "'":
8889 if (lookAhead("'")) {
8890 output += "'";
8891 } else {
8892 literal = true;
8893 }
8894 break;
8895 default:
8896 output += format.charAt(iFormat);
8897 }
8898 }
8899 }
8900 }
8901 return output;
8902 },
8903
8904 /* Extract all possible characters from the date format. */
8905 _possibleChars: function (format) {
8906 var iFormat,
8907 chars = "",
8908 literal = false,
8909 // Check whether a format character is doubled
8910 lookAhead = function(match) {
8911 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
8912 if (matches) {
8913 iFormat++;
8914 }
8915 return matches;
8916 };
8917
8918 for (iFormat = 0; iFormat < format.length; iFormat++) {
8919 if (literal) {
8920 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
8921 literal = false;
8922 } else {
8923 chars += format.charAt(iFormat);
8924 }
8925 } else {
8926 switch (format.charAt(iFormat)) {
8927 case "d": case "m": case "y": case "@":
8928 chars += "0123456789";
8929 break;
8930 case "D": case "M":
8931 return null; // Accept anything
8932 case "'":
8933 if (lookAhead("'")) {
8934 chars += "'";
8935 } else {
8936 literal = true;
8937 }
8938 break;
8939 default:
8940 chars += format.charAt(iFormat);
8941 }
8942 }
8943 }
8944 return chars;
8945 },
8946
8947 /* Get a setting value, defaulting if necessary. */
8948 _get: function(inst, name) {
8949 return inst.settings[name] !== undefined ?
8950 inst.settings[name] : this._defaults[name];
8951 },
8952
8953 /* Parse existing date and initialise date picker. */
8954 _setDateFromField: function(inst, noDefault) {
8955 if (inst.input.val() === inst.lastVal) {
8956 return;
8957 }
8958
8959 var dateFormat = this._get(inst, "dateFormat"),
8960 dates = inst.lastVal = inst.input ? inst.input.val() : null,
8961 defaultDate = this._getDefaultDate(inst),
8962 date = defaultDate,
8963 settings = this._getFormatConfig(inst);
8964
8965 try {
8966 date = this.parseDate(dateFormat, dates, settings) || defaultDate;
8967 } catch (event) {
8968 dates = (noDefault ? "" : dates);
8969 }
8970 inst.selectedDay = date.getDate();
8971 inst.drawMonth = inst.selectedMonth = date.getMonth();
8972 inst.drawYear = inst.selectedYear = date.getFullYear();
8973 inst.currentDay = (dates ? date.getDate() : 0);
8974 inst.currentMonth = (dates ? date.getMonth() : 0);
8975 inst.currentYear = (dates ? date.getFullYear() : 0);
8976 this._adjustInstDate(inst);
8977 },
8978
8979 /* Retrieve the default date shown on opening. */
8980 _getDefaultDate: function(inst) {
8981 return this._restrictMinMax(inst,
8982 this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
8983 },
8984
8985 /* A date may be specified as an exact value or a relative one. */
8986 _determineDate: function(inst, date, defaultDate) {
8987 var offsetNumeric = function(offset) {
8988 var date = new Date();
8989 date.setDate(date.getDate() + offset);
8990 return date;
8991 },
8992 offsetString = function(offset) {
8993 try {
8994 return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
8995 offset, $.datepicker._getFormatConfig(inst));
8996 }
8997 catch (e) {
8998 // Ignore
8999 }
9000
9001 var date = (offset.toLowerCase().match(/^c/) ?
9002 $.datepicker._getDate(inst) : null) || new Date(),
9003 year = date.getFullYear(),
9004 month = date.getMonth(),
9005 day = date.getDate(),
9006 pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
9007 matches = pattern.exec(offset);
9008
9009 while (matches) {
9010 switch (matches[2] || "d") {
9011 case "d" : case "D" :
9012 day += parseInt(matches[1],10); break;
9013 case "w" : case "W" :
9014 day += parseInt(matches[1],10) * 7; break;
9015 case "m" : case "M" :
9016 month += parseInt(matches[1],10);
9017 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
9018 break;
9019 case "y": case "Y" :
9020 year += parseInt(matches[1],10);
9021 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
9022 break;
9023 }
9024 matches = pattern.exec(offset);
9025 }
9026 return new Date(year, month, day);
9027 },
9028 newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
9029 (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
9030
9031 newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
9032 if (newDate) {
9033 newDate.setHours(0);
9034 newDate.setMinutes(0);
9035 newDate.setSeconds(0);
9036 newDate.setMilliseconds(0);
9037 }
9038 return this._daylightSavingAdjust(newDate);
9039 },
9040
9041 /* Handle switch to/from daylight saving.
9042 * Hours may be non-zero on daylight saving cut-over:
9043 * > 12 when midnight changeover, but then cannot generate
9044 * midnight datetime, so jump to 1AM, otherwise reset.
9045 * @param date (Date) the date to check
9046 * @return (Date) the corrected date
9047 */
9048 _daylightSavingAdjust: function(date) {
9049 if (!date) {
9050 return null;
9051 }
9052 date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
9053 return date;
9054 },
9055
9056 /* Set the date(s) directly. */
9057 _setDate: function(inst, date, noChange) {
9058 var clear = !date,
9059 origMonth = inst.selectedMonth,
9060 origYear = inst.selectedYear,
9061 newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
9062
9063 inst.selectedDay = inst.currentDay = newDate.getDate();
9064 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
9065 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
9066 if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
9067 this._notifyChange(inst);
9068 }
9069 this._adjustInstDate(inst);
9070 if (inst.input) {
9071 inst.input.val(clear ? "" : this._formatDate(inst));
9072 }
9073 },
9074
9075 /* Retrieve the date(s) directly. */
9076 _getDate: function(inst) {
9077 var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
9078 this._daylightSavingAdjust(new Date(
9079 inst.currentYear, inst.currentMonth, inst.currentDay)));
9080 return startDate;
9081 },
9082
9083 /* Attach the onxxx handlers. These are declared statically so
9084 * they work with static code transformers like Caja.
9085 */
9086 _attachHandlers: function(inst) {
9087 var stepMonths = this._get(inst, "stepMonths"),
9088 id = "#" + inst.id.replace( /\\\\/g, "\\" );
9089 inst.dpDiv.find("[data-handler]").map(function () {
9090 var handler = {
9091 prev: function () {
9092 window["DP_jQuery_" + dpuuid].datepicker._adjustDate(id, -stepMonths, "M");
9093 },
9094 next: function () {
9095 window["DP_jQuery_" + dpuuid].datepicker._adjustDate(id, +stepMonths, "M");
9096 },
9097 hide: function () {
9098 window["DP_jQuery_" + dpuuid].datepicker._hideDatepicker();
9099 },
9100 today: function () {
9101 window["DP_jQuery_" + dpuuid].datepicker._gotoToday(id);
9102 },
9103 selectDay: function () {
9104 window["DP_jQuery_" + dpuuid].datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
9105 return false;
9106 },
9107 selectMonth: function () {
9108 window["DP_jQuery_" + dpuuid].datepicker._selectMonthYear(id, this, "M");
9109 return false;
9110 },
9111 selectYear: function () {
9112 window["DP_jQuery_" + dpuuid].datepicker._selectMonthYear(id, this, "Y");
9113 return false;
9114 }
9115 };
9116 $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
9117 });
9118 },
9119
9120 /* Generate the HTML for the current state of the date picker. */
9121 _generateHTML: function(inst) {
9122 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
9123 controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
9124 monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
9125 selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
9126 cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
9127 printDate, dRow, tbody, daySettings, otherMonth, unselectable,
9128 tempDate = new Date(),
9129 today = this._daylightSavingAdjust(
9130 new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
9131 isRTL = this._get(inst, "isRTL"),
9132 showButtonPanel = this._get(inst, "showButtonPanel"),
9133 hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
9134 navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
9135 numMonths = this._getNumberOfMonths(inst),
9136 showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
9137 stepMonths = this._get(inst, "stepMonths"),
9138 isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
9139 currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
9140 new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
9141 minDate = this._getMinMaxDate(inst, "min"),
9142 maxDate = this._getMinMaxDate(inst, "max"),
9143 drawMonth = inst.drawMonth - showCurrentAtPos,
9144 drawYear = inst.drawYear;
9145
9146 if (drawMonth < 0) {
9147 drawMonth += 12;
9148 drawYear--;
9149 }
9150 if (maxDate) {
9151 maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
9152 maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
9153 maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
9154 while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
9155 drawMonth--;
9156 if (drawMonth < 0) {
9157 drawMonth = 11;
9158 drawYear--;
9159 }
9160 }
9161 }
9162 inst.drawMonth = drawMonth;
9163 inst.drawYear = drawYear;
9164
9165 prevText = this._get(inst, "prevText");
9166 prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
9167 this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
9168 this._getFormatConfig(inst)));
9169
9170 prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
9171 "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
9172 " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
9173 (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>"));
9174
9175 nextText = this._get(inst, "nextText");
9176 nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
9177 this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
9178 this._getFormatConfig(inst)));
9179
9180 next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
9181 "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
9182 " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
9183 (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>"));
9184
9185 currentText = this._get(inst, "currentText");
9186 gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
9187 currentText = (!navigationAsDateFormat ? currentText :
9188 this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
9189
9190 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'>" +
9191 this._get(inst, "closeText") + "</button>" : "");
9192
9193 buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
9194 (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'" +
9195 ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";
9196
9197 firstDay = parseInt(this._get(inst, "firstDay"),10);
9198 firstDay = (isNaN(firstDay) ? 0 : firstDay);
9199
9200 showWeek = this._get(inst, "showWeek");
9201 dayNames = this._get(inst, "dayNames");
9202 dayNamesMin = this._get(inst, "dayNamesMin");
9203 monthNames = this._get(inst, "monthNames");
9204 monthNamesShort = this._get(inst, "monthNamesShort");
9205 beforeShowDay = this._get(inst, "beforeShowDay");
9206 showOtherMonths = this._get(inst, "showOtherMonths");
9207 selectOtherMonths = this._get(inst, "selectOtherMonths");
9208 defaultDate = this._getDefaultDate(inst);
9209 html = "";
9210 dow;
9211 for (row = 0; row < numMonths[0]; row++) {
9212 group = "";
9213 this.maxRows = 4;
9214 for (col = 0; col < numMonths[1]; col++) {
9215 selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
9216 cornerClass = " ui-corner-all";
9217 calender = "";
9218 if (isMultiMonth) {
9219 calender += "<div class='ui-datepicker-group";
9220 if (numMonths[1] > 1) {
9221 switch (col) {
9222 case 0: calender += " ui-datepicker-group-first";
9223 cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
9224 case numMonths[1]-1: calender += " ui-datepicker-group-last";
9225 cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
9226 default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
9227 }
9228 }
9229 calender += "'>";
9230 }
9231 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
9232 (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
9233 (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
9234 this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
9235 row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
9236 "</div><table class='ui-datepicker-calendar'><thead>" +
9237 "<tr>";
9238 thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
9239 for (dow = 0; dow < 7; dow++) { // days of the week
9240 day = (dow + firstDay) % 7;
9241 thead += "<th" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
9242 "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
9243 }
9244 calender += thead + "</tr></thead><tbody>";
9245 daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
9246 if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
9247 inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
9248 }
9249 leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
9250 curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
9251 numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
9252 this.maxRows = numRows;
9253 printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
9254 for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
9255 calender += "<tr>";
9256 tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
9257 this._get(inst, "calculateWeek")(printDate) + "</td>");
9258 for (dow = 0; dow < 7; dow++) { // create date picker days
9259 daySettings = (beforeShowDay ?
9260 beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
9261 otherMonth = (printDate.getMonth() !== drawMonth);
9262 unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
9263 (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
9264 tbody += "<td class='" +
9265 ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
9266 (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
9267 ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
9268 (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
9269 // or defaultDate is current printedDate and defaultDate is selectedDate
9270 " " + this._dayOverClass : "") + // highlight selected day
9271 (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days
9272 (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
9273 (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
9274 (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
9275 ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "&#39;") + "'" : "") + // cell title
9276 (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
9277 (otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
9278 (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
9279 (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
9280 (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
9281 (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
9282 "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
9283 printDate.setDate(printDate.getDate() + 1);
9284 printDate = this._daylightSavingAdjust(printDate);
9285 }
9286 calender += tbody + "</tr>";
9287 }
9288 drawMonth++;
9289 if (drawMonth > 11) {
9290 drawMonth = 0;
9291 drawYear++;
9292 }
9293 calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
9294 ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
9295 group += calender;
9296 }
9297 html += group;
9298 }
9299 html += buttonPanel;
9300 inst._keyEvent = false;
9301 return html;
9302 },
9303
9304 /* Generate the month and year header. */
9305 _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
9306 secondary, monthNames, monthNamesShort) {
9307
9308 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
9309 changeMonth = this._get(inst, "changeMonth"),
9310 changeYear = this._get(inst, "changeYear"),
9311 showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
9312 html = "<div class='ui-datepicker-title'>",
9313 monthHtml = "";
9314
9315 // month selection
9316 if (secondary || !changeMonth) {
9317 monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
9318 } else {
9319 inMinYear = (minDate && minDate.getFullYear() === drawYear);
9320 inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
9321 monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
9322 for ( month = 0; month < 12; month++) {
9323 if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
9324 monthHtml += "<option value='" + month + "'" +
9325 (month === drawMonth ? " selected='selected'" : "") +
9326 ">" + monthNamesShort[month] + "</option>";
9327 }
9328 }
9329 monthHtml += "</select>";
9330 }
9331
9332 if (!showMonthAfterYear) {
9333 html += monthHtml + (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "");
9334 }
9335
9336 // year selection
9337 if ( !inst.yearshtml ) {
9338 inst.yearshtml = "";
9339 if (secondary || !changeYear) {
9340 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
9341 } else {
9342 // determine range of years to display
9343 years = this._get(inst, "yearRange").split(":");
9344 thisYear = new Date().getFullYear();
9345 determineYear = function(value) {
9346 var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
9347 (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
9348 parseInt(value, 10)));
9349 return (isNaN(year) ? thisYear : year);
9350 };
9351 year = determineYear(years[0]);
9352 endYear = Math.max(year, determineYear(years[1] || ""));
9353 year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
9354 endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
9355 inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
9356 for (; year <= endYear; year++) {
9357 inst.yearshtml += "<option value='" + year + "'" +
9358 (year === drawYear ? " selected='selected'" : "") +
9359 ">" + year + "</option>";
9360 }
9361 inst.yearshtml += "</select>";
9362
9363 html += inst.yearshtml;
9364 inst.yearshtml = null;
9365 }
9366 }
9367
9368 html += this._get(inst, "yearSuffix");
9369 if (showMonthAfterYear) {
9370 html += (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "") + monthHtml;
9371 }
9372 html += "</div>"; // Close datepicker_header
9373 return html;
9374 },
9375
9376 /* Adjust one of the date sub-fields. */
9377 _adjustInstDate: function(inst, offset, period) {
9378 var year = inst.drawYear + (period === "Y" ? offset : 0),
9379 month = inst.drawMonth + (period === "M" ? offset : 0),
9380 day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
9381 date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));
9382
9383 inst.selectedDay = date.getDate();
9384 inst.drawMonth = inst.selectedMonth = date.getMonth();
9385 inst.drawYear = inst.selectedYear = date.getFullYear();
9386 if (period === "M" || period === "Y") {
9387 this._notifyChange(inst);
9388 }
9389 },
9390
9391 /* Ensure a date is within any min/max bounds. */
9392 _restrictMinMax: function(inst, date) {
9393 var minDate = this._getMinMaxDate(inst, "min"),
9394 maxDate = this._getMinMaxDate(inst, "max"),
9395 newDate = (minDate && date < minDate ? minDate : date);
9396 return (maxDate && newDate > maxDate ? maxDate : newDate);
9397 },
9398
9399 /* Notify change of month/year. */
9400 _notifyChange: function(inst) {
9401 var onChange = this._get(inst, "onChangeMonthYear");
9402 if (onChange) {
9403 onChange.apply((inst.input ? inst.input[0] : null),
9404 [inst.selectedYear, inst.selectedMonth + 1, inst]);
9405 }
9406 },
9407
9408 /* Determine the number of months to show. */
9409 _getNumberOfMonths: function(inst) {
9410 var numMonths = this._get(inst, "numberOfMonths");
9411 return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
9412 },
9413
9414 /* Determine the current maximum date - ensure no time components are set. */
9415 _getMinMaxDate: function(inst, minMax) {
9416 return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
9417 },
9418
9419 /* Find the number of days in a given month. */
9420 _getDaysInMonth: function(year, month) {
9421 return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
9422 },
9423
9424 /* Find the day of the week of the first of a month. */
9425 _getFirstDayOfMonth: function(year, month) {
9426 return new Date(year, month, 1).getDay();
9427 },
9428
9429 /* Determines if we should allow a "next/prev" month display change. */
9430 _canAdjustMonth: function(inst, offset, curYear, curMonth) {
9431 var numMonths = this._getNumberOfMonths(inst),
9432 date = this._daylightSavingAdjust(new Date(curYear,
9433 curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
9434
9435 if (offset < 0) {
9436 date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
9437 }
9438 return this._isInRange(inst, date);
9439 },
9440
9441 /* Is the given date in the accepted range? */
9442 _isInRange: function(inst, date) {
9443 var yearSplit, currentYear,
9444 minDate = this._getMinMaxDate(inst, "min"),
9445 maxDate = this._getMinMaxDate(inst, "max"),
9446 minYear = null,
9447 maxYear = null,
9448 years = this._get(inst, "yearRange");
9449 if (years){
9450 yearSplit = years.split(":");
9451 currentYear = new Date().getFullYear();
9452 minYear = parseInt(yearSplit[0], 10);
9453 maxYear = parseInt(yearSplit[1], 10);
9454 if ( yearSplit[0].match(/[+\-].*/) ) {
9455 minYear += currentYear;
9456 }
9457 if ( yearSplit[1].match(/[+\-].*/) ) {
9458 maxYear += currentYear;
9459 }
9460 }
9461
9462 return ((!minDate || date.getTime() >= minDate.getTime()) &&
9463 (!maxDate || date.getTime() <= maxDate.getTime()) &&
9464 (!minYear || date.getFullYear() >= minYear) &&
9465 (!maxYear || date.getFullYear() <= maxYear));
9466 },
9467
9468 /* Provide the configuration settings for formatting/parsing. */
9469 _getFormatConfig: function(inst) {
9470 var shortYearCutoff = this._get(inst, "shortYearCutoff");
9471 shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
9472 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
9473 return {shortYearCutoff: shortYearCutoff,
9474 dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
9475 monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
9476 },
9477
9478 /* Format the given date for display. */
9479 _formatDate: function(inst, day, month, year) {
9480 if (!day) {
9481 inst.currentDay = inst.selectedDay;
9482 inst.currentMonth = inst.selectedMonth;
9483 inst.currentYear = inst.selectedYear;
9484 }
9485 var date = (day ? (typeof day === "object" ? day :
9486 this._daylightSavingAdjust(new Date(year, month, day))) :
9487 this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
9488 return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
9489 }
9490});
9491
9492/*
9493 * Bind hover events for datepicker elements.
9494 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
9495 * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
9496 */
9497function bindHover(dpDiv) {
9498 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
9499 return dpDiv.delegate(selector, "mouseout", function() {
9500 $(this).removeClass("ui-state-hover");
9501 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
9502 $(this).removeClass("ui-datepicker-prev-hover");
9503 }
9504 if (this.className.indexOf("ui-datepicker-next") !== -1) {
9505 $(this).removeClass("ui-datepicker-next-hover");
9506 }
9507 })
9508 .delegate(selector, "mouseover", function(){
9509 if (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) {
9510 $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
9511 $(this).addClass("ui-state-hover");
9512 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
9513 $(this).addClass("ui-datepicker-prev-hover");
9514 }
9515 if (this.className.indexOf("ui-datepicker-next") !== -1) {
9516 $(this).addClass("ui-datepicker-next-hover");
9517 }
9518 }
9519 });
9520}
9521
9522/* jQuery extend now ignores nulls! */
9523function extendRemove(target, props) {
9524 $.extend(target, props);
9525 for (var name in props) {
9526 if (props[name] == null) {
9527 target[name] = props[name];
9528 }
9529 }
9530 return target;
9531}
9532
9533/* Invoke the datepicker functionality.
9534 @param options string - a command, optionally followed by additional parameters or
9535 Object - settings for attaching new datepicker functionality
9536 @return jQuery object */
9537$.fn.datepicker = function(options){
9538
9539 /* Verify an empty collection wasn't passed - Fixes #6976 */
9540 if ( !this.length ) {
9541 return this;
9542 }
9543
9544 /* Initialise the date picker. */
9545 if (!$.datepicker.initialized) {
9546 $(document).mousedown($.datepicker._checkExternalClick);
9547 $.datepicker.initialized = true;
9548 }
9549
9550 /* Append datepicker main container to body if not exist. */
9551 if ($("#"+$.datepicker._mainDivId).length === 0) {
9552 $("body").append($.datepicker.dpDiv);
9553 }
9554
9555 var otherArgs = Array.prototype.slice.call(arguments, 1);
9556 if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
9557 return $.datepicker["_" + options + "Datepicker"].
9558 apply($.datepicker, [this[0]].concat(otherArgs));
9559 }
9560 if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
9561 return $.datepicker["_" + options + "Datepicker"].
9562 apply($.datepicker, [this[0]].concat(otherArgs));
9563 }
9564 return this.each(function() {
9565 typeof options === "string" ?
9566 $.datepicker["_" + options + "Datepicker"].
9567 apply($.datepicker, [this].concat(otherArgs)) :
9568 $.datepicker._attachDatepicker(this, options);
9569 });
9570};
9571
9572$.datepicker = new Datepicker(); // singleton instance
9573$.datepicker.initialized = false;
9574$.datepicker.uuid = new Date().getTime();
9575$.datepicker.version = "1.10.1";
9576
9577// Workaround for #4055
9578// Add another global to avoid noConflict issues with inline event handlers
9579window["DP_jQuery_" + dpuuid] = $;
9580
9581})(jQuery);
9582
9583(function( $, undefined ) {
9584
9585var sizeRelatedOptions = {
9586 buttons: true,
9587 height: true,
9588 maxHeight: true,
9589 maxWidth: true,
9590 minHeight: true,
9591 minWidth: true,
9592 width: true
9593 },
9594 resizableRelatedOptions = {
9595 maxHeight: true,
9596 maxWidth: true,
9597 minHeight: true,
9598 minWidth: true
9599 };
9600
9601$.widget( "ui.dialog", {
9602 version: "1.10.1",
9603 options: {
9604 appendTo: "body",
9605 autoOpen: true,
9606 buttons: [],
9607 closeOnEscape: true,
9608 closeText: "close",
9609 dialogClass: "",
9610 draggable: true,
9611 hide: null,
9612 height: "auto",
9613 maxHeight: null,
9614 maxWidth: null,
9615 minHeight: 150,
9616 minWidth: 150,
9617 modal: false,
9618 position: {
9619 my: "center",
9620 at: "center",
9621 of: window,
9622 collision: "fit",
9623 // Ensure the titlebar is always visible
9624 using: function( pos ) {
9625 var topOffset = $( this ).css( pos ).offset().top;
9626 if ( topOffset < 0 ) {
9627 $( this ).css( "top", pos.top - topOffset );
9628 }
9629 }
9630 },
9631 resizable: true,
9632 show: null,
9633 title: null,
9634 width: 300,
9635
9636 // callbacks
9637 beforeClose: null,
9638 close: null,
9639 drag: null,
9640 dragStart: null,
9641 dragStop: null,
9642 focus: null,
9643 open: null,
9644 resize: null,
9645 resizeStart: null,
9646 resizeStop: null
9647 },
9648
9649 _create: function() {
9650 this.originalCss = {
9651 display: this.element[0].style.display,
9652 width: this.element[0].style.width,
9653 minHeight: this.element[0].style.minHeight,
9654 maxHeight: this.element[0].style.maxHeight,
9655 height: this.element[0].style.height
9656 };
9657 this.originalPosition = {
9658 parent: this.element.parent(),
9659 index: this.element.parent().children().index( this.element )
9660 };
9661 this.originalTitle = this.element.attr("title");
9662 this.options.title = this.options.title || this.originalTitle;
9663
9664 this._createWrapper();
9665
9666 this.element
9667 .show()
9668 .removeAttr("title")
9669 .addClass("ui-dialog-content ui-widget-content")
9670 .appendTo( this.uiDialog );
9671
9672 this._createTitlebar();
9673 this._createButtonPane();
9674
9675 if ( this.options.draggable && $.fn.draggable ) {
9676 this._makeDraggable();
9677 }
9678 if ( this.options.resizable && $.fn.resizable ) {
9679 this._makeResizable();
9680 }
9681
9682 this._isOpen = false;
9683 },
9684
9685 _init: function() {
9686 if ( this.options.autoOpen ) {
9687 this.open();
9688 }
9689 },
9690
9691 _appendTo: function() {
9692 var element = this.options.appendTo;
9693 if ( element && (element.jquery || element.nodeType) ) {
9694 return $( element );
9695 }
9696 return this.document.find( element || "body" ).eq( 0 );
9697 },
9698
9699 _destroy: function() {
9700 var next,
9701 originalPosition = this.originalPosition;
9702
9703 this._destroyOverlay();
9704
9705 this.element
9706 .removeUniqueId()
9707 .removeClass("ui-dialog-content ui-widget-content")
9708 .css( this.originalCss )
9709 // Without detaching first, the following becomes really slow
9710 .detach();
9711
9712 this.uiDialog.stop( true, true ).remove();
9713
9714 if ( this.originalTitle ) {
9715 this.element.attr( "title", this.originalTitle );
9716 }
9717
9718 next = originalPosition.parent.children().eq( originalPosition.index );
9719 // Don't try to place the dialog next to itself (#8613)
9720 if ( next.length && next[0] !== this.element[0] ) {
9721 next.before( this.element );
9722 } else {
9723 originalPosition.parent.append( this.element );
9724 }
9725 },
9726
9727 widget: function() {
9728 return this.uiDialog;
9729 },
9730
9731 disable: $.noop,
9732 enable: $.noop,
9733
9734 close: function( event ) {
9735 var that = this;
9736
9737 if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
9738 return;
9739 }
9740
9741 this._isOpen = false;
9742 this._destroyOverlay();
9743
9744 if ( !this.opener.filter(":focusable").focus().length ) {
9745 // Hiding a focused element doesn't trigger blur in WebKit
9746 // so in case we have nothing to focus on, explicitly blur the active element
9747 // https://bugs.webkit.org/show_bug.cgi?id=47182
9748 $( this.document[0].activeElement ).blur();
9749 }
9750
9751 this._hide( this.uiDialog, this.options.hide, function() {
9752 that._trigger( "close", event );
9753 });
9754 },
9755
9756 isOpen: function() {
9757 return this._isOpen;
9758 },
9759
9760 moveToTop: function() {
9761 this._moveToTop();
9762 },
9763
9764 _moveToTop: function( event, silent ) {
9765 var moved = !!this.uiDialog.nextAll(":visible").insertBefore( this.uiDialog ).length;
9766 if ( moved && !silent ) {
9767 this._trigger( "focus", event );
9768 }
9769 return moved;
9770 },
9771
9772 open: function() {
9773 var that = this;
9774 if ( this._isOpen ) {
9775 if ( this._moveToTop() ) {
9776 this._focusTabbable();
9777 }
9778 return;
9779 }
9780
9781 this._isOpen = true;
9782 this.opener = $( this.document[0].activeElement );
9783
9784 this._size();
9785 this._position();
9786 this._createOverlay();
9787 this._moveToTop( null, true );
9788 this._show( this.uiDialog, this.options.show, function() {
9789 that._focusTabbable();
9790 that._trigger("focus");
9791 });
9792
9793 this._trigger("open");
9794 },
9795
9796 _focusTabbable: function() {
9797 // Set focus to the first match:
9798 // 1. First element inside the dialog matching [autofocus]
9799 // 2. Tabbable element inside the content element
9800 // 3. Tabbable element inside the buttonpane
9801 // 4. The close button
9802 // 5. The dialog itself
9803 var hasFocus = this.element.find("[autofocus]");
9804 if ( !hasFocus.length ) {
9805 hasFocus = this.element.find(":tabbable");
9806 }
9807 if ( !hasFocus.length ) {
9808 hasFocus = this.uiDialogButtonPane.find(":tabbable");
9809 }
9810 if ( !hasFocus.length ) {
9811 hasFocus = this.uiDialogTitlebarClose.filter(":tabbable");
9812 }
9813 if ( !hasFocus.length ) {
9814 hasFocus = this.uiDialog;
9815 }
9816 hasFocus.eq( 0 ).focus();
9817 },
9818
9819 _keepFocus: function( event ) {
9820 function checkFocus() {
9821 var activeElement = this.document[0].activeElement,
9822 isActive = this.uiDialog[0] === activeElement ||
9823 $.contains( this.uiDialog[0], activeElement );
9824 if ( !isActive ) {
9825 this._focusTabbable();
9826 }
9827 }
9828 event.preventDefault();
9829 checkFocus.call( this );
9830 // support: IE
9831 // IE <= 8 doesn't prevent moving focus even with event.preventDefault()
9832 // so we check again later
9833 this._delay( checkFocus );
9834 },
9835
9836 _createWrapper: function() {
9837 this.uiDialog = $("<div>")
9838 .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " +
9839 this.options.dialogClass )
9840 .hide()
9841 .attr({
9842 // Setting tabIndex makes the div focusable
9843 tabIndex: -1,
9844 role: "dialog"
9845 })
9846 .appendTo( this._appendTo() );
9847
9848 this._on( this.uiDialog, {
9849 keydown: function( event ) {
9850 if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
9851 event.keyCode === $.ui.keyCode.ESCAPE ) {
9852 event.preventDefault();
9853 this.close( event );
9854 return;
9855 }
9856
9857 // prevent tabbing out of dialogs
9858 if ( event.keyCode !== $.ui.keyCode.TAB ) {
9859 return;
9860 }
9861 var tabbables = this.uiDialog.find(":tabbable"),
9862 first = tabbables.filter(":first"),
9863 last = tabbables.filter(":last");
9864
9865 if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) {
9866 first.focus( 1 );
9867 event.preventDefault();
9868 } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) {
9869 last.focus( 1 );
9870 event.preventDefault();
9871 }
9872 },
9873 mousedown: function( event ) {
9874 if ( this._moveToTop( event ) ) {
9875 this._focusTabbable();
9876 }
9877 }
9878 });
9879
9880 // We assume that any existing aria-describedby attribute means
9881 // that the dialog content is marked up properly
9882 // otherwise we brute force the content as the description
9883 if ( !this.element.find("[aria-describedby]").length ) {
9884 this.uiDialog.attr({
9885 "aria-describedby": this.element.uniqueId().attr("id")
9886 });
9887 }
9888 },
9889
9890 _createTitlebar: function() {
9891 var uiDialogTitle;
9892
9893 this.uiDialogTitlebar = $("<div>")
9894 .addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix")
9895 .prependTo( this.uiDialog );
9896 this._on( this.uiDialogTitlebar, {
9897 mousedown: function( event ) {
9898 // Don't prevent click on close button (#8838)
9899 // Focusing a dialog that is partially scrolled out of view
9900 // causes the browser to scroll it into view, preventing the click event
9901 if ( !$( event.target ).closest(".ui-dialog-titlebar-close") ) {
9902 // Dialog isn't getting focus when dragging (#8063)
9903 this.uiDialog.focus();
9904 }
9905 }
9906 });
9907
9908 this.uiDialogTitlebarClose = $("<button></button>")
9909 .button({
9910 label: this.options.closeText,
9911 icons: {
9912 primary: "ui-icon-closethick"
9913 },
9914 text: false
9915 })
9916 .addClass("ui-dialog-titlebar-close")
9917 .appendTo( this.uiDialogTitlebar );
9918 this._on( this.uiDialogTitlebarClose, {
9919 click: function( event ) {
9920 event.preventDefault();
9921 this.close( event );
9922 }
9923 });
9924
9925 uiDialogTitle = $("<span>")
9926 .uniqueId()
9927 .addClass("ui-dialog-title")
9928 .prependTo( this.uiDialogTitlebar );
9929 this._title( uiDialogTitle );
9930
9931 this.uiDialog.attr({
9932 "aria-labelledby": uiDialogTitle.attr("id")
9933 });
9934 },
9935
9936 _title: function( title ) {
9937 if ( !this.options.title ) {
9938 title.html("&#160;");
9939 }
9940 title.text( this.options.title );
9941 },
9942
9943 _createButtonPane: function() {
9944 this.uiDialogButtonPane = $("<div>")
9945 .addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix");
9946
9947 this.uiButtonSet = $("<div>")
9948 .addClass("ui-dialog-buttonset")
9949 .appendTo( this.uiDialogButtonPane );
9950
9951 this._createButtons();
9952 },
9953
9954 _createButtons: function() {
9955 var that = this,
9956 buttons = this.options.buttons;
9957
9958 // if we already have a button pane, remove it
9959 this.uiDialogButtonPane.remove();
9960 this.uiButtonSet.empty();
9961
9962 if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) {
9963 this.uiDialog.removeClass("ui-dialog-buttons");
9964 return;
9965 }
9966
9967 $.each( buttons, function( name, props ) {
9968 var click, buttonOptions;
9969 props = $.isFunction( props ) ?
9970 { click: props, text: name } :
9971 props;
9972 // Default to a non-submitting button
9973 props = $.extend( { type: "button" }, props );
9974 // Change the context for the click callback to be the main element
9975 click = props.click;
9976 props.click = function() {
9977 click.apply( that.element[0], arguments );
9978 };
9979 buttonOptions = {
9980 icons: props.icons,
9981 text: props.showText
9982 };
9983 delete props.icons;
9984 delete props.showText;
9985 $( "<button></button>", props )
9986 .button( buttonOptions )
9987 .appendTo( that.uiButtonSet );
9988 });
9989 this.uiDialog.addClass("ui-dialog-buttons");
9990 this.uiDialogButtonPane.appendTo( this.uiDialog );
9991 },
9992
9993 _makeDraggable: function() {
9994 var that = this,
9995 options = this.options;
9996
9997 function filteredUi( ui ) {
9998 return {
9999 position: ui.position,
10000 offset: ui.offset
10001 };
10002 }
10003
10004 this.uiDialog.draggable({
10005 cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
10006 handle: ".ui-dialog-titlebar",
10007 containment: "document",
10008 start: function( event, ui ) {
10009 $( this ).addClass("ui-dialog-dragging");
10010 that._blockFrames();
10011 that._trigger( "dragStart", event, filteredUi( ui ) );
10012 },
10013 drag: function( event, ui ) {
10014 that._trigger( "drag", event, filteredUi( ui ) );
10015 },
10016 stop: function( event, ui ) {
10017 options.position = [
10018 ui.position.left - that.document.scrollLeft(),
10019 ui.position.top - that.document.scrollTop()
10020 ];
10021 $( this ).removeClass("ui-dialog-dragging");
10022 that._unblockFrames();
10023 that._trigger( "dragStop", event, filteredUi( ui ) );
10024 }
10025 });
10026 },
10027
10028 _makeResizable: function() {
10029 var that = this,
10030 options = this.options,
10031 handles = options.resizable,
10032 // .ui-resizable has position: relative defined in the stylesheet
10033 // but dialogs have to use absolute or fixed positioning
10034 position = this.uiDialog.css("position"),
10035 resizeHandles = typeof handles === "string" ?
10036 handles :
10037 "n,e,s,w,se,sw,ne,nw";
10038
10039 function filteredUi( ui ) {
10040 return {
10041 originalPosition: ui.originalPosition,
10042 originalSize: ui.originalSize,
10043 position: ui.position,
10044 size: ui.size
10045 };
10046 }
10047
10048 this.uiDialog.resizable({
10049 cancel: ".ui-dialog-content",
10050 containment: "document",
10051 alsoResize: this.element,
10052 maxWidth: options.maxWidth,
10053 maxHeight: options.maxHeight,
10054 minWidth: options.minWidth,
10055 minHeight: this._minHeight(),
10056 handles: resizeHandles,
10057 start: function( event, ui ) {
10058 $( this ).addClass("ui-dialog-resizing");
10059 that._blockFrames();
10060 that._trigger( "resizeStart", event, filteredUi( ui ) );
10061 },
10062 resize: function( event, ui ) {
10063 that._trigger( "resize", event, filteredUi( ui ) );
10064 },
10065 stop: function( event, ui ) {
10066 options.height = $( this ).height();
10067 options.width = $( this ).width();
10068 $( this ).removeClass("ui-dialog-resizing");
10069 that._unblockFrames();
10070 that._trigger( "resizeStop", event, filteredUi( ui ) );
10071 }
10072 })
10073 .css( "position", position );
10074 },
10075
10076 _minHeight: function() {
10077 var options = this.options;
10078
10079 return options.height === "auto" ?
10080 options.minHeight :
10081 Math.min( options.minHeight, options.height );
10082 },
10083
10084 _position: function() {
10085 // Need to show the dialog to get the actual offset in the position plugin
10086 var isVisible = this.uiDialog.is(":visible");
10087 if ( !isVisible ) {
10088 this.uiDialog.show();
10089 }
10090 this.uiDialog.position( this.options.position );
10091 if ( !isVisible ) {
10092 this.uiDialog.hide();
10093 }
10094 },
10095
10096 _setOptions: function( options ) {
10097 var that = this,
10098 resize = false,
10099 resizableOptions = {};
10100
10101 $.each( options, function( key, value ) {
10102 that._setOption( key, value );
10103
10104 if ( key in sizeRelatedOptions ) {
10105 resize = true;
10106 }
10107 if ( key in resizableRelatedOptions ) {
10108 resizableOptions[ key ] = value;
10109 }
10110 });
10111
10112 if ( resize ) {
10113 this._size();
10114 this._position();
10115 }
10116 if ( this.uiDialog.is(":data(ui-resizable)") ) {
10117 this.uiDialog.resizable( "option", resizableOptions );
10118 }
10119 },
10120
10121 _setOption: function( key, value ) {
10122 /*jshint maxcomplexity:15*/
10123 var isDraggable, isResizable,
10124 uiDialog = this.uiDialog;
10125
10126 if ( key === "dialogClass" ) {
10127 uiDialog
10128 .removeClass( this.options.dialogClass )
10129 .addClass( value );
10130 }
10131
10132 if ( key === "disabled" ) {
10133 return;
10134 }
10135
10136 this._super( key, value );
10137
10138 if ( key === "appendTo" ) {
10139 this.uiDialog.appendTo( this._appendTo() );
10140 }
10141
10142 if ( key === "buttons" ) {
10143 this._createButtons();
10144 }
10145
10146 if ( key === "closeText" ) {
10147 this.uiDialogTitlebarClose.button({
10148 // Ensure that we always pass a string
10149 label: "" + value
10150 });
10151 }
10152
10153 if ( key === "draggable" ) {
10154 isDraggable = uiDialog.is(":data(ui-draggable)");
10155 if ( isDraggable && !value ) {
10156 uiDialog.draggable("destroy");
10157 }
10158
10159 if ( !isDraggable && value ) {
10160 this._makeDraggable();
10161 }
10162 }
10163
10164 if ( key === "position" ) {
10165 this._position();
10166 }
10167
10168 if ( key === "resizable" ) {
10169 // currently resizable, becoming non-resizable
10170 isResizable = uiDialog.is(":data(ui-resizable)");
10171 if ( isResizable && !value ) {
10172 uiDialog.resizable("destroy");
10173 }
10174
10175 // currently resizable, changing handles
10176 if ( isResizable && typeof value === "string" ) {
10177 uiDialog.resizable( "option", "handles", value );
10178 }
10179
10180 // currently non-resizable, becoming resizable
10181 if ( !isResizable && value !== false ) {
10182 this._makeResizable();
10183 }
10184 }
10185
10186 if ( key === "title" ) {
10187 this._title( this.uiDialogTitlebar.find(".ui-dialog-title") );
10188 }
10189 },
10190
10191 _size: function() {
10192 // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
10193 // divs will both have width and height set, so we need to reset them
10194 var nonContentHeight, minContentHeight, maxContentHeight,
10195 options = this.options;
10196
10197 // Reset content sizing
10198 this.element.show().css({
10199 width: "auto",
10200 minHeight: 0,
10201 maxHeight: "none",
10202 height: 0
10203 });
10204
10205 if ( options.minWidth > options.width ) {
10206 options.width = options.minWidth;
10207 }
10208
10209 // reset wrapper sizing
10210 // determine the height of all the non-content elements
10211 nonContentHeight = this.uiDialog.css({
10212 height: "auto",
10213 width: options.width
10214 })
10215 .outerHeight();
10216 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
10217 maxContentHeight = typeof options.maxHeight === "number" ?
10218 Math.max( 0, options.maxHeight - nonContentHeight ) :
10219 "none";
10220
10221 if ( options.height === "auto" ) {
10222 this.element.css({
10223 minHeight: minContentHeight,
10224 maxHeight: maxContentHeight,
10225 height: "auto"
10226 });
10227 } else {
10228 this.element.height( Math.max( 0, options.height - nonContentHeight ) );
10229 }
10230
10231 if (this.uiDialog.is(":data(ui-resizable)") ) {
10232 this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
10233 }
10234 },
10235
10236 _blockFrames: function() {
10237 this.iframeBlocks = this.document.find( "iframe" ).map(function() {
10238 var iframe = $( this );
10239
10240 return $( "<div>" )
10241 .css({
10242 position: "absolute",
10243 width: iframe.outerWidth(),
10244 height: iframe.outerHeight()
10245 })
10246 .appendTo( iframe.parent() )
10247 .offset( iframe.offset() )[0];
10248 });
10249 },
10250
10251 _unblockFrames: function() {
10252 if ( this.iframeBlocks ) {
10253 this.iframeBlocks.remove();
10254 delete this.iframeBlocks;
10255 }
10256 },
10257
10258 _createOverlay: function() {
10259 if ( !this.options.modal ) {
10260 return;
10261 }
10262
10263 if ( !$.ui.dialog.overlayInstances ) {
10264 // Prevent use of anchors and inputs.
10265 // We use a delay in case the overlay is created from an
10266 // event that we're going to be cancelling. (#2804)
10267 this._delay(function() {
10268 // Handle .dialog().dialog("close") (#4065)
10269 if ( $.ui.dialog.overlayInstances ) {
10270 this.document.bind( "focusin.dialog", function( event ) {
10271 if ( !$( event.target ).closest(".ui-dialog").length &&
10272 // TODO: Remove hack when datepicker implements
10273 // the .ui-front logic (#8989)
10274 !$( event.target ).closest(".ui-datepicker").length ) {
10275 event.preventDefault();
10276 $(".ui-dialog:visible:last .ui-dialog-content")
10277 .data("ui-dialog")._focusTabbable();
10278 }
10279 });
10280 }
10281 });
10282 }
10283
10284 this.overlay = $("<div>")
10285 .addClass("ui-widget-overlay ui-front")
10286 .appendTo( this._appendTo() );
10287 this._on( this.overlay, {
10288 mousedown: "_keepFocus"
10289 });
10290 $.ui.dialog.overlayInstances++;
10291 },
10292
10293 _destroyOverlay: function() {
10294 if ( !this.options.modal ) {
10295 return;
10296 }
10297
10298 if ( this.overlay ) {
10299 $.ui.dialog.overlayInstances--;
10300
10301 if ( !$.ui.dialog.overlayInstances ) {
10302 this.document.unbind( "focusin.dialog" );
10303 }
10304 this.overlay.remove();
10305 this.overlay = null;
10306 }
10307 }
10308});
10309
10310$.ui.dialog.overlayInstances = 0;
10311
10312// DEPRECATED
10313if ( $.uiBackCompat !== false ) {
10314 // position option with array notation
10315 // just override with old implementation
10316 $.widget( "ui.dialog", $.ui.dialog, {
10317 _position: function() {
10318 var position = this.options.position,
10319 myAt = [],
10320 offset = [ 0, 0 ],
10321 isVisible;
10322
10323 if ( position ) {
10324 if ( typeof position === "string" || (typeof position === "object" && "0" in position ) ) {
10325 myAt = position.split ? position.split(" ") : [ position[0], position[1] ];
10326 if ( myAt.length === 1 ) {
10327 myAt[1] = myAt[0];
10328 }
10329
10330 $.each( [ "left", "top" ], function( i, offsetPosition ) {
10331 if ( +myAt[ i ] === myAt[ i ] ) {
10332 offset[ i ] = myAt[ i ];
10333 myAt[ i ] = offsetPosition;
10334 }
10335 });
10336
10337 position = {
10338 my: myAt[0] + (offset[0] < 0 ? offset[0] : "+" + offset[0]) + " " +
10339 myAt[1] + (offset[1] < 0 ? offset[1] : "+" + offset[1]),
10340 at: myAt.join(" ")
10341 };
10342 }
10343
10344 position = $.extend( {}, $.ui.dialog.prototype.options.position, position );
10345 } else {
10346 position = $.ui.dialog.prototype.options.position;
10347 }
10348
10349 // need to show the dialog to get the actual offset in the position plugin
10350 isVisible = this.uiDialog.is(":visible");
10351 if ( !isVisible ) {
10352 this.uiDialog.show();
10353 }
10354 this.uiDialog.position( position );
10355 if ( !isVisible ) {
10356 this.uiDialog.hide();
10357 }
10358 }
10359 });
10360}
10361
10362}( jQuery ) );
10363
10364(function( $, undefined ) {
10365
10366var rvertical = /up|down|vertical/,
10367 rpositivemotion = /up|left|vertical|horizontal/;
10368
10369$.effects.effect.blind = function( o, done ) {
10370 // Create element
10371 var el = $( this ),
10372 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10373 mode = $.effects.setMode( el, o.mode || "hide" ),
10374 direction = o.direction || "up",
10375 vertical = rvertical.test( direction ),
10376 ref = vertical ? "height" : "width",
10377 ref2 = vertical ? "top" : "left",
10378 motion = rpositivemotion.test( direction ),
10379 animation = {},
10380 show = mode === "show",
10381 wrapper, distance, margin;
10382
10383 // if already wrapped, the wrapper's properties are my property. #6245
10384 if ( el.parent().is( ".ui-effects-wrapper" ) ) {
10385 $.effects.save( el.parent(), props );
10386 } else {
10387 $.effects.save( el, props );
10388 }
10389 el.show();
10390 wrapper = $.effects.createWrapper( el ).css({
10391 overflow: "hidden"
10392 });
10393
10394 distance = wrapper[ ref ]();
10395 margin = parseFloat( wrapper.css( ref2 ) ) || 0;
10396
10397 animation[ ref ] = show ? distance : 0;
10398 if ( !motion ) {
10399 el
10400 .css( vertical ? "bottom" : "right", 0 )
10401 .css( vertical ? "top" : "left", "auto" )
10402 .css({ position: "absolute" });
10403
10404 animation[ ref2 ] = show ? margin : distance + margin;
10405 }
10406
10407 // start at 0 if we are showing
10408 if ( show ) {
10409 wrapper.css( ref, 0 );
10410 if ( ! motion ) {
10411 wrapper.css( ref2, margin + distance );
10412 }
10413 }
10414
10415 // Animate
10416 wrapper.animate( animation, {
10417 duration: o.duration,
10418 easing: o.easing,
10419 queue: false,
10420 complete: function() {
10421 if ( mode === "hide" ) {
10422 el.hide();
10423 }
10424 $.effects.restore( el, props );
10425 $.effects.removeWrapper( el );
10426 done();
10427 }
10428 });
10429
10430};
10431
10432})(jQuery);
10433
10434(function( $, undefined ) {
10435
10436$.effects.effect.bounce = function( o, done ) {
10437 var el = $( this ),
10438 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10439
10440 // defaults:
10441 mode = $.effects.setMode( el, o.mode || "effect" ),
10442 hide = mode === "hide",
10443 show = mode === "show",
10444 direction = o.direction || "up",
10445 distance = o.distance,
10446 times = o.times || 5,
10447
10448 // number of internal animations
10449 anims = times * 2 + ( show || hide ? 1 : 0 ),
10450 speed = o.duration / anims,
10451 easing = o.easing,
10452
10453 // utility:
10454 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
10455 motion = ( direction === "up" || direction === "left" ),
10456 i,
10457 upAnim,
10458 downAnim,
10459
10460 // we will need to re-assemble the queue to stack our animations in place
10461 queue = el.queue(),
10462 queuelen = queue.length;
10463
10464 // Avoid touching opacity to prevent clearType and PNG issues in IE
10465 if ( show || hide ) {
10466 props.push( "opacity" );
10467 }
10468
10469 $.effects.save( el, props );
10470 el.show();
10471 $.effects.createWrapper( el ); // Create Wrapper
10472
10473 // default distance for the BIGGEST bounce is the outer Distance / 3
10474 if ( !distance ) {
10475 distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
10476 }
10477
10478 if ( show ) {
10479 downAnim = { opacity: 1 };
10480 downAnim[ ref ] = 0;
10481
10482 // if we are showing, force opacity 0 and set the initial position
10483 // then do the "first" animation
10484 el.css( "opacity", 0 )
10485 .css( ref, motion ? -distance * 2 : distance * 2 )
10486 .animate( downAnim, speed, easing );
10487 }
10488
10489 // start at the smallest distance if we are hiding
10490 if ( hide ) {
10491 distance = distance / Math.pow( 2, times - 1 );
10492 }
10493
10494 downAnim = {};
10495 downAnim[ ref ] = 0;
10496 // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
10497 for ( i = 0; i < times; i++ ) {
10498 upAnim = {};
10499 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
10500
10501 el.animate( upAnim, speed, easing )
10502 .animate( downAnim, speed, easing );
10503
10504 distance = hide ? distance * 2 : distance / 2;
10505 }
10506
10507 // Last Bounce when Hiding
10508 if ( hide ) {
10509 upAnim = { opacity: 0 };
10510 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
10511
10512 el.animate( upAnim, speed, easing );
10513 }
10514
10515 el.queue(function() {
10516 if ( hide ) {
10517 el.hide();
10518 }
10519 $.effects.restore( el, props );
10520 $.effects.removeWrapper( el );
10521 done();
10522 });
10523
10524 // inject all the animations we just queued to be first in line (after "inprogress")
10525 if ( queuelen > 1) {
10526 queue.splice.apply( queue,
10527 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
10528 }
10529 el.dequeue();
10530
10531};
10532
10533})(jQuery);
10534
10535(function( $, undefined ) {
10536
10537$.effects.effect.clip = function( o, done ) {
10538 // Create element
10539 var el = $( this ),
10540 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10541 mode = $.effects.setMode( el, o.mode || "hide" ),
10542 show = mode === "show",
10543 direction = o.direction || "vertical",
10544 vert = direction === "vertical",
10545 size = vert ? "height" : "width",
10546 position = vert ? "top" : "left",
10547 animation = {},
10548 wrapper, animate, distance;
10549
10550 // Save & Show
10551 $.effects.save( el, props );
10552 el.show();
10553
10554 // Create Wrapper
10555 wrapper = $.effects.createWrapper( el ).css({
10556 overflow: "hidden"
10557 });
10558 animate = ( el[0].tagName === "IMG" ) ? wrapper : el;
10559 distance = animate[ size ]();
10560
10561 // Shift
10562 if ( show ) {
10563 animate.css( size, 0 );
10564 animate.css( position, distance / 2 );
10565 }
10566
10567 // Create Animation Object:
10568 animation[ size ] = show ? distance : 0;
10569 animation[ position ] = show ? 0 : distance / 2;
10570
10571 // Animate
10572 animate.animate( animation, {
10573 queue: false,
10574 duration: o.duration,
10575 easing: o.easing,
10576 complete: function() {
10577 if ( !show ) {
10578 el.hide();
10579 }
10580 $.effects.restore( el, props );
10581 $.effects.removeWrapper( el );
10582 done();
10583 }
10584 });
10585
10586};
10587
10588})(jQuery);
10589
10590(function( $, undefined ) {
10591
10592$.effects.effect.drop = function( o, done ) {
10593
10594 var el = $( this ),
10595 props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
10596 mode = $.effects.setMode( el, o.mode || "hide" ),
10597 show = mode === "show",
10598 direction = o.direction || "left",
10599 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
10600 motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
10601 animation = {
10602 opacity: show ? 1 : 0
10603 },
10604 distance;
10605
10606 // Adjust
10607 $.effects.save( el, props );
10608 el.show();
10609 $.effects.createWrapper( el );
10610
10611 distance = o.distance || el[ ref === "top" ? "outerHeight": "outerWidth" ]( true ) / 2;
10612
10613 if ( show ) {
10614 el
10615 .css( "opacity", 0 )
10616 .css( ref, motion === "pos" ? -distance : distance );
10617 }
10618
10619 // Animation
10620 animation[ ref ] = ( show ?
10621 ( motion === "pos" ? "+=" : "-=" ) :
10622 ( motion === "pos" ? "-=" : "+=" ) ) +
10623 distance;
10624
10625 // Animate
10626 el.animate( animation, {
10627 queue: false,
10628 duration: o.duration,
10629 easing: o.easing,
10630 complete: function() {
10631 if ( mode === "hide" ) {
10632 el.hide();
10633 }
10634 $.effects.restore( el, props );
10635 $.effects.removeWrapper( el );
10636 done();
10637 }
10638 });
10639};
10640
10641})(jQuery);
10642
10643(function( $, undefined ) {
10644
10645$.effects.effect.explode = function( o, done ) {
10646
10647 var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3,
10648 cells = rows,
10649 el = $( this ),
10650 mode = $.effects.setMode( el, o.mode || "hide" ),
10651 show = mode === "show",
10652
10653 // show and then visibility:hidden the element before calculating offset
10654 offset = el.show().css( "visibility", "hidden" ).offset(),
10655
10656 // width and height of a piece
10657 width = Math.ceil( el.outerWidth() / cells ),
10658 height = Math.ceil( el.outerHeight() / rows ),
10659 pieces = [],
10660
10661 // loop
10662 i, j, left, top, mx, my;
10663
10664 // children animate complete:
10665 function childComplete() {
10666 pieces.push( this );
10667 if ( pieces.length === rows * cells ) {
10668 animComplete();
10669 }
10670 }
10671
10672 // clone the element for each row and cell.
10673 for( i = 0; i < rows ; i++ ) { // ===>
10674 top = offset.top + i * height;
10675 my = i - ( rows - 1 ) / 2 ;
10676
10677 for( j = 0; j < cells ; j++ ) { // |||
10678 left = offset.left + j * width;
10679 mx = j - ( cells - 1 ) / 2 ;
10680
10681 // Create a clone of the now hidden main element that will be absolute positioned
10682 // within a wrapper div off the -left and -top equal to size of our pieces
10683 el
10684 .clone()
10685 .appendTo( "body" )
10686 .wrap( "<div></div>" )
10687 .css({
10688 position: "absolute",
10689 visibility: "visible",
10690 left: -j * width,
10691 top: -i * height
10692 })
10693
10694 // select the wrapper - make it overflow: hidden and absolute positioned based on
10695 // where the original was located +left and +top equal to the size of pieces
10696 .parent()
10697 .addClass( "ui-effects-explode" )
10698 .css({
10699 position: "absolute",
10700 overflow: "hidden",
10701 width: width,
10702 height: height,
10703 left: left + ( show ? mx * width : 0 ),
10704 top: top + ( show ? my * height : 0 ),
10705 opacity: show ? 0 : 1
10706 }).animate({
10707 left: left + ( show ? 0 : mx * width ),
10708 top: top + ( show ? 0 : my * height ),
10709 opacity: show ? 1 : 0
10710 }, o.duration || 500, o.easing, childComplete );
10711 }
10712 }
10713
10714 function animComplete() {
10715 el.css({
10716 visibility: "visible"
10717 });
10718 $( pieces ).remove();
10719 if ( !show ) {
10720 el.hide();
10721 }
10722 done();
10723 }
10724};
10725
10726})(jQuery);
10727
10728(function( $, undefined ) {
10729
10730$.effects.effect.fade = function( o, done ) {
10731 var el = $( this ),
10732 mode = $.effects.setMode( el, o.mode || "toggle" );
10733
10734 el.animate({
10735 opacity: mode
10736 }, {
10737 queue: false,
10738 duration: o.duration,
10739 easing: o.easing,
10740 complete: done
10741 });
10742};
10743
10744})( jQuery );
10745
10746(function( $, undefined ) {
10747
10748$.effects.effect.fold = function( o, done ) {
10749
10750 // Create element
10751 var el = $( this ),
10752 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10753 mode = $.effects.setMode( el, o.mode || "hide" ),
10754 show = mode === "show",
10755 hide = mode === "hide",
10756 size = o.size || 15,
10757 percent = /([0-9]+)%/.exec( size ),
10758 horizFirst = !!o.horizFirst,
10759 widthFirst = show !== horizFirst,
10760 ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ],
10761 duration = o.duration / 2,
10762 wrapper, distance,
10763 animation1 = {},
10764 animation2 = {};
10765
10766 $.effects.save( el, props );
10767 el.show();
10768
10769 // Create Wrapper
10770 wrapper = $.effects.createWrapper( el ).css({
10771 overflow: "hidden"
10772 });
10773 distance = widthFirst ?
10774 [ wrapper.width(), wrapper.height() ] :
10775 [ wrapper.height(), wrapper.width() ];
10776
10777 if ( percent ) {
10778 size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
10779 }
10780 if ( show ) {
10781 wrapper.css( horizFirst ? {
10782 height: 0,
10783 width: size
10784 } : {
10785 height: size,
10786 width: 0
10787 });
10788 }
10789
10790 // Animation
10791 animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size;
10792 animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0;
10793
10794 // Animate
10795 wrapper
10796 .animate( animation1, duration, o.easing )
10797 .animate( animation2, duration, o.easing, function() {
10798 if ( hide ) {
10799 el.hide();
10800 }
10801 $.effects.restore( el, props );
10802 $.effects.removeWrapper( el );
10803 done();
10804 });
10805
10806};
10807
10808})(jQuery);
10809
10810(function( $, undefined ) {
10811
10812$.effects.effect.highlight = function( o, done ) {
10813 var elem = $( this ),
10814 props = [ "backgroundImage", "backgroundColor", "opacity" ],
10815 mode = $.effects.setMode( elem, o.mode || "show" ),
10816 animation = {
10817 backgroundColor: elem.css( "backgroundColor" )
10818 };
10819
10820 if (mode === "hide") {
10821 animation.opacity = 0;
10822 }
10823
10824 $.effects.save( elem, props );
10825
10826 elem
10827 .show()
10828 .css({
10829 backgroundImage: "none",
10830 backgroundColor: o.color || "#ffff99"
10831 })
10832 .animate( animation, {
10833 queue: false,
10834 duration: o.duration,
10835 easing: o.easing,
10836 complete: function() {
10837 if ( mode === "hide" ) {
10838 elem.hide();
10839 }
10840 $.effects.restore( elem, props );
10841 done();
10842 }
10843 });
10844};
10845
10846})(jQuery);
10847
10848(function( $, undefined ) {
10849
10850$.effects.effect.pulsate = function( o, done ) {
10851 var elem = $( this ),
10852 mode = $.effects.setMode( elem, o.mode || "show" ),
10853 show = mode === "show",
10854 hide = mode === "hide",
10855 showhide = ( show || mode === "hide" ),
10856
10857 // showing or hiding leaves of the "last" animation
10858 anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
10859 duration = o.duration / anims,
10860 animateTo = 0,
10861 queue = elem.queue(),
10862 queuelen = queue.length,
10863 i;
10864
10865 if ( show || !elem.is(":visible")) {
10866 elem.css( "opacity", 0 ).show();
10867 animateTo = 1;
10868 }
10869
10870 // anims - 1 opacity "toggles"
10871 for ( i = 1; i < anims; i++ ) {
10872 elem.animate({
10873 opacity: animateTo
10874 }, duration, o.easing );
10875 animateTo = 1 - animateTo;
10876 }
10877
10878 elem.animate({
10879 opacity: animateTo
10880 }, duration, o.easing);
10881
10882 elem.queue(function() {
10883 if ( hide ) {
10884 elem.hide();
10885 }
10886 done();
10887 });
10888
10889 // We just queued up "anims" animations, we need to put them next in the queue
10890 if ( queuelen > 1 ) {
10891 queue.splice.apply( queue,
10892 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
10893 }
10894 elem.dequeue();
10895};
10896
10897})(jQuery);
10898
10899(function( $, undefined ) {
10900
10901$.effects.effect.puff = function( o, done ) {
10902 var elem = $( this ),
10903 mode = $.effects.setMode( elem, o.mode || "hide" ),
10904 hide = mode === "hide",
10905 percent = parseInt( o.percent, 10 ) || 150,
10906 factor = percent / 100,
10907 original = {
10908 height: elem.height(),
10909 width: elem.width(),
10910 outerHeight: elem.outerHeight(),
10911 outerWidth: elem.outerWidth()
10912 };
10913
10914 $.extend( o, {
10915 effect: "scale",
10916 queue: false,
10917 fade: true,
10918 mode: mode,
10919 complete: done,
10920 percent: hide ? percent : 100,
10921 from: hide ?
10922 original :
10923 {
10924 height: original.height * factor,
10925 width: original.width * factor,
10926 outerHeight: original.outerHeight * factor,
10927 outerWidth: original.outerWidth * factor
10928 }
10929 });
10930
10931 elem.effect( o );
10932};
10933
10934$.effects.effect.scale = function( o, done ) {
10935
10936 // Create element
10937 var el = $( this ),
10938 options = $.extend( true, {}, o ),
10939 mode = $.effects.setMode( el, o.mode || "effect" ),
10940 percent = parseInt( o.percent, 10 ) ||
10941 ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ),
10942 direction = o.direction || "both",
10943 origin = o.origin,
10944 original = {
10945 height: el.height(),
10946 width: el.width(),
10947 outerHeight: el.outerHeight(),
10948 outerWidth: el.outerWidth()
10949 },
10950 factor = {
10951 y: direction !== "horizontal" ? (percent / 100) : 1,
10952 x: direction !== "vertical" ? (percent / 100) : 1
10953 };
10954
10955 // We are going to pass this effect to the size effect:
10956 options.effect = "size";
10957 options.queue = false;
10958 options.complete = done;
10959
10960 // Set default origin and restore for show/hide
10961 if ( mode !== "effect" ) {
10962 options.origin = origin || ["middle","center"];
10963 options.restore = true;
10964 }
10965
10966 options.from = o.from || ( mode === "show" ? {
10967 height: 0,
10968 width: 0,
10969 outerHeight: 0,
10970 outerWidth: 0
10971 } : original );
10972 options.to = {
10973 height: original.height * factor.y,
10974 width: original.width * factor.x,
10975 outerHeight: original.outerHeight * factor.y,
10976 outerWidth: original.outerWidth * factor.x
10977 };
10978
10979 // Fade option to support puff
10980 if ( options.fade ) {
10981 if ( mode === "show" ) {
10982 options.from.opacity = 0;
10983 options.to.opacity = 1;
10984 }
10985 if ( mode === "hide" ) {
10986 options.from.opacity = 1;
10987 options.to.opacity = 0;
10988 }
10989 }
10990
10991 // Animate
10992 el.effect( options );
10993
10994};
10995
10996$.effects.effect.size = function( o, done ) {
10997
10998 // Create element
10999 var original, baseline, factor,
11000 el = $( this ),
11001 props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ],
11002
11003 // Always restore
11004 props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ],
11005
11006 // Copy for children
11007 props2 = [ "width", "height", "overflow" ],
11008 cProps = [ "fontSize" ],
11009 vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
11010 hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
11011
11012 // Set options
11013 mode = $.effects.setMode( el, o.mode || "effect" ),
11014 restore = o.restore || mode !== "effect",
11015 scale = o.scale || "both",
11016 origin = o.origin || [ "middle", "center" ],
11017 position = el.css( "position" ),
11018 props = restore ? props0 : props1,
11019 zero = {
11020 height: 0,
11021 width: 0,
11022 outerHeight: 0,
11023 outerWidth: 0
11024 };
11025
11026 if ( mode === "show" ) {
11027 el.show();
11028 }
11029 original = {
11030 height: el.height(),
11031 width: el.width(),
11032 outerHeight: el.outerHeight(),
11033 outerWidth: el.outerWidth()
11034 };
11035
11036 if ( o.mode === "toggle" && mode === "show" ) {
11037 el.from = o.to || zero;
11038 el.to = o.from || original;
11039 } else {
11040 el.from = o.from || ( mode === "show" ? zero : original );
11041 el.to = o.to || ( mode === "hide" ? zero : original );
11042 }
11043
11044 // Set scaling factor
11045 factor = {
11046 from: {
11047 y: el.from.height / original.height,
11048 x: el.from.width / original.width
11049 },
11050 to: {
11051 y: el.to.height / original.height,
11052 x: el.to.width / original.width
11053 }
11054 };
11055
11056 // Scale the css box
11057 if ( scale === "box" || scale === "both" ) {
11058
11059 // Vertical props scaling
11060 if ( factor.from.y !== factor.to.y ) {
11061 props = props.concat( vProps );
11062 el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
11063 el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
11064 }
11065
11066 // Horizontal props scaling
11067 if ( factor.from.x !== factor.to.x ) {
11068 props = props.concat( hProps );
11069 el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
11070 el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
11071 }
11072 }
11073
11074 // Scale the content
11075 if ( scale === "content" || scale === "both" ) {
11076
11077 // Vertical props scaling
11078 if ( factor.from.y !== factor.to.y ) {
11079 props = props.concat( cProps ).concat( props2 );
11080 el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
11081 el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
11082 }
11083 }
11084
11085 $.effects.save( el, props );
11086 el.show();
11087 $.effects.createWrapper( el );
11088 el.css( "overflow", "hidden" ).css( el.from );
11089
11090 // Adjust
11091 if (origin) { // Calculate baseline shifts
11092 baseline = $.effects.getBaseline( origin, original );
11093 el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
11094 el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
11095 el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
11096 el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
11097 }
11098 el.css( el.from ); // set top & left
11099
11100 // Animate
11101 if ( scale === "content" || scale === "both" ) { // Scale the children
11102
11103 // Add margins/font-size
11104 vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps);
11105 hProps = hProps.concat([ "marginLeft", "marginRight" ]);
11106 props2 = props0.concat(vProps).concat(hProps);
11107
11108 el.find( "*[width]" ).each( function(){
11109 var child = $( this ),
11110 c_original = {
11111 height: child.height(),
11112 width: child.width(),
11113 outerHeight: child.outerHeight(),
11114 outerWidth: child.outerWidth()
11115 };
11116 if (restore) {
11117 $.effects.save(child, props2);
11118 }
11119
11120 child.from = {
11121 height: c_original.height * factor.from.y,
11122 width: c_original.width * factor.from.x,
11123 outerHeight: c_original.outerHeight * factor.from.y,
11124 outerWidth: c_original.outerWidth * factor.from.x
11125 };
11126 child.to = {
11127 height: c_original.height * factor.to.y,
11128 width: c_original.width * factor.to.x,
11129 outerHeight: c_original.height * factor.to.y,
11130 outerWidth: c_original.width * factor.to.x
11131 };
11132
11133 // Vertical props scaling
11134 if ( factor.from.y !== factor.to.y ) {
11135 child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
11136 child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
11137 }
11138
11139 // Horizontal props scaling
11140 if ( factor.from.x !== factor.to.x ) {
11141 child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
11142 child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
11143 }
11144
11145 // Animate children
11146 child.css( child.from );
11147 child.animate( child.to, o.duration, o.easing, function() {
11148
11149 // Restore children
11150 if ( restore ) {
11151 $.effects.restore( child, props2 );
11152 }
11153 });
11154 });
11155 }
11156
11157 // Animate
11158 el.animate( el.to, {
11159 queue: false,
11160 duration: o.duration,
11161 easing: o.easing,
11162 complete: function() {
11163 if ( el.to.opacity === 0 ) {
11164 el.css( "opacity", el.from.opacity );
11165 }
11166 if( mode === "hide" ) {
11167 el.hide();
11168 }
11169 $.effects.restore( el, props );
11170 if ( !restore ) {
11171
11172 // we need to calculate our new positioning based on the scaling
11173 if ( position === "static" ) {
11174 el.css({
11175 position: "relative",
11176 top: el.to.top,
11177 left: el.to.left
11178 });
11179 } else {
11180 $.each([ "top", "left" ], function( idx, pos ) {
11181 el.css( pos, function( _, str ) {
11182 var val = parseInt( str, 10 ),
11183 toRef = idx ? el.to.left : el.to.top;
11184
11185 // if original was "auto", recalculate the new value from wrapper
11186 if ( str === "auto" ) {
11187 return toRef + "px";
11188 }
11189
11190 return val + toRef + "px";
11191 });
11192 });
11193 }
11194 }
11195
11196 $.effects.removeWrapper( el );
11197 done();
11198 }
11199 });
11200
11201};
11202
11203})(jQuery);
11204
11205(function( $, undefined ) {
11206
11207$.effects.effect.shake = function( o, done ) {
11208
11209 var el = $( this ),
11210 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
11211 mode = $.effects.setMode( el, o.mode || "effect" ),
11212 direction = o.direction || "left",
11213 distance = o.distance || 20,
11214 times = o.times || 3,
11215 anims = times * 2 + 1,
11216 speed = Math.round(o.duration/anims),
11217 ref = (direction === "up" || direction === "down") ? "top" : "left",
11218 positiveMotion = (direction === "up" || direction === "left"),
11219 animation = {},
11220 animation1 = {},
11221 animation2 = {},
11222 i,
11223
11224 // we will need to re-assemble the queue to stack our animations in place
11225 queue = el.queue(),
11226 queuelen = queue.length;
11227
11228 $.effects.save( el, props );
11229 el.show();
11230 $.effects.createWrapper( el );
11231
11232 // Animation
11233 animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
11234 animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
11235 animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
11236
11237 // Animate
11238 el.animate( animation, speed, o.easing );
11239
11240 // Shakes
11241 for ( i = 1; i < times; i++ ) {
11242 el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing );
11243 }
11244 el
11245 .animate( animation1, speed, o.easing )
11246 .animate( animation, speed / 2, o.easing )
11247 .queue(function() {
11248 if ( mode === "hide" ) {
11249 el.hide();
11250 }
11251 $.effects.restore( el, props );
11252 $.effects.removeWrapper( el );
11253 done();
11254 });
11255
11256 // inject all the animations we just queued to be first in line (after "inprogress")
11257 if ( queuelen > 1) {
11258 queue.splice.apply( queue,
11259 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
11260 }
11261 el.dequeue();
11262
11263};
11264
11265})(jQuery);
11266
11267(function( $, undefined ) {
11268
11269$.effects.effect.slide = function( o, done ) {
11270
11271 // Create element
11272 var el = $( this ),
11273 props = [ "position", "top", "bottom", "left", "right", "width", "height" ],
11274 mode = $.effects.setMode( el, o.mode || "show" ),
11275 show = mode === "show",
11276 direction = o.direction || "left",
11277 ref = (direction === "up" || direction === "down") ? "top" : "left",
11278 positiveMotion = (direction === "up" || direction === "left"),
11279 distance,
11280 animation = {};
11281
11282 // Adjust
11283 $.effects.save( el, props );
11284 el.show();
11285 distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true );
11286
11287 $.effects.createWrapper( el ).css({
11288 overflow: "hidden"
11289 });
11290
11291 if ( show ) {
11292 el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance );
11293 }
11294
11295 // Animation
11296 animation[ ref ] = ( show ?
11297 ( positiveMotion ? "+=" : "-=") :
11298 ( positiveMotion ? "-=" : "+=")) +
11299 distance;
11300
11301 // Animate
11302 el.animate( animation, {
11303 queue: false,
11304 duration: o.duration,
11305 easing: o.easing,
11306 complete: function() {
11307 if ( mode === "hide" ) {
11308 el.hide();
11309 }
11310 $.effects.restore( el, props );
11311 $.effects.removeWrapper( el );
11312 done();
11313 }
11314 });
11315};
11316
11317})(jQuery);
11318
11319(function( $, undefined ) {
11320
11321$.effects.effect.transfer = function( o, done ) {
11322 var elem = $( this ),
11323 target = $( o.to ),
11324 targetFixed = target.css( "position" ) === "fixed",
11325 body = $("body"),
11326 fixTop = targetFixed ? body.scrollTop() : 0,
11327 fixLeft = targetFixed ? body.scrollLeft() : 0,
11328 endPosition = target.offset(),
11329 animation = {
11330 top: endPosition.top - fixTop ,
11331 left: endPosition.left - fixLeft ,
11332 height: target.innerHeight(),
11333 width: target.innerWidth()
11334 },
11335 startPosition = elem.offset(),
11336 transfer = $( "<div class='ui-effects-transfer'></div>" )
11337 .appendTo( document.body )
11338 .addClass( o.className )
11339 .css({
11340 top: startPosition.top - fixTop ,
11341 left: startPosition.left - fixLeft ,
11342 height: elem.innerHeight(),
11343 width: elem.innerWidth(),
11344 position: targetFixed ? "fixed" : "absolute"
11345 })
11346 .animate( animation, o.duration, o.easing, function() {
11347 transfer.remove();
11348 done();
11349 });
11350};
11351
11352})(jQuery);
11353
11354(function( $, undefined ) {
11355
11356$.widget( "ui.menu", {
11357 version: "1.10.1",
11358 defaultElement: "<ul>",
11359 delay: 300,
11360 options: {
11361 icons: {
11362 submenu: "ui-icon-carat-1-e"
11363 },
11364 menus: "ul",
11365 position: {
11366 my: "left top",
11367 at: "right top"
11368 },
11369 role: "menu",
11370
11371 // callbacks
11372 blur: null,
11373 focus: null,
11374 select: null
11375 },
11376
11377 _create: function() {
11378 this.activeMenu = this.element;
11379 // flag used to prevent firing of the click handler
11380 // as the event bubbles up through nested menus
11381 this.mouseHandled = false;
11382 this.element
11383 .uniqueId()
11384 .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
11385 .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
11386 .attr({
11387 role: this.options.role,
11388 tabIndex: 0
11389 })
11390 // need to catch all clicks on disabled menu
11391 // not possible through _on
11392 .bind( "click" + this.eventNamespace, $.proxy(function( event ) {
11393 if ( this.options.disabled ) {
11394 event.preventDefault();
11395 }
11396 }, this ));
11397
11398 if ( this.options.disabled ) {
11399 this.element
11400 .addClass( "ui-state-disabled" )
11401 .attr( "aria-disabled", "true" );
11402 }
11403
11404 this._on({
11405 // Prevent focus from sticking to links inside menu after clicking
11406 // them (focus should always stay on UL during navigation).
11407 "mousedown .ui-menu-item > a": function( event ) {
11408 event.preventDefault();
11409 },
11410 "click .ui-state-disabled > a": function( event ) {
11411 event.preventDefault();
11412 },
11413 "click .ui-menu-item:has(a)": function( event ) {
11414 var target = $( event.target ).closest( ".ui-menu-item" );
11415 if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
11416 this.mouseHandled = true;
11417
11418 this.select( event );
11419 // Open submenu on click
11420 if ( target.has( ".ui-menu" ).length ) {
11421 this.expand( event );
11422 } else if ( !this.element.is( ":focus" ) ) {
11423 // Redirect focus to the menu
11424 this.element.trigger( "focus", [ true ] );
11425
11426 // If the active item is on the top level, let it stay active.
11427 // Otherwise, blur the active item since it is no longer visible.
11428 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
11429 clearTimeout( this.timer );
11430 }
11431 }
11432 }
11433 },
11434 "mouseenter .ui-menu-item": function( event ) {
11435 var target = $( event.currentTarget );
11436 // Remove ui-state-active class from siblings of the newly focused menu item
11437 // to avoid a jump caused by adjacent elements both having a class with a border
11438 target.siblings().children( ".ui-state-active" ).removeClass( "ui-state-active" );
11439 this.focus( event, target );
11440 },
11441 mouseleave: "collapseAll",
11442 "mouseleave .ui-menu": "collapseAll",
11443 focus: function( event, keepActiveItem ) {
11444 // If there's already an active item, keep it active
11445 // If not, activate the first item
11446 var item = this.active || this.element.children( ".ui-menu-item" ).eq( 0 );
11447
11448 if ( !keepActiveItem ) {
11449 this.focus( event, item );
11450 }
11451 },
11452 blur: function( event ) {
11453 this._delay(function() {
11454 if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
11455 this.collapseAll( event );
11456 }
11457 });
11458 },
11459 keydown: "_keydown"
11460 });
11461
11462 this.refresh();
11463
11464 // Clicks outside of a menu collapse any open menus
11465 this._on( this.document, {
11466 click: function( event ) {
11467 if ( !$( event.target ).closest( ".ui-menu" ).length ) {
11468 this.collapseAll( event );
11469 }
11470
11471 // Reset the mouseHandled flag
11472 this.mouseHandled = false;
11473 }
11474 });
11475 },
11476
11477 _destroy: function() {
11478 // Destroy (sub)menus
11479 this.element
11480 .removeAttr( "aria-activedescendant" )
11481 .find( ".ui-menu" ).addBack()
11482 .removeClass( "ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons" )
11483 .removeAttr( "role" )
11484 .removeAttr( "tabIndex" )
11485 .removeAttr( "aria-labelledby" )
11486 .removeAttr( "aria-expanded" )
11487 .removeAttr( "aria-hidden" )
11488 .removeAttr( "aria-disabled" )
11489 .removeUniqueId()
11490 .show();
11491
11492 // Destroy menu items
11493 this.element.find( ".ui-menu-item" )
11494 .removeClass( "ui-menu-item" )
11495 .removeAttr( "role" )
11496 .removeAttr( "aria-disabled" )
11497 .children( "a" )
11498 .removeUniqueId()
11499 .removeClass( "ui-corner-all ui-state-hover" )
11500 .removeAttr( "tabIndex" )
11501 .removeAttr( "role" )
11502 .removeAttr( "aria-haspopup" )
11503 .children().each( function() {
11504 var elem = $( this );
11505 if ( elem.data( "ui-menu-submenu-carat" ) ) {
11506 elem.remove();
11507 }
11508 });
11509
11510 // Destroy menu dividers
11511 this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
11512 },
11513
11514 _keydown: function( event ) {
11515 /*jshint maxcomplexity:20*/
11516 var match, prev, character, skip, regex,
11517 preventDefault = true;
11518
11519 function escape( value ) {
11520 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
11521 }
11522
11523 switch ( event.keyCode ) {
11524 case $.ui.keyCode.PAGE_UP:
11525 this.previousPage( event );
11526 break;
11527 case $.ui.keyCode.PAGE_DOWN:
11528 this.nextPage( event );
11529 break;
11530 case $.ui.keyCode.HOME:
11531 this._move( "first", "first", event );
11532 break;
11533 case $.ui.keyCode.END:
11534 this._move( "last", "last", event );
11535 break;
11536 case $.ui.keyCode.UP:
11537 this.previous( event );
11538 break;
11539 case $.ui.keyCode.DOWN:
11540 this.next( event );
11541 break;
11542 case $.ui.keyCode.LEFT:
11543 this.collapse( event );
11544 break;
11545 case $.ui.keyCode.RIGHT:
11546 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
11547 this.expand( event );
11548 }
11549 break;
11550 case $.ui.keyCode.ENTER:
11551 case $.ui.keyCode.SPACE:
11552 this._activate( event );
11553 break;
11554 case $.ui.keyCode.ESCAPE:
11555 this.collapse( event );
11556 break;
11557 default:
11558 preventDefault = false;
11559 prev = this.previousFilter || "";
11560 character = String.fromCharCode( event.keyCode );
11561 skip = false;
11562
11563 clearTimeout( this.filterTimer );
11564
11565 if ( character === prev ) {
11566 skip = true;
11567 } else {
11568 character = prev + character;
11569 }
11570
11571 regex = new RegExp( "^" + escape( character ), "i" );
11572 match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
11573 return regex.test( $( this ).children( "a" ).text() );
11574 });
11575 match = skip && match.index( this.active.next() ) !== -1 ?
11576 this.active.nextAll( ".ui-menu-item" ) :
11577 match;
11578
11579 // If no matches on the current filter, reset to the last character pressed
11580 // to move down the menu to the first item that starts with that character
11581 if ( !match.length ) {
11582 character = String.fromCharCode( event.keyCode );
11583 regex = new RegExp( "^" + escape( character ), "i" );
11584 match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
11585 return regex.test( $( this ).children( "a" ).text() );
11586 });
11587 }
11588
11589 if ( match.length ) {
11590 this.focus( event, match );
11591 if ( match.length > 1 ) {
11592 this.previousFilter = character;
11593 this.filterTimer = this._delay(function() {
11594 delete this.previousFilter;
11595 }, 1000 );
11596 } else {
11597 delete this.previousFilter;
11598 }
11599 } else {
11600 delete this.previousFilter;
11601 }
11602 }
11603
11604 if ( preventDefault ) {
11605 event.preventDefault();
11606 }
11607 },
11608
11609 _activate: function( event ) {
11610 if ( !this.active.is( ".ui-state-disabled" ) ) {
11611 if ( this.active.children( "a[aria-haspopup='true']" ).length ) {
11612 this.expand( event );
11613 } else {
11614 this.select( event );
11615 }
11616 }
11617 },
11618
11619 refresh: function() {
11620 var menus,
11621 icon = this.options.icons.submenu,
11622 submenus = this.element.find( this.options.menus );
11623
11624 // Initialize nested menus
11625 submenus.filter( ":not(.ui-menu)" )
11626 .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
11627 .hide()
11628 .attr({
11629 role: this.options.role,
11630 "aria-hidden": "true",
11631 "aria-expanded": "false"
11632 })
11633 .each(function() {
11634 var menu = $( this ),
11635 item = menu.prev( "a" ),
11636 submenuCarat = $( "<span>" )
11637 .addClass( "ui-menu-icon ui-icon " + icon )
11638 .data( "ui-menu-submenu-carat", true );
11639
11640 item
11641 .attr( "aria-haspopup", "true" )
11642 .prepend( submenuCarat );
11643 menu.attr( "aria-labelledby", item.attr( "id" ) );
11644 });
11645
11646 menus = submenus.add( this.element );
11647
11648 // Don't refresh list items that are already adapted
11649 menus.children( ":not(.ui-menu-item):has(a)" )
11650 .addClass( "ui-menu-item" )
11651 .attr( "role", "presentation" )
11652 .children( "a" )
11653 .uniqueId()
11654 .addClass( "ui-corner-all" )
11655 .attr({
11656 tabIndex: -1,
11657 role: this._itemRole()
11658 });
11659
11660 // Initialize unlinked menu-items containing spaces and/or dashes only as dividers
11661 menus.children( ":not(.ui-menu-item)" ).each(function() {
11662 var item = $( this );
11663 // hyphen, em dash, en dash
11664 if ( !/[^\-\u2014\u2013\s]/.test( item.text() ) ) {
11665 item.addClass( "ui-widget-content ui-menu-divider" );
11666 }
11667 });
11668
11669 // Add aria-disabled attribute to any disabled menu item
11670 menus.children( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
11671
11672 // If the active item has been removed, blur the menu
11673 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
11674 this.blur();
11675 }
11676 },
11677
11678 _itemRole: function() {
11679 return {
11680 menu: "menuitem",
11681 listbox: "option"
11682 }[ this.options.role ];
11683 },
11684
11685 _setOption: function( key, value ) {
11686 if ( key === "icons" ) {
11687 this.element.find( ".ui-menu-icon" )
11688 .removeClass( this.options.icons.submenu )
11689 .addClass( value.submenu );
11690 }
11691 this._super( key, value );
11692 },
11693
11694 focus: function( event, item ) {
11695 var nested, focused;
11696 this.blur( event, event && event.type === "focus" );
11697
11698 this._scrollIntoView( item );
11699
11700 this.active = item.first();
11701 focused = this.active.children( "a" ).addClass( "ui-state-focus" );
11702 // Only update aria-activedescendant if there's a role
11703 // otherwise we assume focus is managed elsewhere
11704 if ( this.options.role ) {
11705 this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
11706 }
11707
11708 // Highlight active parent menu item, if any
11709 this.active
11710 .parent()
11711 .closest( ".ui-menu-item" )
11712 .children( "a:first" )
11713 .addClass( "ui-state-active" );
11714
11715 if ( event && event.type === "keydown" ) {
11716 this._close();
11717 } else {
11718 this.timer = this._delay(function() {
11719 this._close();
11720 }, this.delay );
11721 }
11722
11723 nested = item.children( ".ui-menu" );
11724 if ( nested.length && ( /^mouse/.test( event.type ) ) ) {
11725 this._startOpening(nested);
11726 }
11727 this.activeMenu = item.parent();
11728
11729 this._trigger( "focus", event, { item: item } );
11730 },
11731
11732 _scrollIntoView: function( item ) {
11733 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
11734 if ( this._hasScroll() ) {
11735 borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
11736 paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
11737 offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
11738 scroll = this.activeMenu.scrollTop();
11739 elementHeight = this.activeMenu.height();
11740 itemHeight = item.height();
11741
11742 if ( offset < 0 ) {
11743 this.activeMenu.scrollTop( scroll + offset );
11744 } else if ( offset + itemHeight > elementHeight ) {
11745 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
11746 }
11747 }
11748 },
11749
11750 blur: function( event, fromFocus ) {
11751 if ( !fromFocus ) {
11752 clearTimeout( this.timer );
11753 }
11754
11755 if ( !this.active ) {
11756 return;
11757 }
11758
11759 this.active.children( "a" ).removeClass( "ui-state-focus" );
11760 this.active = null;
11761
11762 this._trigger( "blur", event, { item: this.active } );
11763 },
11764
11765 _startOpening: function( submenu ) {
11766 clearTimeout( this.timer );
11767
11768 // Don't open if already open fixes a Firefox bug that caused a .5 pixel
11769 // shift in the submenu position when mousing over the carat icon
11770 if ( submenu.attr( "aria-hidden" ) !== "true" ) {
11771 return;
11772 }
11773
11774 this.timer = this._delay(function() {
11775 this._close();
11776 this._open( submenu );
11777 }, this.delay );
11778 },
11779
11780 _open: function( submenu ) {
11781 var position = $.extend({
11782 of: this.active
11783 }, this.options.position );
11784
11785 clearTimeout( this.timer );
11786 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
11787 .hide()
11788 .attr( "aria-hidden", "true" );
11789
11790 submenu
11791 .show()
11792 .removeAttr( "aria-hidden" )
11793 .attr( "aria-expanded", "true" )
11794 .position( position );
11795 },
11796
11797 collapseAll: function( event, all ) {
11798 clearTimeout( this.timer );
11799 this.timer = this._delay(function() {
11800 // If we were passed an event, look for the submenu that contains the event
11801 var currentMenu = all ? this.element :
11802 $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
11803
11804 // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
11805 if ( !currentMenu.length ) {
11806 currentMenu = this.element;
11807 }
11808
11809 this._close( currentMenu );
11810
11811 this.blur( event );
11812 this.activeMenu = currentMenu;
11813 }, this.delay );
11814 },
11815
11816 // With no arguments, closes the currently active menu - if nothing is active
11817 // it closes all menus. If passed an argument, it will search for menus BELOW
11818 _close: function( startMenu ) {
11819 if ( !startMenu ) {
11820 startMenu = this.active ? this.active.parent() : this.element;
11821 }
11822
11823 startMenu
11824 .find( ".ui-menu" )
11825 .hide()
11826 .attr( "aria-hidden", "true" )
11827 .attr( "aria-expanded", "false" )
11828 .end()
11829 .find( "a.ui-state-active" )
11830 .removeClass( "ui-state-active" );
11831 },
11832
11833 collapse: function( event ) {
11834 var newItem = this.active &&
11835 this.active.parent().closest( ".ui-menu-item", this.element );
11836 if ( newItem && newItem.length ) {
11837 this._close();
11838 this.focus( event, newItem );
11839 }
11840 },
11841
11842 expand: function( event ) {
11843 var newItem = this.active &&
11844 this.active
11845 .children( ".ui-menu " )
11846 .children( ".ui-menu-item" )
11847 .first();
11848
11849 if ( newItem && newItem.length ) {
11850 this._open( newItem.parent() );
11851
11852 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
11853 this._delay(function() {
11854 this.focus( event, newItem );
11855 });
11856 }
11857 },
11858
11859 next: function( event ) {
11860 this._move( "next", "first", event );
11861 },
11862
11863 previous: function( event ) {
11864 this._move( "prev", "last", event );
11865 },
11866
11867 isFirstItem: function() {
11868 return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
11869 },
11870
11871 isLastItem: function() {
11872 return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
11873 },
11874
11875 _move: function( direction, filter, event ) {
11876 var next;
11877 if ( this.active ) {
11878 if ( direction === "first" || direction === "last" ) {
11879 next = this.active
11880 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
11881 .eq( -1 );
11882 } else {
11883 next = this.active
11884 [ direction + "All" ]( ".ui-menu-item" )
11885 .eq( 0 );
11886 }
11887 }
11888 if ( !next || !next.length || !this.active ) {
11889 next = this.activeMenu.children( ".ui-menu-item" )[ filter ]();
11890 }
11891
11892 this.focus( event, next );
11893 },
11894
11895 nextPage: function( event ) {
11896 var item, base, height;
11897
11898 if ( !this.active ) {
11899 this.next( event );
11900 return;
11901 }
11902 if ( this.isLastItem() ) {
11903 return;
11904 }
11905 if ( this._hasScroll() ) {
11906 base = this.active.offset().top;
11907 height = this.element.height();
11908 this.active.nextAll( ".ui-menu-item" ).each(function() {
11909 item = $( this );
11910 return item.offset().top - base - height < 0;
11911 });
11912
11913 this.focus( event, item );
11914 } else {
11915 this.focus( event, this.activeMenu.children( ".ui-menu-item" )
11916 [ !this.active ? "first" : "last" ]() );
11917 }
11918 },
11919
11920 previousPage: function( event ) {
11921 var item, base, height;
11922 if ( !this.active ) {
11923 this.next( event );
11924 return;
11925 }
11926 if ( this.isFirstItem() ) {
11927 return;
11928 }
11929 if ( this._hasScroll() ) {
11930 base = this.active.offset().top;
11931 height = this.element.height();
11932 this.active.prevAll( ".ui-menu-item" ).each(function() {
11933 item = $( this );
11934 return item.offset().top - base + height > 0;
11935 });
11936
11937 this.focus( event, item );
11938 } else {
11939 this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
11940 }
11941 },
11942
11943 _hasScroll: function() {
11944 return this.element.outerHeight() < this.element.prop( "scrollHeight" );
11945 },
11946
11947 select: function( event ) {
11948 // TODO: It should never be possible to not have an active item at this
11949 // point, but the tests don't trigger mouseenter before click.
11950 this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
11951 var ui = { item: this.active };
11952 if ( !this.active.has( ".ui-menu" ).length ) {
11953 this.collapseAll( event, true );
11954 }
11955 this._trigger( "select", event, ui );
11956 }
11957});
11958
11959}( jQuery ));
11960
11961(function( $, undefined ) {
11962
11963$.ui = $.ui || {};
11964
11965var cachedScrollbarWidth,
11966 max = Math.max,
11967 abs = Math.abs,
11968 round = Math.round,
11969 rhorizontal = /left|center|right/,
11970 rvertical = /top|center|bottom/,
11971 roffset = /[\+\-]\d+(\.[\d]+)?%?/,
11972 rposition = /^\w+/,
11973 rpercent = /%$/,
11974 _position = $.fn.position;
11975
11976function getOffsets( offsets, width, height ) {
11977 return [
11978 parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
11979 parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
11980 ];
11981}
11982
11983function parseCss( element, property ) {
11984 return parseInt( $.css( element, property ), 10 ) || 0;
11985}
11986
11987function getDimensions( elem ) {
11988 var raw = elem[0];
11989 if ( raw.nodeType === 9 ) {
11990 return {
11991 width: elem.width(),
11992 height: elem.height(),
11993 offset: { top: 0, left: 0 }
11994 };
11995 }
11996 if ( $.isWindow( raw ) ) {
11997 return {
11998 width: elem.width(),
11999 height: elem.height(),
12000 offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
12001 };
12002 }
12003 if ( raw.preventDefault ) {
12004 return {
12005 width: 0,
12006 height: 0,
12007 offset: { top: raw.pageY, left: raw.pageX }
12008 };
12009 }
12010 return {
12011 width: elem.outerWidth(),
12012 height: elem.outerHeight(),
12013 offset: elem.offset()
12014 };
12015}
12016
12017$.position = {
12018 scrollbarWidth: function() {
12019 if ( cachedScrollbarWidth !== undefined ) {
12020 return cachedScrollbarWidth;
12021 }
12022 var w1, w2,
12023 div = $( "<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
12024 innerDiv = div.children()[0];
12025
12026 $( "body" ).append( div );
12027 w1 = innerDiv.offsetWidth;
12028 div.css( "overflow", "scroll" );
12029
12030 w2 = innerDiv.offsetWidth;
12031
12032 if ( w1 === w2 ) {
12033 w2 = div[0].clientWidth;
12034 }
12035
12036 div.remove();
12037
12038 return (cachedScrollbarWidth = w1 - w2);
12039 },
12040 getScrollInfo: function( within ) {
12041 var overflowX = within.isWindow ? "" : within.element.css( "overflow-x" ),
12042 overflowY = within.isWindow ? "" : within.element.css( "overflow-y" ),
12043 hasOverflowX = overflowX === "scroll" ||
12044 ( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
12045 hasOverflowY = overflowY === "scroll" ||
12046 ( overflowY === "auto" && within.height < within.element[0].scrollHeight );
12047 return {
12048 width: hasOverflowX ? $.position.scrollbarWidth() : 0,
12049 height: hasOverflowY ? $.position.scrollbarWidth() : 0
12050 };
12051 },
12052 getWithinInfo: function( element ) {
12053 var withinElement = $( element || window ),
12054 isWindow = $.isWindow( withinElement[0] );
12055 return {
12056 element: withinElement,
12057 isWindow: isWindow,
12058 offset: withinElement.offset() || { left: 0, top: 0 },
12059 scrollLeft: withinElement.scrollLeft(),
12060 scrollTop: withinElement.scrollTop(),
12061 width: isWindow ? withinElement.width() : withinElement.outerWidth(),
12062 height: isWindow ? withinElement.height() : withinElement.outerHeight()
12063 };
12064 }
12065};
12066
12067$.fn.position = function( options ) {
12068 if ( !options || !options.of ) {
12069 return _position.apply( this, arguments );
12070 }
12071
12072 // make a copy, we don't want to modify arguments
12073 options = $.extend( {}, options );
12074
12075 var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
12076 target = $( options.of ),
12077 within = $.position.getWithinInfo( options.within ),
12078 scrollInfo = $.position.getScrollInfo( within ),
12079 collision = ( options.collision || "flip" ).split( " " ),
12080 offsets = {};
12081
12082 dimensions = getDimensions( target );
12083 if ( target[0].preventDefault ) {
12084 // force left top to allow flipping
12085 options.at = "left top";
12086 }
12087 targetWidth = dimensions.width;
12088 targetHeight = dimensions.height;
12089 targetOffset = dimensions.offset;
12090 // clone to reuse original targetOffset later
12091 basePosition = $.extend( {}, targetOffset );
12092
12093 // force my and at to have valid horizontal and vertical positions
12094 // if a value is missing or invalid, it will be converted to center
12095 $.each( [ "my", "at" ], function() {
12096 var pos = ( options[ this ] || "" ).split( " " ),
12097 horizontalOffset,
12098 verticalOffset;
12099
12100 if ( pos.length === 1) {
12101 pos = rhorizontal.test( pos[ 0 ] ) ?
12102 pos.concat( [ "center" ] ) :
12103 rvertical.test( pos[ 0 ] ) ?
12104 [ "center" ].concat( pos ) :
12105 [ "center", "center" ];
12106 }
12107 pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
12108 pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
12109
12110 // calculate offsets
12111 horizontalOffset = roffset.exec( pos[ 0 ] );
12112 verticalOffset = roffset.exec( pos[ 1 ] );
12113 offsets[ this ] = [
12114 horizontalOffset ? horizontalOffset[ 0 ] : 0,
12115 verticalOffset ? verticalOffset[ 0 ] : 0
12116 ];
12117
12118 // reduce to just the positions without the offsets
12119 options[ this ] = [
12120 rposition.exec( pos[ 0 ] )[ 0 ],
12121 rposition.exec( pos[ 1 ] )[ 0 ]
12122 ];
12123 });
12124
12125 // normalize collision option
12126 if ( collision.length === 1 ) {
12127 collision[ 1 ] = collision[ 0 ];
12128 }
12129
12130 if ( options.at[ 0 ] === "right" ) {
12131 basePosition.left += targetWidth;
12132 } else if ( options.at[ 0 ] === "center" ) {
12133 basePosition.left += targetWidth / 2;
12134 }
12135
12136 if ( options.at[ 1 ] === "bottom" ) {
12137 basePosition.top += targetHeight;
12138 } else if ( options.at[ 1 ] === "center" ) {
12139 basePosition.top += targetHeight / 2;
12140 }
12141
12142 atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
12143 basePosition.left += atOffset[ 0 ];
12144 basePosition.top += atOffset[ 1 ];
12145
12146 return this.each(function() {
12147 var collisionPosition, using,
12148 elem = $( this ),
12149 elemWidth = elem.outerWidth(),
12150 elemHeight = elem.outerHeight(),
12151 marginLeft = parseCss( this, "marginLeft" ),
12152 marginTop = parseCss( this, "marginTop" ),
12153 collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
12154 collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
12155 position = $.extend( {}, basePosition ),
12156 myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
12157
12158 if ( options.my[ 0 ] === "right" ) {
12159 position.left -= elemWidth;
12160 } else if ( options.my[ 0 ] === "center" ) {
12161 position.left -= elemWidth / 2;
12162 }
12163
12164 if ( options.my[ 1 ] === "bottom" ) {
12165 position.top -= elemHeight;
12166 } else if ( options.my[ 1 ] === "center" ) {
12167 position.top -= elemHeight / 2;
12168 }
12169
12170 position.left += myOffset[ 0 ];
12171 position.top += myOffset[ 1 ];
12172
12173 // if the browser doesn't support fractions, then round for consistent results
12174 if ( !$.support.offsetFractions ) {
12175 position.left = round( position.left );
12176 position.top = round( position.top );
12177 }
12178
12179 collisionPosition = {
12180 marginLeft: marginLeft,
12181 marginTop: marginTop
12182 };
12183
12184 $.each( [ "left", "top" ], function( i, dir ) {
12185 if ( $.ui.position[ collision[ i ] ] ) {
12186 $.ui.position[ collision[ i ] ][ dir ]( position, {
12187 targetWidth: targetWidth,
12188 targetHeight: targetHeight,
12189 elemWidth: elemWidth,
12190 elemHeight: elemHeight,
12191 collisionPosition: collisionPosition,
12192 collisionWidth: collisionWidth,
12193 collisionHeight: collisionHeight,
12194 offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
12195 my: options.my,
12196 at: options.at,
12197 within: within,
12198 elem : elem
12199 });
12200 }
12201 });
12202
12203 if ( options.using ) {
12204 // adds feedback as second argument to using callback, if present
12205 using = function( props ) {
12206 var left = targetOffset.left - position.left,
12207 right = left + targetWidth - elemWidth,
12208 top = targetOffset.top - position.top,
12209 bottom = top + targetHeight - elemHeight,
12210 feedback = {
12211 target: {
12212 element: target,
12213 left: targetOffset.left,
12214 top: targetOffset.top,
12215 width: targetWidth,
12216 height: targetHeight
12217 },
12218 element: {
12219 element: elem,
12220 left: position.left,
12221 top: position.top,
12222 width: elemWidth,
12223 height: elemHeight
12224 },
12225 horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
12226 vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
12227 };
12228 if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
12229 feedback.horizontal = "center";
12230 }
12231 if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
12232 feedback.vertical = "middle";
12233 }
12234 if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
12235 feedback.important = "horizontal";
12236 } else {
12237 feedback.important = "vertical";
12238 }
12239 options.using.call( this, props, feedback );
12240 };
12241 }
12242
12243 elem.offset( $.extend( position, { using: using } ) );
12244 });
12245};
12246
12247$.ui.position = {
12248 fit: {
12249 left: function( position, data ) {
12250 var within = data.within,
12251 withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
12252 outerWidth = within.width,
12253 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
12254 overLeft = withinOffset - collisionPosLeft,
12255 overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
12256 newOverRight;
12257
12258 // element is wider than within
12259 if ( data.collisionWidth > outerWidth ) {
12260 // element is initially over the left side of within
12261 if ( overLeft > 0 && overRight <= 0 ) {
12262 newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
12263 position.left += overLeft - newOverRight;
12264 // element is initially over right side of within
12265 } else if ( overRight > 0 && overLeft <= 0 ) {
12266 position.left = withinOffset;
12267 // element is initially over both left and right sides of within
12268 } else {
12269 if ( overLeft > overRight ) {
12270 position.left = withinOffset + outerWidth - data.collisionWidth;
12271 } else {
12272 position.left = withinOffset;
12273 }
12274 }
12275 // too far left -> align with left edge
12276 } else if ( overLeft > 0 ) {
12277 position.left += overLeft;
12278 // too far right -> align with right edge
12279 } else if ( overRight > 0 ) {
12280 position.left -= overRight;
12281 // adjust based on position and margin
12282 } else {
12283 position.left = max( position.left - collisionPosLeft, position.left );
12284 }
12285 },
12286 top: function( position, data ) {
12287 var within = data.within,
12288 withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
12289 outerHeight = data.within.height,
12290 collisionPosTop = position.top - data.collisionPosition.marginTop,
12291 overTop = withinOffset - collisionPosTop,
12292 overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
12293 newOverBottom;
12294
12295 // element is taller than within
12296 if ( data.collisionHeight > outerHeight ) {
12297 // element is initially over the top of within
12298 if ( overTop > 0 && overBottom <= 0 ) {
12299 newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
12300 position.top += overTop - newOverBottom;
12301 // element is initially over bottom of within
12302 } else if ( overBottom > 0 && overTop <= 0 ) {
12303 position.top = withinOffset;
12304 // element is initially over both top and bottom of within
12305 } else {
12306 if ( overTop > overBottom ) {
12307 position.top = withinOffset + outerHeight - data.collisionHeight;
12308 } else {
12309 position.top = withinOffset;
12310 }
12311 }
12312 // too far up -> align with top
12313 } else if ( overTop > 0 ) {
12314 position.top += overTop;
12315 // too far down -> align with bottom edge
12316 } else if ( overBottom > 0 ) {
12317 position.top -= overBottom;
12318 // adjust based on position and margin
12319 } else {
12320 position.top = max( position.top - collisionPosTop, position.top );
12321 }
12322 }
12323 },
12324 flip: {
12325 left: function( position, data ) {
12326 var within = data.within,
12327 withinOffset = within.offset.left + within.scrollLeft,
12328 outerWidth = within.width,
12329 offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
12330 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
12331 overLeft = collisionPosLeft - offsetLeft,
12332 overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
12333 myOffset = data.my[ 0 ] === "left" ?
12334 -data.elemWidth :
12335 data.my[ 0 ] === "right" ?
12336 data.elemWidth :
12337 0,
12338 atOffset = data.at[ 0 ] === "left" ?
12339 data.targetWidth :
12340 data.at[ 0 ] === "right" ?
12341 -data.targetWidth :
12342 0,
12343 offset = -2 * data.offset[ 0 ],
12344 newOverRight,
12345 newOverLeft;
12346
12347 if ( overLeft < 0 ) {
12348 newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
12349 if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
12350 position.left += myOffset + atOffset + offset;
12351 }
12352 }
12353 else if ( overRight > 0 ) {
12354 newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
12355 if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
12356 position.left += myOffset + atOffset + offset;
12357 }
12358 }
12359 },
12360 top: function( position, data ) {
12361 var within = data.within,
12362 withinOffset = within.offset.top + within.scrollTop,
12363 outerHeight = within.height,
12364 offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
12365 collisionPosTop = position.top - data.collisionPosition.marginTop,
12366 overTop = collisionPosTop - offsetTop,
12367 overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
12368 top = data.my[ 1 ] === "top",
12369 myOffset = top ?
12370 -data.elemHeight :
12371 data.my[ 1 ] === "bottom" ?
12372 data.elemHeight :
12373 0,
12374 atOffset = data.at[ 1 ] === "top" ?
12375 data.targetHeight :
12376 data.at[ 1 ] === "bottom" ?
12377 -data.targetHeight :
12378 0,
12379 offset = -2 * data.offset[ 1 ],
12380 newOverTop,
12381 newOverBottom;
12382 if ( overTop < 0 ) {
12383 newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
12384 if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) {
12385 position.top += myOffset + atOffset + offset;
12386 }
12387 }
12388 else if ( overBottom > 0 ) {
12389 newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
12390 if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) {
12391 position.top += myOffset + atOffset + offset;
12392 }
12393 }
12394 }
12395 },
12396 flipfit: {
12397 left: function() {
12398 $.ui.position.flip.left.apply( this, arguments );
12399 $.ui.position.fit.left.apply( this, arguments );
12400 },
12401 top: function() {
12402 $.ui.position.flip.top.apply( this, arguments );
12403 $.ui.position.fit.top.apply( this, arguments );
12404 }
12405 }
12406};
12407
12408// fraction support test
12409(function () {
12410 var testElement, testElementParent, testElementStyle, offsetLeft, i,
12411 body = document.getElementsByTagName( "body" )[ 0 ],
12412 div = document.createElement( "div" );
12413
12414 //Create a "fake body" for testing based on method used in jQuery.support
12415 testElement = document.createElement( body ? "div" : "body" );
12416 testElementStyle = {
12417 visibility: "hidden",
12418 width: 0,
12419 height: 0,
12420 border: 0,
12421 margin: 0,
12422 background: "none"
12423 };
12424 if ( body ) {
12425 $.extend( testElementStyle, {
12426 position: "absolute",
12427 left: "-1000px",
12428 top: "-1000px"
12429 });
12430 }
12431 for ( i in testElementStyle ) {
12432 testElement.style[ i ] = testElementStyle[ i ];
12433 }
12434 testElement.appendChild( div );
12435 testElementParent = body || document.documentElement;
12436 testElementParent.insertBefore( testElement, testElementParent.firstChild );
12437
12438 div.style.cssText = "position: absolute; left: 10.7432222px;";
12439
12440 offsetLeft = $( div ).offset().left;
12441 $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11;
12442
12443 testElement.innerHTML = "";
12444 testElementParent.removeChild( testElement );
12445})();
12446
12447}( jQuery ) );
12448
12449(function( $, undefined ) {
12450
12451$.widget( "ui.progressbar", {
12452 version: "1.10.1",
12453 options: {
12454 max: 100,
12455 value: 0,
12456
12457 change: null,
12458 complete: null
12459 },
12460
12461 min: 0,
12462
12463 _create: function() {
12464 // Constrain initial value
12465 this.oldValue = this.options.value = this._constrainedValue();
12466
12467 this.element
12468 .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
12469 .attr({
12470 // Only set static values, aria-valuenow and aria-valuemax are
12471 // set inside _refreshValue()
12472 role: "progressbar",
12473 "aria-valuemin": this.min
12474 });
12475
12476 this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
12477 .appendTo( this.element );
12478
12479 this._refreshValue();
12480 },
12481
12482 _destroy: function() {
12483 this.element
12484 .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
12485 .removeAttr( "role" )
12486 .removeAttr( "aria-valuemin" )
12487 .removeAttr( "aria-valuemax" )
12488 .removeAttr( "aria-valuenow" );
12489
12490 this.valueDiv.remove();
12491 },
12492
12493 value: function( newValue ) {
12494 if ( newValue === undefined ) {
12495 return this.options.value;
12496 }
12497
12498 this.options.value = this._constrainedValue( newValue );
12499 this._refreshValue();
12500 },
12501
12502 _constrainedValue: function( newValue ) {
12503 if ( newValue === undefined ) {
12504 newValue = this.options.value;
12505 }
12506
12507 this.indeterminate = newValue === false;
12508
12509 // sanitize value
12510 if ( typeof newValue !== "number" ) {
12511 newValue = 0;
12512 }
12513
12514 return this.indeterminate ? false :
12515 Math.min( this.options.max, Math.max( this.min, newValue ) );
12516 },
12517
12518 _setOptions: function( options ) {
12519 // Ensure "value" option is set after other values (like max)
12520 var value = options.value;
12521 delete options.value;
12522
12523 this._super( options );
12524
12525 this.options.value = this._constrainedValue( value );
12526 this._refreshValue();
12527 },
12528
12529 _setOption: function( key, value ) {
12530 if ( key === "max" ) {
12531 // Don't allow a max less than min
12532 value = Math.max( this.min, value );
12533 }
12534
12535 this._super( key, value );
12536 },
12537
12538 _percentage: function() {
12539 return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
12540 },
12541
12542 _refreshValue: function() {
12543 var value = this.options.value,
12544 percentage = this._percentage();
12545
12546 this.valueDiv
12547 .toggle( this.indeterminate || value > this.min )
12548 .toggleClass( "ui-corner-right", value === this.options.max )
12549 .width( percentage.toFixed(0) + "%" );
12550
12551 this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate );
12552
12553 if ( this.indeterminate ) {
12554 this.element.removeAttr( "aria-valuenow" );
12555 if ( !this.overlayDiv ) {
12556 this.overlayDiv = $( "<div class='ui-progressbar-overlay'></div>" ).appendTo( this.valueDiv );
12557 }
12558 } else {
12559 this.element.attr({
12560 "aria-valuemax": this.options.max,
12561 "aria-valuenow": value
12562 });
12563 if ( this.overlayDiv ) {
12564 this.overlayDiv.remove();
12565 this.overlayDiv = null;
12566 }
12567 }
12568
12569 if ( this.oldValue !== value ) {
12570 this.oldValue = value;
12571 this._trigger( "change" );
12572 }
12573 if ( value === this.options.max ) {
12574 this._trigger( "complete" );
12575 }
12576 }
12577});
12578
12579})( jQuery );
12580
12581(function( $, undefined ) {
12582
12583// number of pages in a slider
12584// (how many times can you page up/down to go through the whole range)
12585var numPages = 5;
12586
12587$.widget( "ui.slider", $.ui.mouse, {
12588 version: "1.10.1",
12589 widgetEventPrefix: "slide",
12590
12591 options: {
12592 animate: false,
12593 distance: 0,
12594 max: 100,
12595 min: 0,
12596 orientation: "horizontal",
12597 range: false,
12598 step: 1,
12599 value: 0,
12600 values: null,
12601
12602 // callbacks
12603 change: null,
12604 slide: null,
12605 start: null,
12606 stop: null
12607 },
12608
12609 _create: function() {
12610 this._keySliding = false;
12611 this._mouseSliding = false;
12612 this._animateOff = true;
12613 this._handleIndex = null;
12614 this._detectOrientation();
12615 this._mouseInit();
12616
12617 this.element
12618 .addClass( "ui-slider" +
12619 " ui-slider-" + this.orientation +
12620 " ui-widget" +
12621 " ui-widget-content" +
12622 " ui-corner-all");
12623
12624 this._refresh();
12625 this._setOption( "disabled", this.options.disabled );
12626
12627 this._animateOff = false;
12628 },
12629
12630 _refresh: function() {
12631 this._createRange();
12632 this._createHandles();
12633 this._setupEvents();
12634 this._refreshValue();
12635 },
12636
12637 _createHandles: function() {
12638 var i, handleCount,
12639 options = this.options,
12640 existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
12641 handle = "<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",
12642 handles = [];
12643
12644 handleCount = ( options.values && options.values.length ) || 1;
12645
12646 if ( existingHandles.length > handleCount ) {
12647 existingHandles.slice( handleCount ).remove();
12648 existingHandles = existingHandles.slice( 0, handleCount );
12649 }
12650
12651 for ( i = existingHandles.length; i < handleCount; i++ ) {
12652 handles.push( handle );
12653 }
12654
12655 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
12656
12657 this.handle = this.handles.eq( 0 );
12658
12659 this.handles.each(function( i ) {
12660 $( this ).data( "ui-slider-handle-index", i );
12661 });
12662 },
12663
12664 _createRange: function() {
12665 var options = this.options,
12666 classes = "";
12667
12668 if ( options.range ) {
12669 if ( options.range === true ) {
12670 if ( !options.values ) {
12671 options.values = [ this._valueMin(), this._valueMin() ];
12672 } else if ( options.values.length && options.values.length !== 2 ) {
12673 options.values = [ options.values[0], options.values[0] ];
12674 } else if ( $.isArray( options.values ) ) {
12675 options.values = options.values.slice(0);
12676 }
12677 }
12678
12679 if ( !this.range || !this.range.length ) {
12680 this.range = $( "<div></div>" )
12681 .appendTo( this.element );
12682
12683 classes = "ui-slider-range" +
12684 // note: this isn't the most fittingly semantic framework class for this element,
12685 // but worked best visually with a variety of themes
12686 " ui-widget-header ui-corner-all";
12687 } else {
12688 this.range.removeClass( "ui-slider-range-min ui-slider-range-max" )
12689 // Handle range switching from true to min/max
12690 .css({
12691 "left": "",
12692 "bottom": ""
12693 });
12694 }
12695
12696 this.range.addClass( classes +
12697 ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) );
12698 } else {
12699 this.range = $([]);
12700 }
12701 },
12702
12703 _setupEvents: function() {
12704 var elements = this.handles.add( this.range ).filter( "a" );
12705 this._off( elements );
12706 this._on( elements, this._handleEvents );
12707 this._hoverable( elements );
12708 this._focusable( elements );
12709 },
12710
12711 _destroy: function() {
12712 this.handles.remove();
12713 this.range.remove();
12714
12715 this.element
12716 .removeClass( "ui-slider" +
12717 " ui-slider-horizontal" +
12718 " ui-slider-vertical" +
12719 " ui-widget" +
12720 " ui-widget-content" +
12721 " ui-corner-all" );
12722
12723 this._mouseDestroy();
12724 },
12725
12726 _mouseCapture: function( event ) {
12727 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
12728 that = this,
12729 o = this.options;
12730
12731 if ( o.disabled ) {
12732 return false;
12733 }
12734
12735 this.elementSize = {
12736 width: this.element.outerWidth(),
12737 height: this.element.outerHeight()
12738 };
12739 this.elementOffset = this.element.offset();
12740
12741 position = { x: event.pageX, y: event.pageY };
12742 normValue = this._normValueFromMouse( position );
12743 distance = this._valueMax() - this._valueMin() + 1;
12744 this.handles.each(function( i ) {
12745 var thisDistance = Math.abs( normValue - that.values(i) );
12746 if (( distance > thisDistance ) ||
12747 ( distance === thisDistance &&
12748 (i === that._lastChangedValue || that.values(i) === o.min ))) {
12749 distance = thisDistance;
12750 closestHandle = $( this );
12751 index = i;
12752 }
12753 });
12754
12755 allowed = this._start( event, index );
12756 if ( allowed === false ) {
12757 return false;
12758 }
12759 this._mouseSliding = true;
12760
12761 this._handleIndex = index;
12762
12763 closestHandle
12764 .addClass( "ui-state-active" )
12765 .focus();
12766
12767 offset = closestHandle.offset();
12768 mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
12769 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
12770 left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
12771 top: event.pageY - offset.top -
12772 ( closestHandle.height() / 2 ) -
12773 ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
12774 ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
12775 ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
12776 };
12777
12778 if ( !this.handles.hasClass( "ui-state-hover" ) ) {
12779 this._slide( event, index, normValue );
12780 }
12781 this._animateOff = true;
12782 return true;
12783 },
12784
12785 _mouseStart: function() {
12786 return true;
12787 },
12788
12789 _mouseDrag: function( event ) {
12790 var position = { x: event.pageX, y: event.pageY },
12791 normValue = this._normValueFromMouse( position );
12792
12793 this._slide( event, this._handleIndex, normValue );
12794
12795 return false;
12796 },
12797
12798 _mouseStop: function( event ) {
12799 this.handles.removeClass( "ui-state-active" );
12800 this._mouseSliding = false;
12801
12802 this._stop( event, this._handleIndex );
12803 this._change( event, this._handleIndex );
12804
12805 this._handleIndex = null;
12806 this._clickOffset = null;
12807 this._animateOff = false;
12808
12809 return false;
12810 },
12811
12812 _detectOrientation: function() {
12813 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
12814 },
12815
12816 _normValueFromMouse: function( position ) {
12817 var pixelTotal,
12818 pixelMouse,
12819 percentMouse,
12820 valueTotal,
12821 valueMouse;
12822
12823 if ( this.orientation === "horizontal" ) {
12824 pixelTotal = this.elementSize.width;
12825 pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
12826 } else {
12827 pixelTotal = this.elementSize.height;
12828 pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
12829 }
12830
12831 percentMouse = ( pixelMouse / pixelTotal );
12832 if ( percentMouse > 1 ) {
12833 percentMouse = 1;
12834 }
12835 if ( percentMouse < 0 ) {
12836 percentMouse = 0;
12837 }
12838 if ( this.orientation === "vertical" ) {
12839 percentMouse = 1 - percentMouse;
12840 }
12841
12842 valueTotal = this._valueMax() - this._valueMin();
12843 valueMouse = this._valueMin() + percentMouse * valueTotal;
12844
12845 return this._trimAlignValue( valueMouse );
12846 },
12847
12848 _start: function( event, index ) {
12849 var uiHash = {
12850 handle: this.handles[ index ],
12851 value: this.value()
12852 };
12853 if ( this.options.values && this.options.values.length ) {
12854 uiHash.value = this.values( index );
12855 uiHash.values = this.values();
12856 }
12857 return this._trigger( "start", event, uiHash );
12858 },
12859
12860 _slide: function( event, index, newVal ) {
12861 var otherVal,
12862 newValues,
12863 allowed;
12864
12865 if ( this.options.values && this.options.values.length ) {
12866 otherVal = this.values( index ? 0 : 1 );
12867
12868 if ( ( this.options.values.length === 2 && this.options.range === true ) &&
12869 ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
12870 ) {
12871 newVal = otherVal;
12872 }
12873
12874 if ( newVal !== this.values( index ) ) {
12875 newValues = this.values();
12876 newValues[ index ] = newVal;
12877 // A slide can be canceled by returning false from the slide callback
12878 allowed = this._trigger( "slide", event, {
12879 handle: this.handles[ index ],
12880 value: newVal,
12881 values: newValues
12882 } );
12883 otherVal = this.values( index ? 0 : 1 );
12884 if ( allowed !== false ) {
12885 this.values( index, newVal, true );
12886 }
12887 }
12888 } else {
12889 if ( newVal !== this.value() ) {
12890 // A slide can be canceled by returning false from the slide callback
12891 allowed = this._trigger( "slide", event, {
12892 handle: this.handles[ index ],
12893 value: newVal
12894 } );
12895 if ( allowed !== false ) {
12896 this.value( newVal );
12897 }
12898 }
12899 }
12900 },
12901
12902 _stop: function( event, index ) {
12903 var uiHash = {
12904 handle: this.handles[ index ],
12905 value: this.value()
12906 };
12907 if ( this.options.values && this.options.values.length ) {
12908 uiHash.value = this.values( index );
12909 uiHash.values = this.values();
12910 }
12911
12912 this._trigger( "stop", event, uiHash );
12913 },
12914
12915 _change: function( event, index ) {
12916 if ( !this._keySliding && !this._mouseSliding ) {
12917 var uiHash = {
12918 handle: this.handles[ index ],
12919 value: this.value()
12920 };
12921 if ( this.options.values && this.options.values.length ) {
12922 uiHash.value = this.values( index );
12923 uiHash.values = this.values();
12924 }
12925
12926 //store the last changed value index for reference when handles overlap
12927 this._lastChangedValue = index;
12928
12929 this._trigger( "change", event, uiHash );
12930 }
12931 },
12932
12933 value: function( newValue ) {
12934 if ( arguments.length ) {
12935 this.options.value = this._trimAlignValue( newValue );
12936 this._refreshValue();
12937 this._change( null, 0 );
12938 return;
12939 }
12940
12941 return this._value();
12942 },
12943
12944 values: function( index, newValue ) {
12945 var vals,
12946 newValues,
12947 i;
12948
12949 if ( arguments.length > 1 ) {
12950 this.options.values[ index ] = this._trimAlignValue( newValue );
12951 this._refreshValue();
12952 this._change( null, index );
12953 return;
12954 }
12955
12956 if ( arguments.length ) {
12957 if ( $.isArray( arguments[ 0 ] ) ) {
12958 vals = this.options.values;
12959 newValues = arguments[ 0 ];
12960 for ( i = 0; i < vals.length; i += 1 ) {
12961 vals[ i ] = this._trimAlignValue( newValues[ i ] );
12962 this._change( null, i );
12963 }
12964 this._refreshValue();
12965 } else {
12966 if ( this.options.values && this.options.values.length ) {
12967 return this._values( index );
12968 } else {
12969 return this.value();
12970 }
12971 }
12972 } else {
12973 return this._values();
12974 }
12975 },
12976
12977 _setOption: function( key, value ) {
12978 var i,
12979 valsLength = 0;
12980
12981 if ( key === "range" && this.options.range === true ) {
12982 if ( value === "min" ) {
12983 this.options.value = this._values( 0 );
12984 this.options.values = null;
12985 } else if ( value === "max" ) {
12986 this.options.value = this._values( this.options.values.length-1 );
12987 this.options.values = null;
12988 }
12989 }
12990
12991 if ( $.isArray( this.options.values ) ) {
12992 valsLength = this.options.values.length;
12993 }
12994
12995 $.Widget.prototype._setOption.apply( this, arguments );
12996
12997 switch ( key ) {
12998 case "orientation":
12999 this._detectOrientation();
13000 this.element
13001 .removeClass( "ui-slider-horizontal ui-slider-vertical" )
13002 .addClass( "ui-slider-" + this.orientation );
13003 this._refreshValue();
13004 break;
13005 case "value":
13006 this._animateOff = true;
13007 this._refreshValue();
13008 this._change( null, 0 );
13009 this._animateOff = false;
13010 break;
13011 case "values":
13012 this._animateOff = true;
13013 this._refreshValue();
13014 for ( i = 0; i < valsLength; i += 1 ) {
13015 this._change( null, i );
13016 }
13017 this._animateOff = false;
13018 break;
13019 case "min":
13020 case "max":
13021 this._animateOff = true;
13022 this._refreshValue();
13023 this._animateOff = false;
13024 break;
13025 case "range":
13026 this._animateOff = true;
13027 this._refresh();
13028 this._animateOff = false;
13029 break;
13030 }
13031 },
13032
13033 //internal value getter
13034 // _value() returns value trimmed by min and max, aligned by step
13035 _value: function() {
13036 var val = this.options.value;
13037 val = this._trimAlignValue( val );
13038
13039 return val;
13040 },
13041
13042 //internal values getter
13043 // _values() returns array of values trimmed by min and max, aligned by step
13044 // _values( index ) returns single value trimmed by min and max, aligned by step
13045 _values: function( index ) {
13046 var val,
13047 vals,
13048 i;
13049
13050 if ( arguments.length ) {
13051 val = this.options.values[ index ];
13052 val = this._trimAlignValue( val );
13053
13054 return val;
13055 } else if ( this.options.values && this.options.values.length ) {
13056 // .slice() creates a copy of the array
13057 // this copy gets trimmed by min and max and then returned
13058 vals = this.options.values.slice();
13059 for ( i = 0; i < vals.length; i+= 1) {
13060 vals[ i ] = this._trimAlignValue( vals[ i ] );
13061 }
13062
13063 return vals;
13064 } else {
13065 return [];
13066 }
13067 },
13068
13069 // returns the step-aligned value that val is closest to, between (inclusive) min and max
13070 _trimAlignValue: function( val ) {
13071 if ( val <= this._valueMin() ) {
13072 return this._valueMin();
13073 }
13074 if ( val >= this._valueMax() ) {
13075 return this._valueMax();
13076 }
13077 var step = ( this.options.step > 0 ) ? this.options.step : 1,
13078 valModStep = (val - this._valueMin()) % step,
13079 alignValue = val - valModStep;
13080
13081 if ( Math.abs(valModStep) * 2 >= step ) {
13082 alignValue += ( valModStep > 0 ) ? step : ( -step );
13083 }
13084
13085 // Since JavaScript has problems with large floats, round
13086 // the final value to 5 digits after the decimal point (see #4124)
13087 return parseFloat( alignValue.toFixed(5) );
13088 },
13089
13090 _valueMin: function() {
13091 return this.options.min;
13092 },
13093
13094 _valueMax: function() {
13095 return this.options.max;
13096 },
13097
13098 _refreshValue: function() {
13099 var lastValPercent, valPercent, value, valueMin, valueMax,
13100 oRange = this.options.range,
13101 o = this.options,
13102 that = this,
13103 animate = ( !this._animateOff ) ? o.animate : false,
13104 _set = {};
13105
13106 if ( this.options.values && this.options.values.length ) {
13107 this.handles.each(function( i ) {
13108 valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
13109 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
13110 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
13111 if ( that.options.range === true ) {
13112 if ( that.orientation === "horizontal" ) {
13113 if ( i === 0 ) {
13114 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
13115 }
13116 if ( i === 1 ) {
13117 that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
13118 }
13119 } else {
13120 if ( i === 0 ) {
13121 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
13122 }
13123 if ( i === 1 ) {
13124 that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
13125 }
13126 }
13127 }
13128 lastValPercent = valPercent;
13129 });
13130 } else {
13131 value = this.value();
13132 valueMin = this._valueMin();
13133 valueMax = this._valueMax();
13134 valPercent = ( valueMax !== valueMin ) ?
13135 ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
13136 0;
13137 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
13138 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
13139
13140 if ( oRange === "min" && this.orientation === "horizontal" ) {
13141 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
13142 }
13143 if ( oRange === "max" && this.orientation === "horizontal" ) {
13144 this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
13145 }
13146 if ( oRange === "min" && this.orientation === "vertical" ) {
13147 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
13148 }
13149 if ( oRange === "max" && this.orientation === "vertical" ) {
13150 this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
13151 }
13152 }
13153 },
13154
13155 _handleEvents: {
13156 keydown: function( event ) {
13157 /*jshint maxcomplexity:25*/
13158 var allowed, curVal, newVal, step,
13159 index = $( event.target ).data( "ui-slider-handle-index" );
13160
13161 switch ( event.keyCode ) {
13162 case $.ui.keyCode.HOME:
13163 case $.ui.keyCode.END:
13164 case $.ui.keyCode.PAGE_UP:
13165 case $.ui.keyCode.PAGE_DOWN:
13166 case $.ui.keyCode.UP:
13167 case $.ui.keyCode.RIGHT:
13168 case $.ui.keyCode.DOWN:
13169 case $.ui.keyCode.LEFT:
13170 event.preventDefault();
13171 if ( !this._keySliding ) {
13172 this._keySliding = true;
13173 $( event.target ).addClass( "ui-state-active" );
13174 allowed = this._start( event, index );
13175 if ( allowed === false ) {
13176 return;
13177 }
13178 }
13179 break;
13180 }
13181
13182 step = this.options.step;
13183 if ( this.options.values && this.options.values.length ) {
13184 curVal = newVal = this.values( index );
13185 } else {
13186 curVal = newVal = this.value();
13187 }
13188
13189 switch ( event.keyCode ) {
13190 case $.ui.keyCode.HOME:
13191 newVal = this._valueMin();
13192 break;
13193 case $.ui.keyCode.END:
13194 newVal = this._valueMax();
13195 break;
13196 case $.ui.keyCode.PAGE_UP:
13197 newVal = this._trimAlignValue( curVal + ( (this._valueMax() - this._valueMin()) / numPages ) );
13198 break;
13199 case $.ui.keyCode.PAGE_DOWN:
13200 newVal = this._trimAlignValue( curVal - ( (this._valueMax() - this._valueMin()) / numPages ) );
13201 break;
13202 case $.ui.keyCode.UP:
13203 case $.ui.keyCode.RIGHT:
13204 if ( curVal === this._valueMax() ) {
13205 return;
13206 }
13207 newVal = this._trimAlignValue( curVal + step );
13208 break;
13209 case $.ui.keyCode.DOWN:
13210 case $.ui.keyCode.LEFT:
13211 if ( curVal === this._valueMin() ) {
13212 return;
13213 }
13214 newVal = this._trimAlignValue( curVal - step );
13215 break;
13216 }
13217
13218 this._slide( event, index, newVal );
13219 },
13220 click: function( event ) {
13221 event.preventDefault();
13222 },
13223 keyup: function( event ) {
13224 var index = $( event.target ).data( "ui-slider-handle-index" );
13225
13226 if ( this._keySliding ) {
13227 this._keySliding = false;
13228 this._stop( event, index );
13229 this._change( event, index );
13230 $( event.target ).removeClass( "ui-state-active" );
13231 }
13232 }
13233 }
13234
13235});
13236
13237}(jQuery));
13238
13239(function( $ ) {
13240
13241function modifier( fn ) {
13242 return function() {
13243 var previous = this.element.val();
13244 fn.apply( this, arguments );
13245 this._refresh();
13246 if ( previous !== this.element.val() ) {
13247 this._trigger( "change" );
13248 }
13249 };
13250}
13251
13252$.widget( "ui.spinner", {
13253 version: "1.10.1",
13254 defaultElement: "<input>",
13255 widgetEventPrefix: "spin",
13256 options: {
13257 culture: null,
13258 icons: {
13259 down: "ui-icon-triangle-1-s",
13260 up: "ui-icon-triangle-1-n"
13261 },
13262 incremental: true,
13263 max: null,
13264 min: null,
13265 numberFormat: null,
13266 page: 10,
13267 step: 1,
13268
13269 change: null,
13270 spin: null,
13271 start: null,
13272 stop: null
13273 },
13274
13275 _create: function() {
13276 // handle string values that need to be parsed
13277 this._setOption( "max", this.options.max );
13278 this._setOption( "min", this.options.min );
13279 this._setOption( "step", this.options.step );
13280
13281 // format the value, but don't constrain
13282 this._value( this.element.val(), true );
13283
13284 this._draw();
13285 this._on( this._events );
13286 this._refresh();
13287
13288 // turning off autocomplete prevents the browser from remembering the
13289 // value when navigating through history, so we re-enable autocomplete
13290 // if the page is unloaded before the widget is destroyed. #7790
13291 this._on( this.window, {
13292 beforeunload: function() {
13293 this.element.removeAttr( "autocomplete" );
13294 }
13295 });
13296 },
13297
13298 _getCreateOptions: function() {
13299 var options = {},
13300 element = this.element;
13301
13302 $.each( [ "min", "max", "step" ], function( i, option ) {
13303 var value = element.attr( option );
13304 if ( value !== undefined && value.length ) {
13305 options[ option ] = value;
13306 }
13307 });
13308
13309 return options;
13310 },
13311
13312 _events: {
13313 keydown: function( event ) {
13314 if ( this._start( event ) && this._keydown( event ) ) {
13315 event.preventDefault();
13316 }
13317 },
13318 keyup: "_stop",
13319 focus: function() {
13320 this.previous = this.element.val();
13321 },
13322 blur: function( event ) {
13323 if ( this.cancelBlur ) {
13324 delete this.cancelBlur;
13325 return;
13326 }
13327
13328 this._refresh();
13329 if ( this.previous !== this.element.val() ) {
13330 this._trigger( "change", event );
13331 }
13332 },
13333 mousewheel: function( event, delta ) {
13334 if ( !delta ) {
13335 return;
13336 }
13337 if ( !this.spinning && !this._start( event ) ) {
13338 return false;
13339 }
13340
13341 this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
13342 clearTimeout( this.mousewheelTimer );
13343 this.mousewheelTimer = this._delay(function() {
13344 if ( this.spinning ) {
13345 this._stop( event );
13346 }
13347 }, 100 );
13348 event.preventDefault();
13349 },
13350 "mousedown .ui-spinner-button": function( event ) {
13351 var previous;
13352
13353 // We never want the buttons to have focus; whenever the user is
13354 // interacting with the spinner, the focus should be on the input.
13355 // If the input is focused then this.previous is properly set from
13356 // when the input first received focus. If the input is not focused
13357 // then we need to set this.previous based on the value before spinning.
13358 previous = this.element[0] === this.document[0].activeElement ?
13359 this.previous : this.element.val();
13360 function checkFocus() {
13361 var isActive = this.element[0] === this.document[0].activeElement;
13362 if ( !isActive ) {
13363 this.element.focus();
13364 this.previous = previous;
13365 // support: IE
13366 // IE sets focus asynchronously, so we need to check if focus
13367 // moved off of the input because the user clicked on the button.
13368 this._delay(function() {
13369 this.previous = previous;
13370 });
13371 }
13372 }
13373
13374 // ensure focus is on (or stays on) the text field
13375 event.preventDefault();
13376 checkFocus.call( this );
13377
13378 // support: IE
13379 // IE doesn't prevent moving focus even with event.preventDefault()
13380 // so we set a flag to know when we should ignore the blur event
13381 // and check (again) if focus moved off of the input.
13382 this.cancelBlur = true;
13383 this._delay(function() {
13384 delete this.cancelBlur;
13385 checkFocus.call( this );
13386 });
13387
13388 if ( this._start( event ) === false ) {
13389 return;
13390 }
13391
13392 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
13393 },
13394 "mouseup .ui-spinner-button": "_stop",
13395 "mouseenter .ui-spinner-button": function( event ) {
13396 // button will add ui-state-active if mouse was down while mouseleave and kept down
13397 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
13398 return;
13399 }
13400
13401 if ( this._start( event ) === false ) {
13402 return false;
13403 }
13404 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
13405 },
13406 // TODO: do we really want to consider this a stop?
13407 // shouldn't we just stop the repeater and wait until mouseup before
13408 // we trigger the stop event?
13409 "mouseleave .ui-spinner-button": "_stop"
13410 },
13411
13412 _draw: function() {
13413 var uiSpinner = this.uiSpinner = this.element
13414 .addClass( "ui-spinner-input" )
13415 .attr( "autocomplete", "off" )
13416 .wrap( this._uiSpinnerHtml() )
13417 .parent()
13418 // add buttons
13419 .append( this._buttonHtml() );
13420
13421 this.element.attr( "role", "spinbutton" );
13422
13423 // button bindings
13424 this.buttons = uiSpinner.find( ".ui-spinner-button" )
13425 .attr( "tabIndex", -1 )
13426 .button()
13427 .removeClass( "ui-corner-all" );
13428
13429 // IE 6 doesn't understand height: 50% for the buttons
13430 // unless the wrapper has an explicit height
13431 if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&
13432 uiSpinner.height() > 0 ) {
13433 uiSpinner.height( uiSpinner.height() );
13434 }
13435
13436 // disable spinner if element was already disabled
13437 if ( this.options.disabled ) {
13438 this.disable();
13439 }
13440 },
13441
13442 _keydown: function( event ) {
13443 var options = this.options,
13444 keyCode = $.ui.keyCode;
13445
13446 switch ( event.keyCode ) {
13447 case keyCode.UP:
13448 this._repeat( null, 1, event );
13449 return true;
13450 case keyCode.DOWN:
13451 this._repeat( null, -1, event );
13452 return true;
13453 case keyCode.PAGE_UP:
13454 this._repeat( null, options.page, event );
13455 return true;
13456 case keyCode.PAGE_DOWN:
13457 this._repeat( null, -options.page, event );
13458 return true;
13459 }
13460
13461 return false;
13462 },
13463
13464 _uiSpinnerHtml: function() {
13465 return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>";
13466 },
13467
13468 _buttonHtml: function() {
13469 return "" +
13470 "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" +
13471 "<span class='ui-icon " + this.options.icons.up + "'>&#9650;</span>" +
13472 "</a>" +
13473 "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" +
13474 "<span class='ui-icon " + this.options.icons.down + "'>&#9660;</span>" +
13475 "</a>";
13476 },
13477
13478 _start: function( event ) {
13479 if ( !this.spinning && this._trigger( "start", event ) === false ) {
13480 return false;
13481 }
13482
13483 if ( !this.counter ) {
13484 this.counter = 1;
13485 }
13486 this.spinning = true;
13487 return true;
13488 },
13489
13490 _repeat: function( i, steps, event ) {
13491 i = i || 500;
13492
13493 clearTimeout( this.timer );
13494 this.timer = this._delay(function() {
13495 this._repeat( 40, steps, event );
13496 }, i );
13497
13498 this._spin( steps * this.options.step, event );
13499 },
13500
13501 _spin: function( step, event ) {
13502 var value = this.value() || 0;
13503
13504 if ( !this.counter ) {
13505 this.counter = 1;
13506 }
13507
13508 value = this._adjustValue( value + step * this._increment( this.counter ) );
13509
13510 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) {
13511 this._value( value );
13512 this.counter++;
13513 }
13514 },
13515
13516 _increment: function( i ) {
13517 var incremental = this.options.incremental;
13518
13519 if ( incremental ) {
13520 return $.isFunction( incremental ) ?
13521 incremental( i ) :
13522 Math.floor( i*i*i/50000 - i*i/500 + 17*i/200 + 1 );
13523 }
13524
13525 return 1;
13526 },
13527
13528 _precision: function() {
13529 var precision = this._precisionOf( this.options.step );
13530 if ( this.options.min !== null ) {
13531 precision = Math.max( precision, this._precisionOf( this.options.min ) );
13532 }
13533 return precision;
13534 },
13535
13536 _precisionOf: function( num ) {
13537 var str = num.toString(),
13538 decimal = str.indexOf( "." );
13539 return decimal === -1 ? 0 : str.length - decimal - 1;
13540 },
13541
13542 _adjustValue: function( value ) {
13543 var base, aboveMin,
13544 options = this.options;
13545
13546 // make sure we're at a valid step
13547 // - find out where we are relative to the base (min or 0)
13548 base = options.min !== null ? options.min : 0;
13549 aboveMin = value - base;
13550 // - round to the nearest step
13551 aboveMin = Math.round(aboveMin / options.step) * options.step;
13552 // - rounding is based on 0, so adjust back to our base
13553 value = base + aboveMin;
13554
13555 // fix precision from bad JS floating point math
13556 value = parseFloat( value.toFixed( this._precision() ) );
13557
13558 // clamp the value
13559 if ( options.max !== null && value > options.max) {
13560 return options.max;
13561 }
13562 if ( options.min !== null && value < options.min ) {
13563 return options.min;
13564 }
13565
13566 return value;
13567 },
13568
13569 _stop: function( event ) {
13570 if ( !this.spinning ) {
13571 return;
13572 }
13573
13574 clearTimeout( this.timer );
13575 clearTimeout( this.mousewheelTimer );
13576 this.counter = 0;
13577 this.spinning = false;
13578 this._trigger( "stop", event );
13579 },
13580
13581 _setOption: function( key, value ) {
13582 if ( key === "culture" || key === "numberFormat" ) {
13583 var prevValue = this._parse( this.element.val() );
13584 this.options[ key ] = value;
13585 this.element.val( this._format( prevValue ) );
13586 return;
13587 }
13588
13589 if ( key === "max" || key === "min" || key === "step" ) {
13590 if ( typeof value === "string" ) {
13591 value = this._parse( value );
13592 }
13593 }
13594 if ( key === "icons" ) {
13595 this.buttons.first().find( ".ui-icon" )
13596 .removeClass( this.options.icons.up )
13597 .addClass( value.up );
13598 this.buttons.last().find( ".ui-icon" )
13599 .removeClass( this.options.icons.down )
13600 .addClass( value.down );
13601 }
13602
13603 this._super( key, value );
13604
13605 if ( key === "disabled" ) {
13606 if ( value ) {
13607 this.element.prop( "disabled", true );
13608 this.buttons.button( "disable" );
13609 } else {
13610 this.element.prop( "disabled", false );
13611 this.buttons.button( "enable" );
13612 }
13613 }
13614 },
13615
13616 _setOptions: modifier(function( options ) {
13617 this._super( options );
13618 this._value( this.element.val() );
13619 }),
13620
13621 _parse: function( val ) {
13622 if ( typeof val === "string" && val !== "" ) {
13623 val = window.Globalize && this.options.numberFormat ?
13624 Globalize.parseFloat( val, 10, this.options.culture ) : +val;
13625 }
13626 return val === "" || isNaN( val ) ? null : val;
13627 },
13628
13629 _format: function( value ) {
13630 if ( value === "" ) {
13631 return "";
13632 }
13633 return window.Globalize && this.options.numberFormat ?
13634 Globalize.format( value, this.options.numberFormat, this.options.culture ) :
13635 value;
13636 },
13637
13638 _refresh: function() {
13639 this.element.attr({
13640 "aria-valuemin": this.options.min,
13641 "aria-valuemax": this.options.max,
13642 // TODO: what should we do with values that can't be parsed?
13643 "aria-valuenow": this._parse( this.element.val() )
13644 });
13645 },
13646
13647 // update the value without triggering change
13648 _value: function( value, allowAny ) {
13649 var parsed;
13650 if ( value !== "" ) {
13651 parsed = this._parse( value );
13652 if ( parsed !== null ) {
13653 if ( !allowAny ) {
13654 parsed = this._adjustValue( parsed );
13655 }
13656 value = this._format( parsed );
13657 }
13658 }
13659 this.element.val( value );
13660 this._refresh();
13661 },
13662
13663 _destroy: function() {
13664 this.element
13665 .removeClass( "ui-spinner-input" )
13666 .prop( "disabled", false )
13667 .removeAttr( "autocomplete" )
13668 .removeAttr( "role" )
13669 .removeAttr( "aria-valuemin" )
13670 .removeAttr( "aria-valuemax" )
13671 .removeAttr( "aria-valuenow" );
13672 this.uiSpinner.replaceWith( this.element );
13673 },
13674
13675 stepUp: modifier(function( steps ) {
13676 this._stepUp( steps );
13677 }),
13678 _stepUp: function( steps ) {
13679 if ( this._start() ) {
13680 this._spin( (steps || 1) * this.options.step );
13681 this._stop();
13682 }
13683 },
13684
13685 stepDown: modifier(function( steps ) {
13686 this._stepDown( steps );
13687 }),
13688 _stepDown: function( steps ) {
13689 if ( this._start() ) {
13690 this._spin( (steps || 1) * -this.options.step );
13691 this._stop();
13692 }
13693 },
13694
13695 pageUp: modifier(function( pages ) {
13696 this._stepUp( (pages || 1) * this.options.page );
13697 }),
13698
13699 pageDown: modifier(function( pages ) {
13700 this._stepDown( (pages || 1) * this.options.page );
13701 }),
13702
13703 value: function( newVal ) {
13704 if ( !arguments.length ) {
13705 return this._parse( this.element.val() );
13706 }
13707 modifier( this._value ).call( this, newVal );
13708 },
13709
13710 widget: function() {
13711 return this.uiSpinner;
13712 }
13713});
13714
13715}( jQuery ) );
13716
13717(function( $, undefined ) {
13718
13719var tabId = 0,
13720 rhash = /#.*$/;
13721
13722function getNextTabId() {
13723 return ++tabId;
13724}
13725
13726function isLocal( anchor ) {
13727 return anchor.hash.length > 1 &&
13728 decodeURIComponent( anchor.href.replace( rhash, "" ) ) ===
13729 decodeURIComponent( location.href.replace( rhash, "" ) );
13730}
13731
13732$.widget( "ui.tabs", {
13733 version: "1.10.1",
13734 delay: 300,
13735 options: {
13736 active: null,
13737 collapsible: false,
13738 event: "click",
13739 heightStyle: "content",
13740 hide: null,
13741 show: null,
13742
13743 // callbacks
13744 activate: null,
13745 beforeActivate: null,
13746 beforeLoad: null,
13747 load: null
13748 },
13749
13750 _create: function() {
13751 var that = this,
13752 options = this.options;
13753
13754 this.running = false;
13755
13756 this.element
13757 .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" )
13758 .toggleClass( "ui-tabs-collapsible", options.collapsible )
13759 // Prevent users from focusing disabled tabs via click
13760 .delegate( ".ui-tabs-nav > li", "mousedown" + this.eventNamespace, function( event ) {
13761 if ( $( this ).is( ".ui-state-disabled" ) ) {
13762 event.preventDefault();
13763 }
13764 })
13765 // support: IE <9
13766 // Preventing the default action in mousedown doesn't prevent IE
13767 // from focusing the element, so if the anchor gets focused, blur.
13768 // We don't have to worry about focusing the previously focused
13769 // element since clicking on a non-focusable element should focus
13770 // the body anyway.
13771 .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() {
13772 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
13773 this.blur();
13774 }
13775 });
13776
13777 this._processTabs();
13778 options.active = this._initialActive();
13779
13780 // Take disabling tabs via class attribute from HTML
13781 // into account and update option properly.
13782 if ( $.isArray( options.disabled ) ) {
13783 options.disabled = $.unique( options.disabled.concat(
13784 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
13785 return that.tabs.index( li );
13786 })
13787 ) ).sort();
13788 }
13789
13790 // check for length avoids error when initializing empty list
13791 if ( this.options.active !== false && this.anchors.length ) {
13792 this.active = this._findActive( options.active );
13793 } else {
13794 this.active = $();
13795 }
13796
13797 this._refresh();
13798
13799 if ( this.active.length ) {
13800 this.load( options.active );
13801 }
13802 },
13803
13804 _initialActive: function() {
13805 var active = this.options.active,
13806 collapsible = this.options.collapsible,
13807 locationHash = location.hash.substring( 1 );
13808
13809 if ( active === null ) {
13810 // check the fragment identifier in the URL
13811 if ( locationHash ) {
13812 this.tabs.each(function( i, tab ) {
13813 if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
13814 active = i;
13815 return false;
13816 }
13817 });
13818 }
13819
13820 // check for a tab marked active via a class
13821 if ( active === null ) {
13822 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
13823 }
13824
13825 // no active tab, set to false
13826 if ( active === null || active === -1 ) {
13827 active = this.tabs.length ? 0 : false;
13828 }
13829 }
13830
13831 // handle numbers: negative, out of range
13832 if ( active !== false ) {
13833 active = this.tabs.index( this.tabs.eq( active ) );
13834 if ( active === -1 ) {
13835 active = collapsible ? false : 0;
13836 }
13837 }
13838
13839 // don't allow collapsible: false and active: false
13840 if ( !collapsible && active === false && this.anchors.length ) {
13841 active = 0;
13842 }
13843
13844 return active;
13845 },
13846
13847 _getCreateEventData: function() {
13848 return {
13849 tab: this.active,
13850 panel: !this.active.length ? $() : this._getPanelForTab( this.active )
13851 };
13852 },
13853
13854 _tabKeydown: function( event ) {
13855 /*jshint maxcomplexity:15*/
13856 var focusedTab = $( this.document[0].activeElement ).closest( "li" ),
13857 selectedIndex = this.tabs.index( focusedTab ),
13858 goingForward = true;
13859
13860 if ( this._handlePageNav( event ) ) {
13861 return;
13862 }
13863
13864 switch ( event.keyCode ) {
13865 case $.ui.keyCode.RIGHT:
13866 case $.ui.keyCode.DOWN:
13867 selectedIndex++;
13868 break;
13869 case $.ui.keyCode.UP:
13870 case $.ui.keyCode.LEFT:
13871 goingForward = false;
13872 selectedIndex--;
13873 break;
13874 case $.ui.keyCode.END:
13875 selectedIndex = this.anchors.length - 1;
13876 break;
13877 case $.ui.keyCode.HOME:
13878 selectedIndex = 0;
13879 break;
13880 case $.ui.keyCode.SPACE:
13881 // Activate only, no collapsing
13882 event.preventDefault();
13883 clearTimeout( this.activating );
13884 this._activate( selectedIndex );
13885 return;
13886 case $.ui.keyCode.ENTER:
13887 // Toggle (cancel delayed activation, allow collapsing)
13888 event.preventDefault();
13889 clearTimeout( this.activating );
13890 // Determine if we should collapse or activate
13891 this._activate( selectedIndex === this.options.active ? false : selectedIndex );
13892 return;
13893 default:
13894 return;
13895 }
13896
13897 // Focus the appropriate tab, based on which key was pressed
13898 event.preventDefault();
13899 clearTimeout( this.activating );
13900 selectedIndex = this._focusNextTab( selectedIndex, goingForward );
13901
13902 // Navigating with control key will prevent automatic activation
13903 if ( !event.ctrlKey ) {
13904 // Update aria-selected immediately so that AT think the tab is already selected.
13905 // Otherwise AT may confuse the user by stating that they need to activate the tab,
13906 // but the tab will already be activated by the time the announcement finishes.
13907 focusedTab.attr( "aria-selected", "false" );
13908 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
13909
13910 this.activating = this._delay(function() {
13911 this.option( "active", selectedIndex );
13912 }, this.delay );
13913 }
13914 },
13915
13916 _panelKeydown: function( event ) {
13917 if ( this._handlePageNav( event ) ) {
13918 return;
13919 }
13920
13921 // Ctrl+up moves focus to the current tab
13922 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
13923 event.preventDefault();
13924 this.active.focus();
13925 }
13926 },
13927
13928 // Alt+page up/down moves focus to the previous/next tab (and activates)
13929 _handlePageNav: function( event ) {
13930 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
13931 this._activate( this._focusNextTab( this.options.active - 1, false ) );
13932 return true;
13933 }
13934 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
13935 this._activate( this._focusNextTab( this.options.active + 1, true ) );
13936 return true;
13937 }
13938 },
13939
13940 _findNextTab: function( index, goingForward ) {
13941 var lastTabIndex = this.tabs.length - 1;
13942
13943 function constrain() {
13944 if ( index > lastTabIndex ) {
13945 index = 0;
13946 }
13947 if ( index < 0 ) {
13948 index = lastTabIndex;
13949 }
13950 return index;
13951 }
13952
13953 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
13954 index = goingForward ? index + 1 : index - 1;
13955 }
13956
13957 return index;
13958 },
13959
13960 _focusNextTab: function( index, goingForward ) {
13961 index = this._findNextTab( index, goingForward );
13962 this.tabs.eq( index ).focus();
13963 return index;
13964 },
13965
13966 _setOption: function( key, value ) {
13967 if ( key === "active" ) {
13968 // _activate() will handle invalid values and update this.options
13969 this._activate( value );
13970 return;
13971 }
13972
13973 if ( key === "disabled" ) {
13974 // don't use the widget factory's disabled handling
13975 this._setupDisabled( value );
13976 return;
13977 }
13978
13979 this._super( key, value);
13980
13981 if ( key === "collapsible" ) {
13982 this.element.toggleClass( "ui-tabs-collapsible", value );
13983 // Setting collapsible: false while collapsed; open first panel
13984 if ( !value && this.options.active === false ) {
13985 this._activate( 0 );
13986 }
13987 }
13988
13989 if ( key === "event" ) {
13990 this._setupEvents( value );
13991 }
13992
13993 if ( key === "heightStyle" ) {
13994 this._setupHeightStyle( value );
13995 }
13996 },
13997
13998 _tabId: function( tab ) {
13999 return tab.attr( "aria-controls" ) || "ui-tabs-" + getNextTabId();
14000 },
14001
14002 _sanitizeSelector: function( hash ) {
14003 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
14004 },
14005
14006 refresh: function() {
14007 var options = this.options,
14008 lis = this.tablist.children( ":has(a[href])" );
14009
14010 // get disabled tabs from class attribute from HTML
14011 // this will get converted to a boolean if needed in _refresh()
14012 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
14013 return lis.index( tab );
14014 });
14015
14016 this._processTabs();
14017
14018 // was collapsed or no tabs
14019 if ( options.active === false || !this.anchors.length ) {
14020 options.active = false;
14021 this.active = $();
14022 // was active, but active tab is gone
14023 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
14024 // all remaining tabs are disabled
14025 if ( this.tabs.length === options.disabled.length ) {
14026 options.active = false;
14027 this.active = $();
14028 // activate previous tab
14029 } else {
14030 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
14031 }
14032 // was active, active tab still exists
14033 } else {
14034 // make sure active index is correct
14035 options.active = this.tabs.index( this.active );
14036 }
14037
14038 this._refresh();
14039 },
14040
14041 _refresh: function() {
14042 this._setupDisabled( this.options.disabled );
14043 this._setupEvents( this.options.event );
14044 this._setupHeightStyle( this.options.heightStyle );
14045
14046 this.tabs.not( this.active ).attr({
14047 "aria-selected": "false",
14048 tabIndex: -1
14049 });
14050 this.panels.not( this._getPanelForTab( this.active ) )
14051 .hide()
14052 .attr({
14053 "aria-expanded": "false",
14054 "aria-hidden": "true"
14055 });
14056
14057 // Make sure one tab is in the tab order
14058 if ( !this.active.length ) {
14059 this.tabs.eq( 0 ).attr( "tabIndex", 0 );
14060 } else {
14061 this.active
14062 .addClass( "ui-tabs-active ui-state-active" )
14063 .attr({
14064 "aria-selected": "true",
14065 tabIndex: 0
14066 });
14067 this._getPanelForTab( this.active )
14068 .show()
14069 .attr({
14070 "aria-expanded": "true",
14071 "aria-hidden": "false"
14072 });
14073 }
14074 },
14075
14076 _processTabs: function() {
14077 var that = this;
14078
14079 this.tablist = this._getList()
14080 .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
14081 .attr( "role", "tablist" );
14082
14083 this.tabs = this.tablist.find( "> li:has(a[href])" )
14084 .addClass( "ui-state-default ui-corner-top" )
14085 .attr({
14086 role: "tab",
14087 tabIndex: -1
14088 });
14089
14090 this.anchors = this.tabs.map(function() {
14091 return $( "a", this )[ 0 ];
14092 })
14093 .addClass( "ui-tabs-anchor" )
14094 .attr({
14095 role: "presentation",
14096 tabIndex: -1
14097 });
14098
14099 this.panels = $();
14100
14101 this.anchors.each(function( i, anchor ) {
14102 var selector, panel, panelId,
14103 anchorId = $( anchor ).uniqueId().attr( "id" ),
14104 tab = $( anchor ).closest( "li" ),
14105 originalAriaControls = tab.attr( "aria-controls" );
14106
14107 // inline tab
14108 if ( isLocal( anchor ) ) {
14109 selector = anchor.hash;
14110 panel = that.element.find( that._sanitizeSelector( selector ) );
14111 // remote tab
14112 } else {
14113 panelId = that._tabId( tab );
14114 selector = "#" + panelId;
14115 panel = that.element.find( selector );
14116 if ( !panel.length ) {
14117 panel = that._createPanel( panelId );
14118 panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
14119 }
14120 panel.attr( "aria-live", "polite" );
14121 }
14122
14123 if ( panel.length) {
14124 that.panels = that.panels.add( panel );
14125 }
14126 if ( originalAriaControls ) {
14127 tab.data( "ui-tabs-aria-controls", originalAriaControls );
14128 }
14129 tab.attr({
14130 "aria-controls": selector.substring( 1 ),
14131 "aria-labelledby": anchorId
14132 });
14133 panel.attr( "aria-labelledby", anchorId );
14134 });
14135
14136 this.panels
14137 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
14138 .attr( "role", "tabpanel" );
14139 },
14140
14141 // allow overriding how to find the list for rare usage scenarios (#7715)
14142 _getList: function() {
14143 return this.element.find( "ol,ul" ).eq( 0 );
14144 },
14145
14146 _createPanel: function( id ) {
14147 return $( "<div>" )
14148 .attr( "id", id )
14149 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
14150 .data( "ui-tabs-destroy", true );
14151 },
14152
14153 _setupDisabled: function( disabled ) {
14154 if ( $.isArray( disabled ) ) {
14155 if ( !disabled.length ) {
14156 disabled = false;
14157 } else if ( disabled.length === this.anchors.length ) {
14158 disabled = true;
14159 }
14160 }
14161
14162 // disable tabs
14163 for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {
14164 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
14165 $( li )
14166 .addClass( "ui-state-disabled" )
14167 .attr( "aria-disabled", "true" );
14168 } else {
14169 $( li )
14170 .removeClass( "ui-state-disabled" )
14171 .removeAttr( "aria-disabled" );
14172 }
14173 }
14174
14175 this.options.disabled = disabled;
14176 },
14177
14178 _setupEvents: function( event ) {
14179 var events = {
14180 click: function( event ) {
14181 event.preventDefault();
14182 }
14183 };
14184 if ( event ) {
14185 $.each( event.split(" "), function( index, eventName ) {
14186 events[ eventName ] = "_eventHandler";
14187 });
14188 }
14189
14190 this._off( this.anchors.add( this.tabs ).add( this.panels ) );
14191 this._on( this.anchors, events );
14192 this._on( this.tabs, { keydown: "_tabKeydown" } );
14193 this._on( this.panels, { keydown: "_panelKeydown" } );
14194
14195 this._focusable( this.tabs );
14196 this._hoverable( this.tabs );
14197 },
14198
14199 _setupHeightStyle: function( heightStyle ) {
14200 var maxHeight,
14201 parent = this.element.parent();
14202
14203 if ( heightStyle === "fill" ) {
14204 maxHeight = parent.height();
14205 maxHeight -= this.element.outerHeight() - this.element.height();
14206
14207 this.element.siblings( ":visible" ).each(function() {
14208 var elem = $( this ),
14209 position = elem.css( "position" );
14210
14211 if ( position === "absolute" || position === "fixed" ) {
14212 return;
14213 }
14214 maxHeight -= elem.outerHeight( true );
14215 });
14216
14217 this.element.children().not( this.panels ).each(function() {
14218 maxHeight -= $( this ).outerHeight( true );
14219 });
14220
14221 this.panels.each(function() {
14222 $( this ).height( Math.max( 0, maxHeight -
14223 $( this ).innerHeight() + $( this ).height() ) );
14224 })
14225 .css( "overflow", "auto" );
14226 } else if ( heightStyle === "auto" ) {
14227 maxHeight = 0;
14228 this.panels.each(function() {
14229 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
14230 }).height( maxHeight );
14231 }
14232 },
14233
14234 _eventHandler: function( event ) {
14235 var options = this.options,
14236 active = this.active,
14237 anchor = $( event.currentTarget ),
14238 tab = anchor.closest( "li" ),
14239 clickedIsActive = tab[ 0 ] === active[ 0 ],
14240 collapsing = clickedIsActive && options.collapsible,
14241 toShow = collapsing ? $() : this._getPanelForTab( tab ),
14242 toHide = !active.length ? $() : this._getPanelForTab( active ),
14243 eventData = {
14244 oldTab: active,
14245 oldPanel: toHide,
14246 newTab: collapsing ? $() : tab,
14247 newPanel: toShow
14248 };
14249
14250 event.preventDefault();
14251
14252 if ( tab.hasClass( "ui-state-disabled" ) ||
14253 // tab is already loading
14254 tab.hasClass( "ui-tabs-loading" ) ||
14255 // can't switch durning an animation
14256 this.running ||
14257 // click on active header, but not collapsible
14258 ( clickedIsActive && !options.collapsible ) ||
14259 // allow canceling activation
14260 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
14261 return;
14262 }
14263
14264 options.active = collapsing ? false : this.tabs.index( tab );
14265
14266 this.active = clickedIsActive ? $() : tab;
14267 if ( this.xhr ) {
14268 this.xhr.abort();
14269 }
14270
14271 if ( !toHide.length && !toShow.length ) {
14272 $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
14273 }
14274
14275 if ( toShow.length ) {
14276 this.load( this.tabs.index( tab ), event );
14277 }
14278 this._toggle( event, eventData );
14279 },
14280
14281 // handles show/hide for selecting tabs
14282 _toggle: function( event, eventData ) {
14283 var that = this,
14284 toShow = eventData.newPanel,
14285 toHide = eventData.oldPanel;
14286
14287 this.running = true;
14288
14289 function complete() {
14290 that.running = false;
14291 that._trigger( "activate", event, eventData );
14292 }
14293
14294 function show() {
14295 eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
14296
14297 if ( toShow.length && that.options.show ) {
14298 that._show( toShow, that.options.show, complete );
14299 } else {
14300 toShow.show();
14301 complete();
14302 }
14303 }
14304
14305 // start out by hiding, then showing, then completing
14306 if ( toHide.length && this.options.hide ) {
14307 this._hide( toHide, this.options.hide, function() {
14308 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
14309 show();
14310 });
14311 } else {
14312 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
14313 toHide.hide();
14314 show();
14315 }
14316
14317 toHide.attr({
14318 "aria-expanded": "false",
14319 "aria-hidden": "true"
14320 });
14321 eventData.oldTab.attr( "aria-selected", "false" );
14322 // If we're switching tabs, remove the old tab from the tab order.
14323 // If we're opening from collapsed state, remove the previous tab from the tab order.
14324 // If we're collapsing, then keep the collapsing tab in the tab order.
14325 if ( toShow.length && toHide.length ) {
14326 eventData.oldTab.attr( "tabIndex", -1 );
14327 } else if ( toShow.length ) {
14328 this.tabs.filter(function() {
14329 return $( this ).attr( "tabIndex" ) === 0;
14330 })
14331 .attr( "tabIndex", -1 );
14332 }
14333
14334 toShow.attr({
14335 "aria-expanded": "true",
14336 "aria-hidden": "false"
14337 });
14338 eventData.newTab.attr({
14339 "aria-selected": "true",
14340 tabIndex: 0
14341 });
14342 },
14343
14344 _activate: function( index ) {
14345 var anchor,
14346 active = this._findActive( index );
14347
14348 // trying to activate the already active panel
14349 if ( active[ 0 ] === this.active[ 0 ] ) {
14350 return;
14351 }
14352
14353 // trying to collapse, simulate a click on the current active header
14354 if ( !active.length ) {
14355 active = this.active;
14356 }
14357
14358 anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
14359 this._eventHandler({
14360 target: anchor,
14361 currentTarget: anchor,
14362 preventDefault: $.noop
14363 });
14364 },
14365
14366 _findActive: function( index ) {
14367 return index === false ? $() : this.tabs.eq( index );
14368 },
14369
14370 _getIndex: function( index ) {
14371 // meta-function to give users option to provide a href string instead of a numerical index.
14372 if ( typeof index === "string" ) {
14373 index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) );
14374 }
14375
14376 return index;
14377 },
14378
14379 _destroy: function() {
14380 if ( this.xhr ) {
14381 this.xhr.abort();
14382 }
14383
14384 this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" );
14385
14386 this.tablist
14387 .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
14388 .removeAttr( "role" );
14389
14390 this.anchors
14391 .removeClass( "ui-tabs-anchor" )
14392 .removeAttr( "role" )
14393 .removeAttr( "tabIndex" )
14394 .removeUniqueId();
14395
14396 this.tabs.add( this.panels ).each(function() {
14397 if ( $.data( this, "ui-tabs-destroy" ) ) {
14398 $( this ).remove();
14399 } else {
14400 $( this )
14401 .removeClass( "ui-state-default ui-state-active ui-state-disabled " +
14402 "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" )
14403 .removeAttr( "tabIndex" )
14404 .removeAttr( "aria-live" )
14405 .removeAttr( "aria-busy" )
14406 .removeAttr( "aria-selected" )
14407 .removeAttr( "aria-labelledby" )
14408 .removeAttr( "aria-hidden" )
14409 .removeAttr( "aria-expanded" )
14410 .removeAttr( "role" );
14411 }
14412 });
14413
14414 this.tabs.each(function() {
14415 var li = $( this ),
14416 prev = li.data( "ui-tabs-aria-controls" );
14417 if ( prev ) {
14418 li
14419 .attr( "aria-controls", prev )
14420 .removeData( "ui-tabs-aria-controls" );
14421 } else {
14422 li.removeAttr( "aria-controls" );
14423 }
14424 });
14425
14426 this.panels.show();
14427
14428 if ( this.options.heightStyle !== "content" ) {
14429 this.panels.css( "height", "" );
14430 }
14431 },
14432
14433 enable: function( index ) {
14434 var disabled = this.options.disabled;
14435 if ( disabled === false ) {
14436 return;
14437 }
14438
14439 if ( index === undefined ) {
14440 disabled = false;
14441 } else {
14442 index = this._getIndex( index );
14443 if ( $.isArray( disabled ) ) {
14444 disabled = $.map( disabled, function( num ) {
14445 return num !== index ? num : null;
14446 });
14447 } else {
14448 disabled = $.map( this.tabs, function( li, num ) {
14449 return num !== index ? num : null;
14450 });
14451 }
14452 }
14453 this._setupDisabled( disabled );
14454 },
14455
14456 disable: function( index ) {
14457 var disabled = this.options.disabled;
14458 if ( disabled === true ) {
14459 return;
14460 }
14461
14462 if ( index === undefined ) {
14463 disabled = true;
14464 } else {
14465 index = this._getIndex( index );
14466 if ( $.inArray( index, disabled ) !== -1 ) {
14467 return;
14468 }
14469 if ( $.isArray( disabled ) ) {
14470 disabled = $.merge( [ index ], disabled ).sort();
14471 } else {
14472 disabled = [ index ];
14473 }
14474 }
14475 this._setupDisabled( disabled );
14476 },
14477
14478 load: function( index, event ) {
14479 index = this._getIndex( index );
14480 var that = this,
14481 tab = this.tabs.eq( index ),
14482 anchor = tab.find( ".ui-tabs-anchor" ),
14483 panel = this._getPanelForTab( tab ),
14484 eventData = {
14485 tab: tab,
14486 panel: panel
14487 };
14488
14489 // not remote
14490 if ( isLocal( anchor[ 0 ] ) ) {
14491 return;
14492 }
14493
14494 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
14495
14496 // support: jQuery <1.8
14497 // jQuery <1.8 returns false if the request is canceled in beforeSend,
14498 // but as of 1.8, $.ajax() always returns a jqXHR object.
14499 if ( this.xhr && this.xhr.statusText !== "canceled" ) {
14500 tab.addClass( "ui-tabs-loading" );
14501 panel.attr( "aria-busy", "true" );
14502
14503 this.xhr
14504 .success(function( response ) {
14505 // support: jQuery <1.8
14506 // http://bugs.jquery.com/ticket/11778
14507 setTimeout(function() {
14508 panel.html( response );
14509 that._trigger( "load", event, eventData );
14510 }, 1 );
14511 })
14512 .complete(function( jqXHR, status ) {
14513 // support: jQuery <1.8
14514 // http://bugs.jquery.com/ticket/11778
14515 setTimeout(function() {
14516 if ( status === "abort" ) {
14517 that.panels.stop( false, true );
14518 }
14519
14520 tab.removeClass( "ui-tabs-loading" );
14521 panel.removeAttr( "aria-busy" );
14522
14523 if ( jqXHR === that.xhr ) {
14524 delete that.xhr;
14525 }
14526 }, 1 );
14527 });
14528 }
14529 },
14530
14531 _ajaxSettings: function( anchor, event, eventData ) {
14532 var that = this;
14533 return {
14534 url: anchor.attr( "href" ),
14535 beforeSend: function( jqXHR, settings ) {
14536 return that._trigger( "beforeLoad", event,
14537 $.extend( { jqXHR : jqXHR, ajaxSettings: settings }, eventData ) );
14538 }
14539 };
14540 },
14541
14542 _getPanelForTab: function( tab ) {
14543 var id = $( tab ).attr( "aria-controls" );
14544 return this.element.find( this._sanitizeSelector( "#" + id ) );
14545 }
14546});
14547
14548})( jQuery );
14549
14550(function( $ ) {
14551
14552var increments = 0;
14553
14554function addDescribedBy( elem, id ) {
14555 var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ );
14556 describedby.push( id );
14557 elem
14558 .data( "ui-tooltip-id", id )
14559 .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
14560}
14561
14562function removeDescribedBy( elem ) {
14563 var id = elem.data( "ui-tooltip-id" ),
14564 describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ),
14565 index = $.inArray( id, describedby );
14566 if ( index !== -1 ) {
14567 describedby.splice( index, 1 );
14568 }
14569
14570 elem.removeData( "ui-tooltip-id" );
14571 describedby = $.trim( describedby.join( " " ) );
14572 if ( describedby ) {
14573 elem.attr( "aria-describedby", describedby );
14574 } else {
14575 elem.removeAttr( "aria-describedby" );
14576 }
14577}
14578
14579$.widget( "ui.tooltip", {
14580 version: "1.10.1",
14581 options: {
14582 content: function() {
14583 // support: IE<9, Opera in jQuery <1.7
14584 // .text() can't accept undefined, so coerce to a string
14585 var title = $( this ).attr( "title" ) || "";
14586 // Escape title, since we're going from an attribute to raw HTML
14587 return $( "<a>" ).text( title ).html();
14588 },
14589 hide: true,
14590 // Disabled elements have inconsistent behavior across browsers (#8661)
14591 items: "[title]:not([disabled])",
14592 position: {
14593 my: "left top+15",
14594 at: "left bottom",
14595 collision: "flipfit flip"
14596 },
14597 show: true,
14598 tooltipClass: null,
14599 track: false,
14600
14601 // callbacks
14602 close: null,
14603 open: null
14604 },
14605
14606 _create: function() {
14607 this._on({
14608 mouseover: "open",
14609 focusin: "open"
14610 });
14611
14612 // IDs of generated tooltips, needed for destroy
14613 this.tooltips = {};
14614 // IDs of parent tooltips where we removed the title attribute
14615 this.parents = {};
14616
14617 if ( this.options.disabled ) {
14618 this._disable();
14619 }
14620 },
14621
14622 _setOption: function( key, value ) {
14623 var that = this;
14624
14625 if ( key === "disabled" ) {
14626 this[ value ? "_disable" : "_enable" ]();
14627 this.options[ key ] = value;
14628 // disable element style changes
14629 return;
14630 }
14631
14632 this._super( key, value );
14633
14634 if ( key === "content" ) {
14635 $.each( this.tooltips, function( id, element ) {
14636 that._updateContent( element );
14637 });
14638 }
14639 },
14640
14641 _disable: function() {
14642 var that = this;
14643
14644 // close open tooltips
14645 $.each( this.tooltips, function( id, element ) {
14646 var event = $.Event( "blur" );
14647 event.target = event.currentTarget = element[0];
14648 that.close( event, true );
14649 });
14650
14651 // remove title attributes to prevent native tooltips
14652 this.element.find( this.options.items ).addBack().each(function() {
14653 var element = $( this );
14654 if ( element.is( "[title]" ) ) {
14655 element
14656 .data( "ui-tooltip-title", element.attr( "title" ) )
14657 .attr( "title", "" );
14658 }
14659 });
14660 },
14661
14662 _enable: function() {
14663 // restore title attributes
14664 this.element.find( this.options.items ).addBack().each(function() {
14665 var element = $( this );
14666 if ( element.data( "ui-tooltip-title" ) ) {
14667 element.attr( "title", element.data( "ui-tooltip-title" ) );
14668 }
14669 });
14670 },
14671
14672 open: function( event ) {
14673 var that = this,
14674 target = $( event ? event.target : this.element )
14675 // we need closest here due to mouseover bubbling,
14676 // but always pointing at the same event target
14677 .closest( this.options.items );
14678
14679 // No element to show a tooltip for or the tooltip is already open
14680 if ( !target.length || target.data( "ui-tooltip-id" ) ) {
14681 return;
14682 }
14683
14684 if ( target.attr( "title" ) ) {
14685 target.data( "ui-tooltip-title", target.attr( "title" ) );
14686 }
14687
14688 target.data( "ui-tooltip-open", true );
14689
14690 // kill parent tooltips, custom or native, for hover
14691 if ( event && event.type === "mouseover" ) {
14692 target.parents().each(function() {
14693 var parent = $( this ),
14694 blurEvent;
14695 if ( parent.data( "ui-tooltip-open" ) ) {
14696 blurEvent = $.Event( "blur" );
14697 blurEvent.target = blurEvent.currentTarget = this;
14698 that.close( blurEvent, true );
14699 }
14700 if ( parent.attr( "title" ) ) {
14701 parent.uniqueId();
14702 that.parents[ this.id ] = {
14703 element: this,
14704 title: parent.attr( "title" )
14705 };
14706 parent.attr( "title", "" );
14707 }
14708 });
14709 }
14710
14711 this._updateContent( target, event );
14712 },
14713
14714 _updateContent: function( target, event ) {
14715 var content,
14716 contentOption = this.options.content,
14717 that = this,
14718 eventType = event ? event.type : null;
14719
14720 if ( typeof contentOption === "string" ) {
14721 return this._open( event, target, contentOption );
14722 }
14723
14724 content = contentOption.call( target[0], function( response ) {
14725 // ignore async response if tooltip was closed already
14726 if ( !target.data( "ui-tooltip-open" ) ) {
14727 return;
14728 }
14729 // IE may instantly serve a cached response for ajax requests
14730 // delay this call to _open so the other call to _open runs first
14731 that._delay(function() {
14732 // jQuery creates a special event for focusin when it doesn't
14733 // exist natively. To improve performance, the native event
14734 // object is reused and the type is changed. Therefore, we can't
14735 // rely on the type being correct after the event finished
14736 // bubbling, so we set it back to the previous value. (#8740)
14737 if ( event ) {
14738 event.type = eventType;
14739 }
14740 this._open( event, target, response );
14741 });
14742 });
14743 if ( content ) {
14744 this._open( event, target, content );
14745 }
14746 },
14747
14748 _open: function( event, target, content ) {
14749 var tooltip, events, delayedShow,
14750 positionOption = $.extend( {}, this.options.position );
14751
14752 if ( !content ) {
14753 return;
14754 }
14755
14756 // Content can be updated multiple times. If the tooltip already
14757 // exists, then just update the content and bail.
14758 tooltip = this._find( target );
14759 if ( tooltip.length ) {
14760 tooltip.find( ".ui-tooltip-content" ).html( content );
14761 return;
14762 }
14763
14764 // if we have a title, clear it to prevent the native tooltip
14765 // we have to check first to avoid defining a title if none exists
14766 // (we don't want to cause an element to start matching [title])
14767 //
14768 // We use removeAttr only for key events, to allow IE to export the correct
14769 // accessible attributes. For mouse events, set to empty string to avoid
14770 // native tooltip showing up (happens only when removing inside mouseover).
14771 if ( target.is( "[title]" ) ) {
14772 if ( event && event.type === "mouseover" ) {
14773 target.attr( "title", "" );
14774 } else {
14775 target.removeAttr( "title" );
14776 }
14777 }
14778
14779 tooltip = this._tooltip( target );
14780 addDescribedBy( target, tooltip.attr( "id" ) );
14781 tooltip.find( ".ui-tooltip-content" ).html( content );
14782
14783 function position( event ) {
14784 positionOption.of = event;
14785 if ( tooltip.is( ":hidden" ) ) {
14786 return;
14787 }
14788 tooltip.position( positionOption );
14789 }
14790 if ( this.options.track && event && /^mouse/.test( event.type ) ) {
14791 this._on( this.document, {
14792 mousemove: position
14793 });
14794 // trigger once to override element-relative positioning
14795 position( event );
14796 } else {
14797 tooltip.position( $.extend({
14798 of: target
14799 }, this.options.position ) );
14800 }
14801
14802 tooltip.hide();
14803
14804 this._show( tooltip, this.options.show );
14805 // Handle tracking tooltips that are shown with a delay (#8644). As soon
14806 // as the tooltip is visible, position the tooltip using the most recent
14807 // event.
14808 if ( this.options.show && this.options.show.delay ) {
14809 delayedShow = this.delayedShow = setInterval(function() {
14810 if ( tooltip.is( ":visible" ) ) {
14811 position( positionOption.of );
14812 clearInterval( delayedShow );
14813 }
14814 }, $.fx.interval );
14815 }
14816
14817 this._trigger( "open", event, { tooltip: tooltip } );
14818
14819 events = {
14820 keyup: function( event ) {
14821 if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
14822 var fakeEvent = $.Event(event);
14823 fakeEvent.currentTarget = target[0];
14824 this.close( fakeEvent, true );
14825 }
14826 },
14827 remove: function() {
14828 this._removeTooltip( tooltip );
14829 }
14830 };
14831 if ( !event || event.type === "mouseover" ) {
14832 events.mouseleave = "close";
14833 }
14834 if ( !event || event.type === "focusin" ) {
14835 events.focusout = "close";
14836 }
14837 this._on( true, target, events );
14838 },
14839
14840 close: function( event ) {
14841 var that = this,
14842 target = $( event ? event.currentTarget : this.element ),
14843 tooltip = this._find( target );
14844
14845 // disabling closes the tooltip, so we need to track when we're closing
14846 // to avoid an infinite loop in case the tooltip becomes disabled on close
14847 if ( this.closing ) {
14848 return;
14849 }
14850
14851 // Clear the interval for delayed tracking tooltips
14852 clearInterval( this.delayedShow );
14853
14854 // only set title if we had one before (see comment in _open())
14855 if ( target.data( "ui-tooltip-title" ) ) {
14856 target.attr( "title", target.data( "ui-tooltip-title" ) );
14857 }
14858
14859 removeDescribedBy( target );
14860
14861 tooltip.stop( true );
14862 this._hide( tooltip, this.options.hide, function() {
14863 that._removeTooltip( $( this ) );
14864 });
14865
14866 target.removeData( "ui-tooltip-open" );
14867 this._off( target, "mouseleave focusout keyup" );
14868 // Remove 'remove' binding only on delegated targets
14869 if ( target[0] !== this.element[0] ) {
14870 this._off( target, "remove" );
14871 }
14872 this._off( this.document, "mousemove" );
14873
14874 if ( event && event.type === "mouseleave" ) {
14875 $.each( this.parents, function( id, parent ) {
14876 $( parent.element ).attr( "title", parent.title );
14877 delete that.parents[ id ];
14878 });
14879 }
14880
14881 this.closing = true;
14882 this._trigger( "close", event, { tooltip: tooltip } );
14883 this.closing = false;
14884 },
14885
14886 _tooltip: function( element ) {
14887 var id = "ui-tooltip-" + increments++,
14888 tooltip = $( "<div>" )
14889 .attr({
14890 id: id,
14891 role: "tooltip"
14892 })
14893 .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " +
14894 ( this.options.tooltipClass || "" ) );
14895 $( "<div>" )
14896 .addClass( "ui-tooltip-content" )
14897 .appendTo( tooltip );
14898 tooltip.appendTo( this.document[0].body );
14899 this.tooltips[ id ] = element;
14900 return tooltip;
14901 },
14902
14903 _find: function( target ) {
14904 var id = target.data( "ui-tooltip-id" );
14905 return id ? $( "#" + id ) : $();
14906 },
14907
14908 _removeTooltip: function( tooltip ) {
14909 tooltip.remove();
14910 delete this.tooltips[ tooltip.attr( "id" ) ];
14911 },
14912
14913 _destroy: function() {
14914 var that = this;
14915
14916 // close open tooltips
14917 $.each( this.tooltips, function( id, element ) {
14918 // Delegate to close method to handle common cleanup
14919 var event = $.Event( "blur" );
14920 event.target = event.currentTarget = element[0];
14921 that.close( event, true );
14922
14923 // Remove immediately; destroying an open tooltip doesn't use the
14924 // hide animation
14925 $( "#" + id ).remove();
14926
14927 // Restore the title
14928 if ( element.data( "ui-tooltip-title" ) ) {
14929 element.attr( "title", element.data( "ui-tooltip-title" ) );
14930 element.removeData( "ui-tooltip-title" );
14931 }
14932 });
14933 }
14934});
14935
14936}( jQuery ) );