blob: 2f83e5a2ae9167a8280ee073b5fa1ad2b3ca4062 [file] [log] [blame]
Felix Meschbergerefc5de52012-12-02 18:44:51 +00001/*! jQuery UI - v1.9.2 - 2012-11-23
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 2012 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.9.2",
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().andSelf().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
179$(function() {
180 var body = document.body,
181 div = body.appendChild( div = document.createElement( "div" ) );
182
183 // access offsetHeight before setting the style to prevent a layout bug
184 // in IE 9 which causes the element to continue to take up space even
185 // after it is removed from the DOM (#8026)
186 div.offsetHeight;
187
188 $.extend( div.style, {
189 minHeight: "100px",
190 height: "auto",
191 padding: 0,
192 borderWidth: 0
193 });
194
195 $.support.minHeight = div.offsetHeight === 100;
196 $.support.selectstart = "onselectstart" in div;
197
198 // set display to none to avoid a layout bug in IE
199 // http://dev.jquery.com/ticket/4014
200 body.removeChild( div ).style.display = "none";
201});
202
203// support: jQuery <1.8
204if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
205 $.each( [ "Width", "Height" ], function( i, name ) {
206 var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
207 type = name.toLowerCase(),
208 orig = {
209 innerWidth: $.fn.innerWidth,
210 innerHeight: $.fn.innerHeight,
211 outerWidth: $.fn.outerWidth,
212 outerHeight: $.fn.outerHeight
213 };
214
215 function reduce( elem, size, border, margin ) {
216 $.each( side, function() {
217 size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
218 if ( border ) {
219 size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
220 }
221 if ( margin ) {
222 size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
223 }
224 });
225 return size;
226 }
227
228 $.fn[ "inner" + name ] = function( size ) {
229 if ( size === undefined ) {
230 return orig[ "inner" + name ].call( this );
231 }
232
233 return this.each(function() {
234 $( this ).css( type, reduce( this, size ) + "px" );
235 });
236 };
237
238 $.fn[ "outer" + name] = function( size, margin ) {
239 if ( typeof size !== "number" ) {
240 return orig[ "outer" + name ].call( this, size );
241 }
242
243 return this.each(function() {
244 $( this).css( type, reduce( this, size, true, margin ) + "px" );
245 });
246 };
247 });
248}
249
250// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
251if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
252 $.fn.removeData = (function( removeData ) {
253 return function( key ) {
254 if ( arguments.length ) {
255 return removeData.call( this, $.camelCase( key ) );
256 } else {
257 return removeData.call( this );
258 }
259 };
260 })( $.fn.removeData );
261}
262
263
264
265
266
267// deprecated
268
269(function() {
270 var uaMatch = /msie ([\w.]+)/.exec( navigator.userAgent.toLowerCase() ) || [];
271 $.ui.ie = uaMatch.length ? true : false;
272 $.ui.ie6 = parseFloat( uaMatch[ 1 ], 10 ) === 6;
273})();
274
275$.fn.extend({
276 disableSelection: function() {
277 return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
278 ".ui-disableSelection", function( event ) {
279 event.preventDefault();
280 });
281 },
282
283 enableSelection: function() {
284 return this.unbind( ".ui-disableSelection" );
285 }
286});
287
288$.extend( $.ui, {
289 // $.ui.plugin is deprecated. Use the proxy pattern instead.
290 plugin: {
291 add: function( module, option, set ) {
292 var i,
293 proto = $.ui[ module ].prototype;
294 for ( i in set ) {
295 proto.plugins[ i ] = proto.plugins[ i ] || [];
296 proto.plugins[ i ].push( [ option, set[ i ] ] );
297 }
298 },
299 call: function( instance, name, args ) {
300 var i,
301 set = instance.plugins[ name ];
302 if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) {
303 return;
304 }
305
306 for ( i = 0; i < set.length; i++ ) {
307 if ( instance.options[ set[ i ][ 0 ] ] ) {
308 set[ i ][ 1 ].apply( instance.element, args );
309 }
310 }
311 }
312 },
313
314 contains: $.contains,
315
316 // only used by resizable
317 hasScroll: function( el, a ) {
318
319 //If overflow is hidden, the element might have extra content, but the user wants to hide it
320 if ( $( el ).css( "overflow" ) === "hidden") {
321 return false;
322 }
323
324 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
325 has = false;
326
327 if ( el[ scroll ] > 0 ) {
328 return true;
329 }
330
331 // TODO: determine which cases actually cause this to happen
332 // if the element doesn't have the scroll set, see if it's possible to
333 // set the scroll
334 el[ scroll ] = 1;
335 has = ( el[ scroll ] > 0 );
336 el[ scroll ] = 0;
337 return has;
338 },
339
340 // these are odd functions, fix the API or move into individual plugins
341 isOverAxis: function( x, reference, size ) {
342 //Determines when x coordinate is over "b" element axis
343 return ( x > reference ) && ( x < ( reference + size ) );
344 },
345 isOver: function( y, x, top, left, height, width ) {
346 //Determines when x, y coordinates is over "b" element
347 return $.ui.isOverAxis( y, top, height ) && $.ui.isOverAxis( x, left, width );
348 }
349});
350
351})( jQuery );
352
353(function( $, undefined ) {
354
355var uuid = 0,
356 slice = Array.prototype.slice,
357 _cleanData = $.cleanData;
358$.cleanData = function( elems ) {
359 for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
360 try {
361 $( elem ).triggerHandler( "remove" );
362 // http://bugs.jquery.com/ticket/8235
363 } catch( e ) {}
364 }
365 _cleanData( elems );
366};
367
368$.widget = function( name, base, prototype ) {
369 var fullName, existingConstructor, constructor, basePrototype,
370 namespace = name.split( "." )[ 0 ];
371
372 name = name.split( "." )[ 1 ];
373 fullName = namespace + "-" + name;
374
375 if ( !prototype ) {
376 prototype = base;
377 base = $.Widget;
378 }
379
380 // create selector for plugin
381 $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
382 return !!$.data( elem, fullName );
383 };
384
385 $[ namespace ] = $[ namespace ] || {};
386 existingConstructor = $[ namespace ][ name ];
387 constructor = $[ namespace ][ name ] = function( options, element ) {
388 // allow instantiation without "new" keyword
389 if ( !this._createWidget ) {
390 return new constructor( options, element );
391 }
392
393 // allow instantiation without initializing for simple inheritance
394 // must use "new" keyword (the code above always passes args)
395 if ( arguments.length ) {
396 this._createWidget( options, element );
397 }
398 };
399 // extend with the existing constructor to carry over any static properties
400 $.extend( constructor, existingConstructor, {
401 version: prototype.version,
402 // copy the object used to create the prototype in case we need to
403 // redefine the widget later
404 _proto: $.extend( {}, prototype ),
405 // track widgets that inherit from this widget in case this widget is
406 // redefined after a widget inherits from it
407 _childConstructors: []
408 });
409
410 basePrototype = new base();
411 // we need to make the options hash a property directly on the new instance
412 // otherwise we'll modify the options hash on the prototype that we're
413 // inheriting from
414 basePrototype.options = $.widget.extend( {}, basePrototype.options );
415 $.each( prototype, function( prop, value ) {
416 if ( $.isFunction( value ) ) {
417 prototype[ prop ] = (function() {
418 var _super = function() {
419 return base.prototype[ prop ].apply( this, arguments );
420 },
421 _superApply = function( args ) {
422 return base.prototype[ prop ].apply( this, args );
423 };
424 return function() {
425 var __super = this._super,
426 __superApply = this._superApply,
427 returnValue;
428
429 this._super = _super;
430 this._superApply = _superApply;
431
432 returnValue = value.apply( this, arguments );
433
434 this._super = __super;
435 this._superApply = __superApply;
436
437 return returnValue;
438 };
439 })();
440 }
441 });
442 constructor.prototype = $.widget.extend( basePrototype, {
443 // TODO: remove support for widgetEventPrefix
444 // always use the name + a colon as the prefix, e.g., draggable:start
445 // don't prefix for widgets that aren't DOM-based
446 widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name
447 }, prototype, {
448 constructor: constructor,
449 namespace: namespace,
450 widgetName: name,
451 // TODO remove widgetBaseClass, see #8155
452 widgetBaseClass: fullName,
453 widgetFullName: fullName
454 });
455
456 // If this widget is being redefined then we need to find all widgets that
457 // are inheriting from it and redefine all of them so that they inherit from
458 // the new version of this widget. We're essentially trying to replace one
459 // level in the prototype chain.
460 if ( existingConstructor ) {
461 $.each( existingConstructor._childConstructors, function( i, child ) {
462 var childPrototype = child.prototype;
463
464 // redefine the child widget using the same prototype that was
465 // originally used, but inherit from the new version of the base
466 $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
467 });
468 // remove the list of existing child constructors from the old constructor
469 // so the old child constructors can be garbage collected
470 delete existingConstructor._childConstructors;
471 } else {
472 base._childConstructors.push( constructor );
473 }
474
475 $.widget.bridge( name, constructor );
476};
477
478$.widget.extend = function( target ) {
479 var input = slice.call( arguments, 1 ),
480 inputIndex = 0,
481 inputLength = input.length,
482 key,
483 value;
484 for ( ; inputIndex < inputLength; inputIndex++ ) {
485 for ( key in input[ inputIndex ] ) {
486 value = input[ inputIndex ][ key ];
487 if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
488 // Clone objects
489 if ( $.isPlainObject( value ) ) {
490 target[ key ] = $.isPlainObject( target[ key ] ) ?
491 $.widget.extend( {}, target[ key ], value ) :
492 // Don't extend strings, arrays, etc. with objects
493 $.widget.extend( {}, value );
494 // Copy everything else by reference
495 } else {
496 target[ key ] = value;
497 }
498 }
499 }
500 }
501 return target;
502};
503
504$.widget.bridge = function( name, object ) {
505 var fullName = object.prototype.widgetFullName || name;
506 $.fn[ name ] = function( options ) {
507 var isMethodCall = typeof options === "string",
508 args = slice.call( arguments, 1 ),
509 returnValue = this;
510
511 // allow multiple hashes to be passed on init
512 options = !isMethodCall && args.length ?
513 $.widget.extend.apply( null, [ options ].concat(args) ) :
514 options;
515
516 if ( isMethodCall ) {
517 this.each(function() {
518 var methodValue,
519 instance = $.data( this, fullName );
520 if ( !instance ) {
521 return $.error( "cannot call methods on " + name + " prior to initialization; " +
522 "attempted to call method '" + options + "'" );
523 }
524 if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
525 return $.error( "no such method '" + options + "' for " + name + " widget instance" );
526 }
527 methodValue = instance[ options ].apply( instance, args );
528 if ( methodValue !== instance && methodValue !== undefined ) {
529 returnValue = methodValue && methodValue.jquery ?
530 returnValue.pushStack( methodValue.get() ) :
531 methodValue;
532 return false;
533 }
534 });
535 } else {
536 this.each(function() {
537 var instance = $.data( this, fullName );
538 if ( instance ) {
539 instance.option( options || {} )._init();
540 } else {
541 $.data( this, fullName, new object( options, this ) );
542 }
543 });
544 }
545
546 return returnValue;
547 };
548};
549
550$.Widget = function( /* options, element */ ) {};
551$.Widget._childConstructors = [];
552
553$.Widget.prototype = {
554 widgetName: "widget",
555 widgetEventPrefix: "",
556 defaultElement: "<div>",
557 options: {
558 disabled: false,
559
560 // callbacks
561 create: null
562 },
563 _createWidget: function( options, element ) {
564 element = $( element || this.defaultElement || this )[ 0 ];
565 this.element = $( element );
566 this.uuid = uuid++;
567 this.eventNamespace = "." + this.widgetName + this.uuid;
568 this.options = $.widget.extend( {},
569 this.options,
570 this._getCreateOptions(),
571 options );
572
573 this.bindings = $();
574 this.hoverable = $();
575 this.focusable = $();
576
577 if ( element !== this ) {
578 // 1.9 BC for #7810
579 // TODO remove dual storage
580 $.data( element, this.widgetName, this );
581 $.data( element, this.widgetFullName, this );
582 this._on( true, this.element, {
583 remove: function( event ) {
584 if ( event.target === element ) {
585 this.destroy();
586 }
587 }
588 });
589 this.document = $( element.style ?
590 // element within the document
591 element.ownerDocument :
592 // element is window or document
593 element.document || element );
594 this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
595 }
596
597 this._create();
598 this._trigger( "create", null, this._getCreateEventData() );
599 this._init();
600 },
601 _getCreateOptions: $.noop,
602 _getCreateEventData: $.noop,
603 _create: $.noop,
604 _init: $.noop,
605
606 destroy: function() {
607 this._destroy();
608 // we can probably remove the unbind calls in 2.0
609 // all event bindings should go through this._on()
610 this.element
611 .unbind( this.eventNamespace )
612 // 1.9 BC for #7810
613 // TODO remove dual storage
614 .removeData( this.widgetName )
615 .removeData( this.widgetFullName )
616 // support: jquery <1.6.3
617 // http://bugs.jquery.com/ticket/9413
618 .removeData( $.camelCase( this.widgetFullName ) );
619 this.widget()
620 .unbind( this.eventNamespace )
621 .removeAttr( "aria-disabled" )
622 .removeClass(
623 this.widgetFullName + "-disabled " +
624 "ui-state-disabled" );
625
626 // clean up events and states
627 this.bindings.unbind( this.eventNamespace );
628 this.hoverable.removeClass( "ui-state-hover" );
629 this.focusable.removeClass( "ui-state-focus" );
630 },
631 _destroy: $.noop,
632
633 widget: function() {
634 return this.element;
635 },
636
637 option: function( key, value ) {
638 var options = key,
639 parts,
640 curOption,
641 i;
642
643 if ( arguments.length === 0 ) {
644 // don't return a reference to the internal hash
645 return $.widget.extend( {}, this.options );
646 }
647
648 if ( typeof key === "string" ) {
649 // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
650 options = {};
651 parts = key.split( "." );
652 key = parts.shift();
653 if ( parts.length ) {
654 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
655 for ( i = 0; i < parts.length - 1; i++ ) {
656 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
657 curOption = curOption[ parts[ i ] ];
658 }
659 key = parts.pop();
660 if ( value === undefined ) {
661 return curOption[ key ] === undefined ? null : curOption[ key ];
662 }
663 curOption[ key ] = value;
664 } else {
665 if ( value === undefined ) {
666 return this.options[ key ] === undefined ? null : this.options[ key ];
667 }
668 options[ key ] = value;
669 }
670 }
671
672 this._setOptions( options );
673
674 return this;
675 },
676 _setOptions: function( options ) {
677 var key;
678
679 for ( key in options ) {
680 this._setOption( key, options[ key ] );
681 }
682
683 return this;
684 },
685 _setOption: function( key, value ) {
686 this.options[ key ] = value;
687
688 if ( key === "disabled" ) {
689 this.widget()
690 .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value )
691 .attr( "aria-disabled", value );
692 this.hoverable.removeClass( "ui-state-hover" );
693 this.focusable.removeClass( "ui-state-focus" );
694 }
695
696 return this;
697 },
698
699 enable: function() {
700 return this._setOption( "disabled", false );
701 },
702 disable: function() {
703 return this._setOption( "disabled", true );
704 },
705
706 _on: function( suppressDisabledCheck, element, handlers ) {
707 var delegateElement,
708 instance = this;
709
710 // no suppressDisabledCheck flag, shuffle arguments
711 if ( typeof suppressDisabledCheck !== "boolean" ) {
712 handlers = element;
713 element = suppressDisabledCheck;
714 suppressDisabledCheck = false;
715 }
716
717 // no element argument, shuffle and use this.element
718 if ( !handlers ) {
719 handlers = element;
720 element = this.element;
721 delegateElement = this.widget();
722 } else {
723 // accept selectors, DOM elements
724 element = delegateElement = $( element );
725 this.bindings = this.bindings.add( element );
726 }
727
728 $.each( handlers, function( event, handler ) {
729 function handlerProxy() {
730 // allow widgets to customize the disabled handling
731 // - disabled as an array instead of boolean
732 // - disabled class as method for disabling individual parts
733 if ( !suppressDisabledCheck &&
734 ( instance.options.disabled === true ||
735 $( this ).hasClass( "ui-state-disabled" ) ) ) {
736 return;
737 }
738 return ( typeof handler === "string" ? instance[ handler ] : handler )
739 .apply( instance, arguments );
740 }
741
742 // copy the guid so direct unbinding works
743 if ( typeof handler !== "string" ) {
744 handlerProxy.guid = handler.guid =
745 handler.guid || handlerProxy.guid || $.guid++;
746 }
747
748 var match = event.match( /^(\w+)\s*(.*)$/ ),
749 eventName = match[1] + instance.eventNamespace,
750 selector = match[2];
751 if ( selector ) {
752 delegateElement.delegate( selector, eventName, handlerProxy );
753 } else {
754 element.bind( eventName, handlerProxy );
755 }
756 });
757 },
758
759 _off: function( element, eventName ) {
760 eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
761 element.unbind( eventName ).undelegate( eventName );
762 },
763
764 _delay: function( handler, delay ) {
765 function handlerProxy() {
766 return ( typeof handler === "string" ? instance[ handler ] : handler )
767 .apply( instance, arguments );
768 }
769 var instance = this;
770 return setTimeout( handlerProxy, delay || 0 );
771 },
772
773 _hoverable: function( element ) {
774 this.hoverable = this.hoverable.add( element );
775 this._on( element, {
776 mouseenter: function( event ) {
777 $( event.currentTarget ).addClass( "ui-state-hover" );
778 },
779 mouseleave: function( event ) {
780 $( event.currentTarget ).removeClass( "ui-state-hover" );
781 }
782 });
783 },
784
785 _focusable: function( element ) {
786 this.focusable = this.focusable.add( element );
787 this._on( element, {
788 focusin: function( event ) {
789 $( event.currentTarget ).addClass( "ui-state-focus" );
790 },
791 focusout: function( event ) {
792 $( event.currentTarget ).removeClass( "ui-state-focus" );
793 }
794 });
795 },
796
797 _trigger: function( type, event, data ) {
798 var prop, orig,
799 callback = this.options[ type ];
800
801 data = data || {};
802 event = $.Event( event );
803 event.type = ( type === this.widgetEventPrefix ?
804 type :
805 this.widgetEventPrefix + type ).toLowerCase();
806 // the original event may come from any element
807 // so we need to reset the target on the new event
808 event.target = this.element[ 0 ];
809
810 // copy original event properties over to the new event
811 orig = event.originalEvent;
812 if ( orig ) {
813 for ( prop in orig ) {
814 if ( !( prop in event ) ) {
815 event[ prop ] = orig[ prop ];
816 }
817 }
818 }
819
820 this.element.trigger( event, data );
821 return !( $.isFunction( callback ) &&
822 callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
823 event.isDefaultPrevented() );
824 }
825};
826
827$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
828 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
829 if ( typeof options === "string" ) {
830 options = { effect: options };
831 }
832 var hasOptions,
833 effectName = !options ?
834 method :
835 options === true || typeof options === "number" ?
836 defaultEffect :
837 options.effect || defaultEffect;
838 options = options || {};
839 if ( typeof options === "number" ) {
840 options = { duration: options };
841 }
842 hasOptions = !$.isEmptyObject( options );
843 options.complete = callback;
844 if ( options.delay ) {
845 element.delay( options.delay );
846 }
847 if ( hasOptions && $.effects && ( $.effects.effect[ effectName ] || $.uiBackCompat !== false && $.effects[ effectName ] ) ) {
848 element[ method ]( options );
849 } else if ( effectName !== method && element[ effectName ] ) {
850 element[ effectName ]( options.duration, options.easing, callback );
851 } else {
852 element.queue(function( next ) {
853 $( this )[ method ]();
854 if ( callback ) {
855 callback.call( element[ 0 ] );
856 }
857 next();
858 });
859 }
860 };
861});
862
863// DEPRECATED
864if ( $.uiBackCompat !== false ) {
865 $.Widget.prototype._getCreateOptions = function() {
866 return $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ];
867 };
868}
869
870})( jQuery );
871
872(function( $, undefined ) {
873
874var mouseHandled = false;
875$( document ).mouseup( function( e ) {
876 mouseHandled = false;
877});
878
879$.widget("ui.mouse", {
880 version: "1.9.2",
881 options: {
882 cancel: 'input,textarea,button,select,option',
883 distance: 1,
884 delay: 0
885 },
886 _mouseInit: function() {
887 var that = this;
888
889 this.element
890 .bind('mousedown.'+this.widgetName, function(event) {
891 return that._mouseDown(event);
892 })
893 .bind('click.'+this.widgetName, function(event) {
894 if (true === $.data(event.target, that.widgetName + '.preventClickEvent')) {
895 $.removeData(event.target, that.widgetName + '.preventClickEvent');
896 event.stopImmediatePropagation();
897 return false;
898 }
899 });
900
901 this.started = false;
902 },
903
904 // TODO: make sure destroying one instance of mouse doesn't mess with
905 // other instances of mouse
906 _mouseDestroy: function() {
907 this.element.unbind('.'+this.widgetName);
908 if ( this._mouseMoveDelegate ) {
909 $(document)
910 .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
911 .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
912 }
913 },
914
915 _mouseDown: function(event) {
916 // don't let more than one widget handle mouseStart
917 if( mouseHandled ) { return; }
918
919 // we may have missed mouseup (out of window)
920 (this._mouseStarted && this._mouseUp(event));
921
922 this._mouseDownEvent = event;
923
924 var that = this,
925 btnIsLeft = (event.which === 1),
926 // event.target.nodeName works around a bug in IE 8 with
927 // disabled inputs (#7620)
928 elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
929 if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
930 return true;
931 }
932
933 this.mouseDelayMet = !this.options.delay;
934 if (!this.mouseDelayMet) {
935 this._mouseDelayTimer = setTimeout(function() {
936 that.mouseDelayMet = true;
937 }, this.options.delay);
938 }
939
940 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
941 this._mouseStarted = (this._mouseStart(event) !== false);
942 if (!this._mouseStarted) {
943 event.preventDefault();
944 return true;
945 }
946 }
947
948 // Click event may never have fired (Gecko & Opera)
949 if (true === $.data(event.target, this.widgetName + '.preventClickEvent')) {
950 $.removeData(event.target, this.widgetName + '.preventClickEvent');
951 }
952
953 // these delegates are required to keep context
954 this._mouseMoveDelegate = function(event) {
955 return that._mouseMove(event);
956 };
957 this._mouseUpDelegate = function(event) {
958 return that._mouseUp(event);
959 };
960 $(document)
961 .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
962 .bind('mouseup.'+this.widgetName, this._mouseUpDelegate);
963
964 event.preventDefault();
965
966 mouseHandled = true;
967 return true;
968 },
969
970 _mouseMove: function(event) {
971 // IE mouseup check - mouseup happened when mouse was out of window
972 if ($.ui.ie && !(document.documentMode >= 9) && !event.button) {
973 return this._mouseUp(event);
974 }
975
976 if (this._mouseStarted) {
977 this._mouseDrag(event);
978 return event.preventDefault();
979 }
980
981 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
982 this._mouseStarted =
983 (this._mouseStart(this._mouseDownEvent, event) !== false);
984 (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
985 }
986
987 return !this._mouseStarted;
988 },
989
990 _mouseUp: function(event) {
991 $(document)
992 .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
993 .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
994
995 if (this._mouseStarted) {
996 this._mouseStarted = false;
997
998 if (event.target === this._mouseDownEvent.target) {
999 $.data(event.target, this.widgetName + '.preventClickEvent', true);
1000 }
1001
1002 this._mouseStop(event);
1003 }
1004
1005 return false;
1006 },
1007
1008 _mouseDistanceMet: function(event) {
1009 return (Math.max(
1010 Math.abs(this._mouseDownEvent.pageX - event.pageX),
1011 Math.abs(this._mouseDownEvent.pageY - event.pageY)
1012 ) >= this.options.distance
1013 );
1014 },
1015
1016 _mouseDelayMet: function(event) {
1017 return this.mouseDelayMet;
1018 },
1019
1020 // These are placeholder methods, to be overriden by extending plugin
1021 _mouseStart: function(event) {},
1022 _mouseDrag: function(event) {},
1023 _mouseStop: function(event) {},
1024 _mouseCapture: function(event) { return true; }
1025});
1026
1027})(jQuery);
1028
1029(function( $, undefined ) {
1030
1031$.widget("ui.draggable", $.ui.mouse, {
1032 version: "1.9.2",
1033 widgetEventPrefix: "drag",
1034 options: {
1035 addClasses: true,
1036 appendTo: "parent",
1037 axis: false,
1038 connectToSortable: false,
1039 containment: false,
1040 cursor: "auto",
1041 cursorAt: false,
1042 grid: false,
1043 handle: false,
1044 helper: "original",
1045 iframeFix: false,
1046 opacity: false,
1047 refreshPositions: false,
1048 revert: false,
1049 revertDuration: 500,
1050 scope: "default",
1051 scroll: true,
1052 scrollSensitivity: 20,
1053 scrollSpeed: 20,
1054 snap: false,
1055 snapMode: "both",
1056 snapTolerance: 20,
1057 stack: false,
1058 zIndex: false
1059 },
1060 _create: function() {
1061
1062 if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position")))
1063 this.element[0].style.position = 'relative';
1064
1065 (this.options.addClasses && this.element.addClass("ui-draggable"));
1066 (this.options.disabled && this.element.addClass("ui-draggable-disabled"));
1067
1068 this._mouseInit();
1069
1070 },
1071
1072 _destroy: function() {
1073 this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
1074 this._mouseDestroy();
1075 },
1076
1077 _mouseCapture: function(event) {
1078
1079 var o = this.options;
1080
1081 // among others, prevent a drag on a resizable-handle
1082 if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle'))
1083 return false;
1084
1085 //Quit if we're not on a valid handle
1086 this.handle = this._getHandle(event);
1087 if (!this.handle)
1088 return false;
1089
1090 $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
1091 $('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>')
1092 .css({
1093 width: this.offsetWidth+"px", height: this.offsetHeight+"px",
1094 position: "absolute", opacity: "0.001", zIndex: 1000
1095 })
1096 .css($(this).offset())
1097 .appendTo("body");
1098 });
1099
1100 return true;
1101
1102 },
1103
1104 _mouseStart: function(event) {
1105
1106 var o = this.options;
1107
1108 //Create and append the visible helper
1109 this.helper = this._createHelper(event);
1110
1111 this.helper.addClass("ui-draggable-dragging");
1112
1113 //Cache the helper size
1114 this._cacheHelperProportions();
1115
1116 //If ddmanager is used for droppables, set the global draggable
1117 if($.ui.ddmanager)
1118 $.ui.ddmanager.current = this;
1119
1120 /*
1121 * - Position generation -
1122 * This block generates everything position related - it's the core of draggables.
1123 */
1124
1125 //Cache the margins of the original element
1126 this._cacheMargins();
1127
1128 //Store the helper's css position
1129 this.cssPosition = this.helper.css("position");
1130 this.scrollParent = this.helper.scrollParent();
1131
1132 //The element's absolute position on the page minus margins
1133 this.offset = this.positionAbs = this.element.offset();
1134 this.offset = {
1135 top: this.offset.top - this.margins.top,
1136 left: this.offset.left - this.margins.left
1137 };
1138
1139 $.extend(this.offset, {
1140 click: { //Where the click happened, relative to the element
1141 left: event.pageX - this.offset.left,
1142 top: event.pageY - this.offset.top
1143 },
1144 parent: this._getParentOffset(),
1145 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
1146 });
1147
1148 //Generate the original position
1149 this.originalPosition = this.position = this._generatePosition(event);
1150 this.originalPageX = event.pageX;
1151 this.originalPageY = event.pageY;
1152
1153 //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
1154 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
1155
1156 //Set a containment if given in the options
1157 if(o.containment)
1158 this._setContainment();
1159
1160 //Trigger event + callbacks
1161 if(this._trigger("start", event) === false) {
1162 this._clear();
1163 return false;
1164 }
1165
1166 //Recache the helper size
1167 this._cacheHelperProportions();
1168
1169 //Prepare the droppable offsets
1170 if ($.ui.ddmanager && !o.dropBehaviour)
1171 $.ui.ddmanager.prepareOffsets(this, event);
1172
1173
1174 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
1175
1176 //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
1177 if ( $.ui.ddmanager ) $.ui.ddmanager.dragStart(this, event);
1178
1179 return true;
1180 },
1181
1182 _mouseDrag: function(event, noPropagation) {
1183
1184 //Compute the helpers position
1185 this.position = this._generatePosition(event);
1186 this.positionAbs = this._convertPositionTo("absolute");
1187
1188 //Call plugins and callbacks and use the resulting position if something is returned
1189 if (!noPropagation) {
1190 var ui = this._uiHash();
1191 if(this._trigger('drag', event, ui) === false) {
1192 this._mouseUp({});
1193 return false;
1194 }
1195 this.position = ui.position;
1196 }
1197
1198 if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
1199 if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
1200 if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
1201
1202 return false;
1203 },
1204
1205 _mouseStop: function(event) {
1206
1207 //If we are using droppables, inform the manager about the drop
1208 var dropped = false;
1209 if ($.ui.ddmanager && !this.options.dropBehaviour)
1210 dropped = $.ui.ddmanager.drop(this, event);
1211
1212 //if a drop comes from outside (a sortable)
1213 if(this.dropped) {
1214 dropped = this.dropped;
1215 this.dropped = false;
1216 }
1217
1218 //if the original element is no longer in the DOM don't bother to continue (see #8269)
1219 var element = this.element[0], elementInDom = false;
1220 while ( element && (element = element.parentNode) ) {
1221 if (element == document ) {
1222 elementInDom = true;
1223 }
1224 }
1225 if ( !elementInDom && this.options.helper === "original" )
1226 return false;
1227
1228 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))) {
1229 var that = this;
1230 $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
1231 if(that._trigger("stop", event) !== false) {
1232 that._clear();
1233 }
1234 });
1235 } else {
1236 if(this._trigger("stop", event) !== false) {
1237 this._clear();
1238 }
1239 }
1240
1241 return false;
1242 },
1243
1244 _mouseUp: function(event) {
1245 //Remove frame helpers
1246 $("div.ui-draggable-iframeFix").each(function() {
1247 this.parentNode.removeChild(this);
1248 });
1249
1250 //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
1251 if( $.ui.ddmanager ) $.ui.ddmanager.dragStop(this, event);
1252
1253 return $.ui.mouse.prototype._mouseUp.call(this, event);
1254 },
1255
1256 cancel: function() {
1257
1258 if(this.helper.is(".ui-draggable-dragging")) {
1259 this._mouseUp({});
1260 } else {
1261 this._clear();
1262 }
1263
1264 return this;
1265
1266 },
1267
1268 _getHandle: function(event) {
1269
1270 var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false;
1271 $(this.options.handle, this.element)
1272 .find("*")
1273 .andSelf()
1274 .each(function() {
1275 if(this == event.target) handle = true;
1276 });
1277
1278 return handle;
1279
1280 },
1281
1282 _createHelper: function(event) {
1283
1284 var o = this.options;
1285 var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone().removeAttr('id') : this.element);
1286
1287 if(!helper.parents('body').length)
1288 helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo));
1289
1290 if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position")))
1291 helper.css("position", "absolute");
1292
1293 return helper;
1294
1295 },
1296
1297 _adjustOffsetFromHelper: function(obj) {
1298 if (typeof obj == 'string') {
1299 obj = obj.split(' ');
1300 }
1301 if ($.isArray(obj)) {
1302 obj = {left: +obj[0], top: +obj[1] || 0};
1303 }
1304 if ('left' in obj) {
1305 this.offset.click.left = obj.left + this.margins.left;
1306 }
1307 if ('right' in obj) {
1308 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
1309 }
1310 if ('top' in obj) {
1311 this.offset.click.top = obj.top + this.margins.top;
1312 }
1313 if ('bottom' in obj) {
1314 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
1315 }
1316 },
1317
1318 _getParentOffset: function() {
1319
1320 //Get the offsetParent and cache its position
1321 this.offsetParent = this.helper.offsetParent();
1322 var po = this.offsetParent.offset();
1323
1324 // This is a special case where we need to modify a offset calculated on start, since the following happened:
1325 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
1326 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
1327 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
1328 if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
1329 po.left += this.scrollParent.scrollLeft();
1330 po.top += this.scrollParent.scrollTop();
1331 }
1332
1333 if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information
1334 || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.ui.ie)) //Ugly IE fix
1335 po = { top: 0, left: 0 };
1336
1337 return {
1338 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
1339 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
1340 };
1341
1342 },
1343
1344 _getRelativeOffset: function() {
1345
1346 if(this.cssPosition == "relative") {
1347 var p = this.element.position();
1348 return {
1349 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
1350 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
1351 };
1352 } else {
1353 return { top: 0, left: 0 };
1354 }
1355
1356 },
1357
1358 _cacheMargins: function() {
1359 this.margins = {
1360 left: (parseInt(this.element.css("marginLeft"),10) || 0),
1361 top: (parseInt(this.element.css("marginTop"),10) || 0),
1362 right: (parseInt(this.element.css("marginRight"),10) || 0),
1363 bottom: (parseInt(this.element.css("marginBottom"),10) || 0)
1364 };
1365 },
1366
1367 _cacheHelperProportions: function() {
1368 this.helperProportions = {
1369 width: this.helper.outerWidth(),
1370 height: this.helper.outerHeight()
1371 };
1372 },
1373
1374 _setContainment: function() {
1375
1376 var o = this.options;
1377 if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
1378 if(o.containment == 'document' || o.containment == 'window') this.containment = [
1379 o.containment == 'document' ? 0 : $(window).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
1380 o.containment == 'document' ? 0 : $(window).scrollTop() - this.offset.relative.top - this.offset.parent.top,
1381 (o.containment == 'document' ? 0 : $(window).scrollLeft()) + $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left,
1382 (o.containment == 'document' ? 0 : $(window).scrollTop()) + ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
1383 ];
1384
1385 if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) {
1386 var c = $(o.containment);
1387 var ce = c[0]; if(!ce) return;
1388 var co = c.offset();
1389 var over = ($(ce).css("overflow") != 'hidden');
1390
1391 this.containment = [
1392 (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0),
1393 (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0),
1394 (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,
1395 (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
1396 ];
1397 this.relative_container = c;
1398
1399 } else if(o.containment.constructor == Array) {
1400 this.containment = o.containment;
1401 }
1402
1403 },
1404
1405 _convertPositionTo: function(d, pos) {
1406
1407 if(!pos) pos = this.position;
1408 var mod = d == "absolute" ? 1 : -1;
1409 var o = this.options, 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);
1410
1411 return {
1412 top: (
1413 pos.top // The absolute mouse position
1414 + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent
1415 + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border)
1416 - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
1417 ),
1418 left: (
1419 pos.left // The absolute mouse position
1420 + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent
1421 + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border)
1422 - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
1423 )
1424 };
1425
1426 },
1427
1428 _generatePosition: function(event) {
1429
1430 var o = this.options, 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);
1431 var pageX = event.pageX;
1432 var pageY = event.pageY;
1433
1434 /*
1435 * - Position constraining -
1436 * Constrain the position to a mix of grid, containment.
1437 */
1438
1439 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
1440 var containment;
1441 if(this.containment) {
1442 if (this.relative_container){
1443 var co = this.relative_container.offset();
1444 containment = [ this.containment[0] + co.left,
1445 this.containment[1] + co.top,
1446 this.containment[2] + co.left,
1447 this.containment[3] + co.top ];
1448 }
1449 else {
1450 containment = this.containment;
1451 }
1452
1453 if(event.pageX - this.offset.click.left < containment[0]) pageX = containment[0] + this.offset.click.left;
1454 if(event.pageY - this.offset.click.top < containment[1]) pageY = containment[1] + this.offset.click.top;
1455 if(event.pageX - this.offset.click.left > containment[2]) pageX = containment[2] + this.offset.click.left;
1456 if(event.pageY - this.offset.click.top > containment[3]) pageY = containment[3] + this.offset.click.top;
1457 }
1458
1459 if(o.grid) {
1460 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
1461 var top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
1462 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;
1463
1464 var left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
1465 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;
1466 }
1467
1468 }
1469
1470 return {
1471 top: (
1472 pageY // The absolute mouse position
1473 - this.offset.click.top // Click offset (relative to the element)
1474 - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent
1475 - this.offset.parent.top // The offsetParent's offset without borders (offset + border)
1476 + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
1477 ),
1478 left: (
1479 pageX // The absolute mouse position
1480 - this.offset.click.left // Click offset (relative to the element)
1481 - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent
1482 - this.offset.parent.left // The offsetParent's offset without borders (offset + border)
1483 + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
1484 )
1485 };
1486
1487 },
1488
1489 _clear: function() {
1490 this.helper.removeClass("ui-draggable-dragging");
1491 if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove();
1492 //if($.ui.ddmanager) $.ui.ddmanager.current = null;
1493 this.helper = null;
1494 this.cancelHelperRemoval = false;
1495 },
1496
1497 // From now on bulk stuff - mainly helpers
1498
1499 _trigger: function(type, event, ui) {
1500 ui = ui || this._uiHash();
1501 $.ui.plugin.call(this, type, [event, ui]);
1502 if(type == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins
1503 return $.Widget.prototype._trigger.call(this, type, event, ui);
1504 },
1505
1506 plugins: {},
1507
1508 _uiHash: function(event) {
1509 return {
1510 helper: this.helper,
1511 position: this.position,
1512 originalPosition: this.originalPosition,
1513 offset: this.positionAbs
1514 };
1515 }
1516
1517});
1518
1519$.ui.plugin.add("draggable", "connectToSortable", {
1520 start: function(event, ui) {
1521
1522 var inst = $(this).data("draggable"), o = inst.options,
1523 uiSortable = $.extend({}, ui, { item: inst.element });
1524 inst.sortables = [];
1525 $(o.connectToSortable).each(function() {
1526 var sortable = $.data(this, 'sortable');
1527 if (sortable && !sortable.options.disabled) {
1528 inst.sortables.push({
1529 instance: sortable,
1530 shouldRevert: sortable.options.revert
1531 });
1532 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).
1533 sortable._trigger("activate", event, uiSortable);
1534 }
1535 });
1536
1537 },
1538 stop: function(event, ui) {
1539
1540 //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
1541 var inst = $(this).data("draggable"),
1542 uiSortable = $.extend({}, ui, { item: inst.element });
1543
1544 $.each(inst.sortables, function() {
1545 if(this.instance.isOver) {
1546
1547 this.instance.isOver = 0;
1548
1549 inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
1550 this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
1551
1552 //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid'
1553 if(this.shouldRevert) this.instance.options.revert = true;
1554
1555 //Trigger the stop of the sortable
1556 this.instance._mouseStop(event);
1557
1558 this.instance.options.helper = this.instance.options._helper;
1559
1560 //If the helper has been the original item, restore properties in the sortable
1561 if(inst.options.helper == 'original')
1562 this.instance.currentItem.css({ top: 'auto', left: 'auto' });
1563
1564 } else {
1565 this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
1566 this.instance._trigger("deactivate", event, uiSortable);
1567 }
1568
1569 });
1570
1571 },
1572 drag: function(event, ui) {
1573
1574 var inst = $(this).data("draggable"), that = this;
1575
1576 var checkPos = function(o) {
1577 var dyClick = this.offset.click.top, dxClick = this.offset.click.left;
1578 var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left;
1579 var itemHeight = o.height, itemWidth = o.width;
1580 var itemTop = o.top, itemLeft = o.left;
1581
1582 return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth);
1583 };
1584
1585 $.each(inst.sortables, function(i) {
1586
1587 var innermostIntersecting = false;
1588 var thisSortable = this;
1589 //Copy over some variables to allow calling the sortable's native _intersectsWith
1590 this.instance.positionAbs = inst.positionAbs;
1591 this.instance.helperProportions = inst.helperProportions;
1592 this.instance.offset.click = inst.offset.click;
1593
1594 if(this.instance._intersectsWith(this.instance.containerCache)) {
1595 innermostIntersecting = true;
1596 $.each(inst.sortables, function () {
1597 this.instance.positionAbs = inst.positionAbs;
1598 this.instance.helperProportions = inst.helperProportions;
1599 this.instance.offset.click = inst.offset.click;
1600 if (this != thisSortable
1601 && this.instance._intersectsWith(this.instance.containerCache)
1602 && $.ui.contains(thisSortable.instance.element[0], this.instance.element[0]))
1603 innermostIntersecting = false;
1604 return innermostIntersecting;
1605 });
1606 }
1607
1608
1609 if(innermostIntersecting) {
1610 //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
1611 if(!this.instance.isOver) {
1612
1613 this.instance.isOver = 1;
1614 //Now we fake the start of dragging for the sortable instance,
1615 //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
1616 //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)
1617 this.instance.currentItem = $(that).clone().removeAttr('id').appendTo(this.instance.element).data("sortable-item", true);
1618 this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
1619 this.instance.options.helper = function() { return ui.helper[0]; };
1620
1621 event.target = this.instance.currentItem[0];
1622 this.instance._mouseCapture(event, true);
1623 this.instance._mouseStart(event, true, true);
1624
1625 //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
1626 this.instance.offset.click.top = inst.offset.click.top;
1627 this.instance.offset.click.left = inst.offset.click.left;
1628 this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
1629 this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
1630
1631 inst._trigger("toSortable", event);
1632 inst.dropped = this.instance.element; //draggable revert needs that
1633 //hack so receive/update callbacks work (mostly)
1634 inst.currentItem = inst.element;
1635 this.instance.fromOutside = inst;
1636
1637 }
1638
1639 //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
1640 if(this.instance.currentItem) this.instance._mouseDrag(event);
1641
1642 } else {
1643
1644 //If it doesn't intersect with the sortable, and it intersected before,
1645 //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
1646 if(this.instance.isOver) {
1647
1648 this.instance.isOver = 0;
1649 this.instance.cancelHelperRemoval = true;
1650
1651 //Prevent reverting on this forced stop
1652 this.instance.options.revert = false;
1653
1654 // The out event needs to be triggered independently
1655 this.instance._trigger('out', event, this.instance._uiHash(this.instance));
1656
1657 this.instance._mouseStop(event, true);
1658 this.instance.options.helper = this.instance.options._helper;
1659
1660 //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
1661 this.instance.currentItem.remove();
1662 if(this.instance.placeholder) this.instance.placeholder.remove();
1663
1664 inst._trigger("fromSortable", event);
1665 inst.dropped = false; //draggable revert needs that
1666 }
1667
1668 };
1669
1670 });
1671
1672 }
1673});
1674
1675$.ui.plugin.add("draggable", "cursor", {
1676 start: function(event, ui) {
1677 var t = $('body'), o = $(this).data('draggable').options;
1678 if (t.css("cursor")) o._cursor = t.css("cursor");
1679 t.css("cursor", o.cursor);
1680 },
1681 stop: function(event, ui) {
1682 var o = $(this).data('draggable').options;
1683 if (o._cursor) $('body').css("cursor", o._cursor);
1684 }
1685});
1686
1687$.ui.plugin.add("draggable", "opacity", {
1688 start: function(event, ui) {
1689 var t = $(ui.helper), o = $(this).data('draggable').options;
1690 if(t.css("opacity")) o._opacity = t.css("opacity");
1691 t.css('opacity', o.opacity);
1692 },
1693 stop: function(event, ui) {
1694 var o = $(this).data('draggable').options;
1695 if(o._opacity) $(ui.helper).css('opacity', o._opacity);
1696 }
1697});
1698
1699$.ui.plugin.add("draggable", "scroll", {
1700 start: function(event, ui) {
1701 var i = $(this).data("draggable");
1702 if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset();
1703 },
1704 drag: function(event, ui) {
1705
1706 var i = $(this).data("draggable"), o = i.options, scrolled = false;
1707
1708 if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') {
1709
1710 if(!o.axis || o.axis != 'x') {
1711 if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
1712 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
1713 else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity)
1714 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
1715 }
1716
1717 if(!o.axis || o.axis != 'y') {
1718 if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
1719 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
1720 else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity)
1721 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
1722 }
1723
1724 } else {
1725
1726 if(!o.axis || o.axis != 'x') {
1727 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
1728 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
1729 else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
1730 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
1731 }
1732
1733 if(!o.axis || o.axis != 'y') {
1734 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
1735 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
1736 else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
1737 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
1738 }
1739
1740 }
1741
1742 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
1743 $.ui.ddmanager.prepareOffsets(i, event);
1744
1745 }
1746});
1747
1748$.ui.plugin.add("draggable", "snap", {
1749 start: function(event, ui) {
1750
1751 var i = $(this).data("draggable"), o = i.options;
1752 i.snapElements = [];
1753
1754 $(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) : o.snap).each(function() {
1755 var $t = $(this); var $o = $t.offset();
1756 if(this != i.element[0]) i.snapElements.push({
1757 item: this,
1758 width: $t.outerWidth(), height: $t.outerHeight(),
1759 top: $o.top, left: $o.left
1760 });
1761 });
1762
1763 },
1764 drag: function(event, ui) {
1765
1766 var inst = $(this).data("draggable"), o = inst.options;
1767 var d = o.snapTolerance;
1768
1769 var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
1770 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
1771
1772 for (var i = inst.snapElements.length - 1; i >= 0; i--){
1773
1774 var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width,
1775 t = inst.snapElements[i].top, b = t + inst.snapElements[i].height;
1776
1777 //Yes, I know, this is insane ;)
1778 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))) {
1779 if(inst.snapElements[i].snapping) (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
1780 inst.snapElements[i].snapping = false;
1781 continue;
1782 }
1783
1784 if(o.snapMode != 'inner') {
1785 var ts = Math.abs(t - y2) <= d;
1786 var bs = Math.abs(b - y1) <= d;
1787 var ls = Math.abs(l - x2) <= d;
1788 var rs = Math.abs(r - x1) <= d;
1789 if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
1790 if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
1791 if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
1792 if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
1793 }
1794
1795 var first = (ts || bs || ls || rs);
1796
1797 if(o.snapMode != 'outer') {
1798 var ts = Math.abs(t - y1) <= d;
1799 var bs = Math.abs(b - y2) <= d;
1800 var ls = Math.abs(l - x1) <= d;
1801 var rs = Math.abs(r - x2) <= d;
1802 if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
1803 if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
1804 if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
1805 if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
1806 }
1807
1808 if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first))
1809 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
1810 inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
1811
1812 };
1813
1814 }
1815});
1816
1817$.ui.plugin.add("draggable", "stack", {
1818 start: function(event, ui) {
1819
1820 var o = $(this).data("draggable").options;
1821
1822 var group = $.makeArray($(o.stack)).sort(function(a,b) {
1823 return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0);
1824 });
1825 if (!group.length) { return; }
1826
1827 var min = parseInt(group[0].style.zIndex) || 0;
1828 $(group).each(function(i) {
1829 this.style.zIndex = min + i;
1830 });
1831
1832 this[0].style.zIndex = min + group.length;
1833
1834 }
1835});
1836
1837$.ui.plugin.add("draggable", "zIndex", {
1838 start: function(event, ui) {
1839 var t = $(ui.helper), o = $(this).data("draggable").options;
1840 if(t.css("zIndex")) o._zIndex = t.css("zIndex");
1841 t.css('zIndex', o.zIndex);
1842 },
1843 stop: function(event, ui) {
1844 var o = $(this).data("draggable").options;
1845 if(o._zIndex) $(ui.helper).css('zIndex', o._zIndex);
1846 }
1847});
1848
1849})(jQuery);
1850
1851(function( $, undefined ) {
1852
1853$.widget("ui.droppable", {
1854 version: "1.9.2",
1855 widgetEventPrefix: "drop",
1856 options: {
1857 accept: '*',
1858 activeClass: false,
1859 addClasses: true,
1860 greedy: false,
1861 hoverClass: false,
1862 scope: 'default',
1863 tolerance: 'intersect'
1864 },
1865 _create: function() {
1866
1867 var o = this.options, accept = o.accept;
1868 this.isover = 0; this.isout = 1;
1869
1870 this.accept = $.isFunction(accept) ? accept : function(d) {
1871 return d.is(accept);
1872 };
1873
1874 //Store the droppable's proportions
1875 this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight };
1876
1877 // Add the reference and positions to the manager
1878 $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || [];
1879 $.ui.ddmanager.droppables[o.scope].push(this);
1880
1881 (o.addClasses && this.element.addClass("ui-droppable"));
1882
1883 },
1884
1885 _destroy: function() {
1886 var drop = $.ui.ddmanager.droppables[this.options.scope];
1887 for ( var i = 0; i < drop.length; i++ )
1888 if ( drop[i] == this )
1889 drop.splice(i, 1);
1890
1891 this.element.removeClass("ui-droppable ui-droppable-disabled");
1892 },
1893
1894 _setOption: function(key, value) {
1895
1896 if(key == 'accept') {
1897 this.accept = $.isFunction(value) ? value : function(d) {
1898 return d.is(value);
1899 };
1900 }
1901 $.Widget.prototype._setOption.apply(this, arguments);
1902 },
1903
1904 _activate: function(event) {
1905 var draggable = $.ui.ddmanager.current;
1906 if(this.options.activeClass) this.element.addClass(this.options.activeClass);
1907 (draggable && this._trigger('activate', event, this.ui(draggable)));
1908 },
1909
1910 _deactivate: function(event) {
1911 var draggable = $.ui.ddmanager.current;
1912 if(this.options.activeClass) this.element.removeClass(this.options.activeClass);
1913 (draggable && this._trigger('deactivate', event, this.ui(draggable)));
1914 },
1915
1916 _over: function(event) {
1917
1918 var draggable = $.ui.ddmanager.current;
1919 if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element
1920
1921 if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
1922 if(this.options.hoverClass) this.element.addClass(this.options.hoverClass);
1923 this._trigger('over', event, this.ui(draggable));
1924 }
1925
1926 },
1927
1928 _out: function(event) {
1929
1930 var draggable = $.ui.ddmanager.current;
1931 if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element
1932
1933 if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
1934 if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass);
1935 this._trigger('out', event, this.ui(draggable));
1936 }
1937
1938 },
1939
1940 _drop: function(event,custom) {
1941
1942 var draggable = custom || $.ui.ddmanager.current;
1943 if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element
1944
1945 var childrenIntersection = false;
1946 this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function() {
1947 var inst = $.data(this, 'droppable');
1948 if(
1949 inst.options.greedy
1950 && !inst.options.disabled
1951 && inst.options.scope == draggable.options.scope
1952 && inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element))
1953 && $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)
1954 ) { childrenIntersection = true; return false; }
1955 });
1956 if(childrenIntersection) return false;
1957
1958 if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
1959 if(this.options.activeClass) this.element.removeClass(this.options.activeClass);
1960 if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass);
1961 this._trigger('drop', event, this.ui(draggable));
1962 return this.element;
1963 }
1964
1965 return false;
1966
1967 },
1968
1969 ui: function(c) {
1970 return {
1971 draggable: (c.currentItem || c.element),
1972 helper: c.helper,
1973 position: c.position,
1974 offset: c.positionAbs
1975 };
1976 }
1977
1978});
1979
1980$.ui.intersect = function(draggable, droppable, toleranceMode) {
1981
1982 if (!droppable.offset) return false;
1983
1984 var x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width,
1985 y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height;
1986 var l = droppable.offset.left, r = l + droppable.proportions.width,
1987 t = droppable.offset.top, b = t + droppable.proportions.height;
1988
1989 switch (toleranceMode) {
1990 case 'fit':
1991 return (l <= x1 && x2 <= r
1992 && t <= y1 && y2 <= b);
1993 break;
1994 case 'intersect':
1995 return (l < x1 + (draggable.helperProportions.width / 2) // Right Half
1996 && x2 - (draggable.helperProportions.width / 2) < r // Left Half
1997 && t < y1 + (draggable.helperProportions.height / 2) // Bottom Half
1998 && y2 - (draggable.helperProportions.height / 2) < b ); // Top Half
1999 break;
2000 case 'pointer':
2001 var draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left),
2002 draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top),
2003 isOver = $.ui.isOver(draggableTop, draggableLeft, t, l, droppable.proportions.height, droppable.proportions.width);
2004 return isOver;
2005 break;
2006 case 'touch':
2007 return (
2008 (y1 >= t && y1 <= b) || // Top edge touching
2009 (y2 >= t && y2 <= b) || // Bottom edge touching
2010 (y1 < t && y2 > b) // Surrounded vertically
2011 ) && (
2012 (x1 >= l && x1 <= r) || // Left edge touching
2013 (x2 >= l && x2 <= r) || // Right edge touching
2014 (x1 < l && x2 > r) // Surrounded horizontally
2015 );
2016 break;
2017 default:
2018 return false;
2019 break;
2020 }
2021
2022};
2023
2024/*
2025 This manager tracks offsets of draggables and droppables
2026*/
2027$.ui.ddmanager = {
2028 current: null,
2029 droppables: { 'default': [] },
2030 prepareOffsets: function(t, event) {
2031
2032 var m = $.ui.ddmanager.droppables[t.options.scope] || [];
2033 var type = event ? event.type : null; // workaround for #2317
2034 var list = (t.currentItem || t.element).find(":data(droppable)").andSelf();
2035
2036 droppablesLoop: for (var i = 0; i < m.length; i++) {
2037
2038 if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) continue; //No disabled and non-accepted
2039 for (var j=0; j < list.length; j++) { if(list[j] == m[i].element[0]) { m[i].proportions.height = 0; continue droppablesLoop; } }; //Filter out elements in the current dragged item
2040 m[i].visible = m[i].element.css("display") != "none"; if(!m[i].visible) continue; //If the element is not visible, continue
2041
2042 if(type == "mousedown") m[i]._activate.call(m[i], event); //Activate the droppable if used directly from draggables
2043
2044 m[i].offset = m[i].element.offset();
2045 m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight };
2046
2047 }
2048
2049 },
2050 drop: function(draggable, event) {
2051
2052 var dropped = false;
2053 $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
2054
2055 if(!this.options) return;
2056 if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance))
2057 dropped = this._drop.call(this, event) || dropped;
2058
2059 if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
2060 this.isout = 1; this.isover = 0;
2061 this._deactivate.call(this, event);
2062 }
2063
2064 });
2065 return dropped;
2066
2067 },
2068 dragStart: function( draggable, event ) {
2069 //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
2070 draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
2071 if( !draggable.options.refreshPositions ) $.ui.ddmanager.prepareOffsets( draggable, event );
2072 });
2073 },
2074 drag: function(draggable, event) {
2075
2076 //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
2077 if(draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event);
2078
2079 //Run through all droppables and check their positions based on specific tolerance options
2080 $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
2081
2082 if(this.options.disabled || this.greedyChild || !this.visible) return;
2083 var intersects = $.ui.intersect(draggable, this, this.options.tolerance);
2084
2085 var c = !intersects && this.isover == 1 ? 'isout' : (intersects && this.isover == 0 ? 'isover' : null);
2086 if(!c) return;
2087
2088 var parentInstance;
2089 if (this.options.greedy) {
2090 // find droppable parents with same scope
2091 var scope = this.options.scope;
2092 var parent = this.element.parents(':data(droppable)').filter(function () {
2093 return $.data(this, 'droppable').options.scope === scope;
2094 });
2095
2096 if (parent.length) {
2097 parentInstance = $.data(parent[0], 'droppable');
2098 parentInstance.greedyChild = (c == 'isover' ? 1 : 0);
2099 }
2100 }
2101
2102 // we just moved into a greedy child
2103 if (parentInstance && c == 'isover') {
2104 parentInstance['isover'] = 0;
2105 parentInstance['isout'] = 1;
2106 parentInstance._out.call(parentInstance, event);
2107 }
2108
2109 this[c] = 1; this[c == 'isout' ? 'isover' : 'isout'] = 0;
2110 this[c == "isover" ? "_over" : "_out"].call(this, event);
2111
2112 // we just moved out of a greedy child
2113 if (parentInstance && c == 'isout') {
2114 parentInstance['isout'] = 0;
2115 parentInstance['isover'] = 1;
2116 parentInstance._over.call(parentInstance, event);
2117 }
2118 });
2119
2120 },
2121 dragStop: function( draggable, event ) {
2122 draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
2123 //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
2124 if( !draggable.options.refreshPositions ) $.ui.ddmanager.prepareOffsets( draggable, event );
2125 }
2126};
2127
2128})(jQuery);
2129
2130(function( $, undefined ) {
2131
2132$.widget("ui.resizable", $.ui.mouse, {
2133 version: "1.9.2",
2134 widgetEventPrefix: "resize",
2135 options: {
2136 alsoResize: false,
2137 animate: false,
2138 animateDuration: "slow",
2139 animateEasing: "swing",
2140 aspectRatio: false,
2141 autoHide: false,
2142 containment: false,
2143 ghost: false,
2144 grid: false,
2145 handles: "e,s,se",
2146 helper: false,
2147 maxHeight: null,
2148 maxWidth: null,
2149 minHeight: 10,
2150 minWidth: 10,
2151 zIndex: 1000
2152 },
2153 _create: function() {
2154
2155 var that = this, o = this.options;
2156 this.element.addClass("ui-resizable");
2157
2158 $.extend(this, {
2159 _aspectRatio: !!(o.aspectRatio),
2160 aspectRatio: o.aspectRatio,
2161 originalElement: this.element,
2162 _proportionallyResizeElements: [],
2163 _helper: o.helper || o.ghost || o.animate ? o.helper || 'ui-resizable-helper' : null
2164 });
2165
2166 //Wrap the element if it cannot hold child nodes
2167 if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {
2168
2169 //Create a wrapper element and set the wrapper to the new current internal element
2170 this.element.wrap(
2171 $('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({
2172 position: this.element.css('position'),
2173 width: this.element.outerWidth(),
2174 height: this.element.outerHeight(),
2175 top: this.element.css('top'),
2176 left: this.element.css('left')
2177 })
2178 );
2179
2180 //Overwrite the original this.element
2181 this.element = this.element.parent().data(
2182 "resizable", this.element.data('resizable')
2183 );
2184
2185 this.elementIsWrapper = true;
2186
2187 //Move margins to the wrapper
2188 this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") });
2189 this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});
2190
2191 //Prevent Safari textarea resize
2192 this.originalResizeStyle = this.originalElement.css('resize');
2193 this.originalElement.css('resize', 'none');
2194
2195 //Push the actual element to our proportionallyResize internal array
2196 this._proportionallyResizeElements.push(this.originalElement.css({ position: 'static', zoom: 1, display: 'block' }));
2197
2198 // avoid IE jump (hard set the margin)
2199 this.originalElement.css({ margin: this.originalElement.css('margin') });
2200
2201 // fix handlers offset
2202 this._proportionallyResize();
2203
2204 }
2205
2206 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' });
2207 if(this.handles.constructor == String) {
2208
2209 if(this.handles == 'all') this.handles = 'n,e,s,w,se,sw,ne,nw';
2210 var n = this.handles.split(","); this.handles = {};
2211
2212 for(var i = 0; i < n.length; i++) {
2213
2214 var handle = $.trim(n[i]), hname = 'ui-resizable-'+handle;
2215 var axis = $('<div class="ui-resizable-handle ' + hname + '"></div>');
2216
2217 // Apply zIndex to all handles - see #7960
2218 axis.css({ zIndex: o.zIndex });
2219
2220 //TODO : What's going on here?
2221 if ('se' == handle) {
2222 axis.addClass('ui-icon ui-icon-gripsmall-diagonal-se');
2223 };
2224
2225 //Insert into internal handles object and append to element
2226 this.handles[handle] = '.ui-resizable-'+handle;
2227 this.element.append(axis);
2228 }
2229
2230 }
2231
2232 this._renderAxis = function(target) {
2233
2234 target = target || this.element;
2235
2236 for(var i in this.handles) {
2237
2238 if(this.handles[i].constructor == String)
2239 this.handles[i] = $(this.handles[i], this.element).show();
2240
2241 //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)
2242 if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {
2243
2244 var axis = $(this.handles[i], this.element), padWrapper = 0;
2245
2246 //Checking the correct pad and border
2247 padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
2248
2249 //The padding type i have to apply...
2250 var padPos = [ 'padding',
2251 /ne|nw|n/.test(i) ? 'Top' :
2252 /se|sw|s/.test(i) ? 'Bottom' :
2253 /^e$/.test(i) ? 'Right' : 'Left' ].join("");
2254
2255 target.css(padPos, padWrapper);
2256
2257 this._proportionallyResize();
2258
2259 }
2260
2261 //TODO: What's that good for? There's not anything to be executed left
2262 if(!$(this.handles[i]).length)
2263 continue;
2264
2265 }
2266 };
2267
2268 //TODO: make renderAxis a prototype function
2269 this._renderAxis(this.element);
2270
2271 this._handles = $('.ui-resizable-handle', this.element)
2272 .disableSelection();
2273
2274 //Matching axis name
2275 this._handles.mouseover(function() {
2276 if (!that.resizing) {
2277 if (this.className)
2278 var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
2279 //Axis, default = se
2280 that.axis = axis && axis[1] ? axis[1] : 'se';
2281 }
2282 });
2283
2284 //If we want to auto hide the elements
2285 if (o.autoHide) {
2286 this._handles.hide();
2287 $(this.element)
2288 .addClass("ui-resizable-autohide")
2289 .mouseenter(function() {
2290 if (o.disabled) return;
2291 $(this).removeClass("ui-resizable-autohide");
2292 that._handles.show();
2293 })
2294 .mouseleave(function(){
2295 if (o.disabled) return;
2296 if (!that.resizing) {
2297 $(this).addClass("ui-resizable-autohide");
2298 that._handles.hide();
2299 }
2300 });
2301 }
2302
2303 //Initialize the mouse interaction
2304 this._mouseInit();
2305
2306 },
2307
2308 _destroy: function() {
2309
2310 this._mouseDestroy();
2311
2312 var _destroy = function(exp) {
2313 $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
2314 .removeData("resizable").removeData("ui-resizable").unbind(".resizable").find('.ui-resizable-handle').remove();
2315 };
2316
2317 //TODO: Unwrap at same DOM position
2318 if (this.elementIsWrapper) {
2319 _destroy(this.element);
2320 var wrapper = this.element;
2321 this.originalElement.css({
2322 position: wrapper.css('position'),
2323 width: wrapper.outerWidth(),
2324 height: wrapper.outerHeight(),
2325 top: wrapper.css('top'),
2326 left: wrapper.css('left')
2327 }).insertAfter( wrapper );
2328 wrapper.remove();
2329 }
2330
2331 this.originalElement.css('resize', this.originalResizeStyle);
2332 _destroy(this.originalElement);
2333
2334 return this;
2335 },
2336
2337 _mouseCapture: function(event) {
2338 var handle = false;
2339 for (var i in this.handles) {
2340 if ($(this.handles[i])[0] == event.target) {
2341 handle = true;
2342 }
2343 }
2344
2345 return !this.options.disabled && handle;
2346 },
2347
2348 _mouseStart: function(event) {
2349
2350 var o = this.options, iniPos = this.element.position(), el = this.element;
2351
2352 this.resizing = true;
2353 this.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() };
2354
2355 // bugfix for http://dev.jquery.com/ticket/1749
2356 if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) {
2357 el.css({ position: 'absolute', top: iniPos.top, left: iniPos.left });
2358 }
2359
2360 this._renderProxy();
2361
2362 var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top'));
2363
2364 if (o.containment) {
2365 curleft += $(o.containment).scrollLeft() || 0;
2366 curtop += $(o.containment).scrollTop() || 0;
2367 }
2368
2369 //Store needed variables
2370 this.offset = this.helper.offset();
2371 this.position = { left: curleft, top: curtop };
2372 this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
2373 this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
2374 this.originalPosition = { left: curleft, top: curtop };
2375 this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };
2376 this.originalMousePosition = { left: event.pageX, top: event.pageY };
2377
2378 //Aspect Ratio
2379 this.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1);
2380
2381 var cursor = $('.ui-resizable-' + this.axis).css('cursor');
2382 $('body').css('cursor', cursor == 'auto' ? this.axis + '-resize' : cursor);
2383
2384 el.addClass("ui-resizable-resizing");
2385 this._propagate("start", event);
2386 return true;
2387 },
2388
2389 _mouseDrag: function(event) {
2390
2391 //Increase performance, avoid regex
2392 var el = this.helper, o = this.options, props = {},
2393 that = this, smp = this.originalMousePosition, a = this.axis;
2394
2395 var dx = (event.pageX-smp.left)||0, dy = (event.pageY-smp.top)||0;
2396 var trigger = this._change[a];
2397 if (!trigger) return false;
2398
2399 // Calculate the attrs that will be change
2400 var data = trigger.apply(this, [event, dx, dy]);
2401
2402 // Put this in the mouseDrag handler since the user can start pressing shift while resizing
2403 this._updateVirtualBoundaries(event.shiftKey);
2404 if (this._aspectRatio || event.shiftKey)
2405 data = this._updateRatio(data, event);
2406
2407 data = this._respectSize(data, event);
2408
2409 // plugins callbacks need to be called first
2410 this._propagate("resize", event);
2411
2412 el.css({
2413 top: this.position.top + "px", left: this.position.left + "px",
2414 width: this.size.width + "px", height: this.size.height + "px"
2415 });
2416
2417 if (!this._helper && this._proportionallyResizeElements.length)
2418 this._proportionallyResize();
2419
2420 this._updateCache(data);
2421
2422 // calling the user callback at the end
2423 this._trigger('resize', event, this.ui());
2424
2425 return false;
2426 },
2427
2428 _mouseStop: function(event) {
2429
2430 this.resizing = false;
2431 var o = this.options, that = this;
2432
2433 if(this._helper) {
2434 var pr = this._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName),
2435 soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : that.sizeDiff.height,
2436 soffsetw = ista ? 0 : that.sizeDiff.width;
2437
2438 var s = { width: (that.helper.width() - soffsetw), height: (that.helper.height() - soffseth) },
2439 left = (parseInt(that.element.css('left'), 10) + (that.position.left - that.originalPosition.left)) || null,
2440 top = (parseInt(that.element.css('top'), 10) + (that.position.top - that.originalPosition.top)) || null;
2441
2442 if (!o.animate)
2443 this.element.css($.extend(s, { top: top, left: left }));
2444
2445 that.helper.height(that.size.height);
2446 that.helper.width(that.size.width);
2447
2448 if (this._helper && !o.animate) this._proportionallyResize();
2449 }
2450
2451 $('body').css('cursor', 'auto');
2452
2453 this.element.removeClass("ui-resizable-resizing");
2454
2455 this._propagate("stop", event);
2456
2457 if (this._helper) this.helper.remove();
2458 return false;
2459
2460 },
2461
2462 _updateVirtualBoundaries: function(forceAspectRatio) {
2463 var o = this.options, pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b;
2464
2465 b = {
2466 minWidth: isNumber(o.minWidth) ? o.minWidth : 0,
2467 maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity,
2468 minHeight: isNumber(o.minHeight) ? o.minHeight : 0,
2469 maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity
2470 };
2471
2472 if(this._aspectRatio || forceAspectRatio) {
2473 // We want to create an enclosing box whose aspect ration is the requested one
2474 // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension
2475 pMinWidth = b.minHeight * this.aspectRatio;
2476 pMinHeight = b.minWidth / this.aspectRatio;
2477 pMaxWidth = b.maxHeight * this.aspectRatio;
2478 pMaxHeight = b.maxWidth / this.aspectRatio;
2479
2480 if(pMinWidth > b.minWidth) b.minWidth = pMinWidth;
2481 if(pMinHeight > b.minHeight) b.minHeight = pMinHeight;
2482 if(pMaxWidth < b.maxWidth) b.maxWidth = pMaxWidth;
2483 if(pMaxHeight < b.maxHeight) b.maxHeight = pMaxHeight;
2484 }
2485 this._vBoundaries = b;
2486 },
2487
2488 _updateCache: function(data) {
2489 var o = this.options;
2490 this.offset = this.helper.offset();
2491 if (isNumber(data.left)) this.position.left = data.left;
2492 if (isNumber(data.top)) this.position.top = data.top;
2493 if (isNumber(data.height)) this.size.height = data.height;
2494 if (isNumber(data.width)) this.size.width = data.width;
2495 },
2496
2497 _updateRatio: function(data, event) {
2498
2499 var o = this.options, cpos = this.position, csize = this.size, a = this.axis;
2500
2501 if (isNumber(data.height)) data.width = (data.height * this.aspectRatio);
2502 else if (isNumber(data.width)) data.height = (data.width / this.aspectRatio);
2503
2504 if (a == 'sw') {
2505 data.left = cpos.left + (csize.width - data.width);
2506 data.top = null;
2507 }
2508 if (a == 'nw') {
2509 data.top = cpos.top + (csize.height - data.height);
2510 data.left = cpos.left + (csize.width - data.width);
2511 }
2512
2513 return data;
2514 },
2515
2516 _respectSize: function(data, event) {
2517
2518 var el = this.helper, o = this._vBoundaries, pRatio = this._aspectRatio || event.shiftKey, a = this.axis,
2519 ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
2520 isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height);
2521
2522 if (isminw) data.width = o.minWidth;
2523 if (isminh) data.height = o.minHeight;
2524 if (ismaxw) data.width = o.maxWidth;
2525 if (ismaxh) data.height = o.maxHeight;
2526
2527 var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height;
2528 var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
2529
2530 if (isminw && cw) data.left = dw - o.minWidth;
2531 if (ismaxw && cw) data.left = dw - o.maxWidth;
2532 if (isminh && ch) data.top = dh - o.minHeight;
2533 if (ismaxh && ch) data.top = dh - o.maxHeight;
2534
2535 // fixing jump error on top/left - bug #2330
2536 var isNotwh = !data.width && !data.height;
2537 if (isNotwh && !data.left && data.top) data.top = null;
2538 else if (isNotwh && !data.top && data.left) data.left = null;
2539
2540 return data;
2541 },
2542
2543 _proportionallyResize: function() {
2544
2545 var o = this.options;
2546 if (!this._proportionallyResizeElements.length) return;
2547 var element = this.helper || this.element;
2548
2549 for (var i=0; i < this._proportionallyResizeElements.length; i++) {
2550
2551 var prel = this._proportionallyResizeElements[i];
2552
2553 if (!this.borderDif) {
2554 var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')],
2555 p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')];
2556
2557 this.borderDif = $.map(b, function(v, i) {
2558 var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0;
2559 return border + padding;
2560 });
2561 }
2562
2563 prel.css({
2564 height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0,
2565 width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0
2566 });
2567
2568 };
2569
2570 },
2571
2572 _renderProxy: function() {
2573
2574 var el = this.element, o = this.options;
2575 this.elementOffset = el.offset();
2576
2577 if(this._helper) {
2578
2579 this.helper = this.helper || $('<div style="overflow:hidden;"></div>');
2580
2581 // fix ie6 offset TODO: This seems broken
2582 var ie6offset = ($.ui.ie6 ? 1 : 0),
2583 pxyoffset = ( $.ui.ie6 ? 2 : -1 );
2584
2585 this.helper.addClass(this._helper).css({
2586 width: this.element.outerWidth() + pxyoffset,
2587 height: this.element.outerHeight() + pxyoffset,
2588 position: 'absolute',
2589 left: this.elementOffset.left - ie6offset +'px',
2590 top: this.elementOffset.top - ie6offset +'px',
2591 zIndex: ++o.zIndex //TODO: Don't modify option
2592 });
2593
2594 this.helper
2595 .appendTo("body")
2596 .disableSelection();
2597
2598 } else {
2599 this.helper = this.element;
2600 }
2601
2602 },
2603
2604 _change: {
2605 e: function(event, dx, dy) {
2606 return { width: this.originalSize.width + dx };
2607 },
2608 w: function(event, dx, dy) {
2609 var o = this.options, cs = this.originalSize, sp = this.originalPosition;
2610 return { left: sp.left + dx, width: cs.width - dx };
2611 },
2612 n: function(event, dx, dy) {
2613 var o = this.options, cs = this.originalSize, sp = this.originalPosition;
2614 return { top: sp.top + dy, height: cs.height - dy };
2615 },
2616 s: function(event, dx, dy) {
2617 return { height: this.originalSize.height + dy };
2618 },
2619 se: function(event, dx, dy) {
2620 return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
2621 },
2622 sw: function(event, dx, dy) {
2623 return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
2624 },
2625 ne: function(event, dx, dy) {
2626 return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
2627 },
2628 nw: function(event, dx, dy) {
2629 return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
2630 }
2631 },
2632
2633 _propagate: function(n, event) {
2634 $.ui.plugin.call(this, n, [event, this.ui()]);
2635 (n != "resize" && this._trigger(n, event, this.ui()));
2636 },
2637
2638 plugins: {},
2639
2640 ui: function() {
2641 return {
2642 originalElement: this.originalElement,
2643 element: this.element,
2644 helper: this.helper,
2645 position: this.position,
2646 size: this.size,
2647 originalSize: this.originalSize,
2648 originalPosition: this.originalPosition
2649 };
2650 }
2651
2652});
2653
2654/*
2655 * Resizable Extensions
2656 */
2657
2658$.ui.plugin.add("resizable", "alsoResize", {
2659
2660 start: function (event, ui) {
2661 var that = $(this).data("resizable"), o = that.options;
2662
2663 var _store = function (exp) {
2664 $(exp).each(function() {
2665 var el = $(this);
2666 el.data("resizable-alsoresize", {
2667 width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
2668 left: parseInt(el.css('left'), 10), top: parseInt(el.css('top'), 10)
2669 });
2670 });
2671 };
2672
2673 if (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) {
2674 if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); }
2675 else { $.each(o.alsoResize, function (exp) { _store(exp); }); }
2676 }else{
2677 _store(o.alsoResize);
2678 }
2679 },
2680
2681 resize: function (event, ui) {
2682 var that = $(this).data("resizable"), o = that.options, os = that.originalSize, op = that.originalPosition;
2683
2684 var delta = {
2685 height: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0,
2686 top: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0
2687 },
2688
2689 _alsoResize = function (exp, c) {
2690 $(exp).each(function() {
2691 var el = $(this), start = $(this).data("resizable-alsoresize"), style = {},
2692 css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ['width', 'height'] : ['width', 'height', 'top', 'left'];
2693
2694 $.each(css, function (i, prop) {
2695 var sum = (start[prop]||0) + (delta[prop]||0);
2696 if (sum && sum >= 0)
2697 style[prop] = sum || null;
2698 });
2699
2700 el.css(style);
2701 });
2702 };
2703
2704 if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) {
2705 $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); });
2706 }else{
2707 _alsoResize(o.alsoResize);
2708 }
2709 },
2710
2711 stop: function (event, ui) {
2712 $(this).removeData("resizable-alsoresize");
2713 }
2714});
2715
2716$.ui.plugin.add("resizable", "animate", {
2717
2718 stop: function(event, ui) {
2719 var that = $(this).data("resizable"), o = that.options;
2720
2721 var pr = that._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName),
2722 soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : that.sizeDiff.height,
2723 soffsetw = ista ? 0 : that.sizeDiff.width;
2724
2725 var style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) },
2726 left = (parseInt(that.element.css('left'), 10) + (that.position.left - that.originalPosition.left)) || null,
2727 top = (parseInt(that.element.css('top'), 10) + (that.position.top - that.originalPosition.top)) || null;
2728
2729 that.element.animate(
2730 $.extend(style, top && left ? { top: top, left: left } : {}), {
2731 duration: o.animateDuration,
2732 easing: o.animateEasing,
2733 step: function() {
2734
2735 var data = {
2736 width: parseInt(that.element.css('width'), 10),
2737 height: parseInt(that.element.css('height'), 10),
2738 top: parseInt(that.element.css('top'), 10),
2739 left: parseInt(that.element.css('left'), 10)
2740 };
2741
2742 if (pr && pr.length) $(pr[0]).css({ width: data.width, height: data.height });
2743
2744 // propagating resize, and updating values for each animation step
2745 that._updateCache(data);
2746 that._propagate("resize", event);
2747
2748 }
2749 }
2750 );
2751 }
2752
2753});
2754
2755$.ui.plugin.add("resizable", "containment", {
2756
2757 start: function(event, ui) {
2758 var that = $(this).data("resizable"), o = that.options, el = that.element;
2759 var oc = o.containment, ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc;
2760 if (!ce) return;
2761
2762 that.containerElement = $(ce);
2763
2764 if (/document/.test(oc) || oc == document) {
2765 that.containerOffset = { left: 0, top: 0 };
2766 that.containerPosition = { left: 0, top: 0 };
2767
2768 that.parentData = {
2769 element: $(document), left: 0, top: 0,
2770 width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight
2771 };
2772 }
2773
2774 // i'm a node, so compute top, left, right, bottom
2775 else {
2776 var element = $(ce), p = [];
2777 $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); });
2778
2779 that.containerOffset = element.offset();
2780 that.containerPosition = element.position();
2781 that.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) };
2782
2783 var co = that.containerOffset, ch = that.containerSize.height, cw = that.containerSize.width,
2784 width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch);
2785
2786 that.parentData = {
2787 element: ce, left: co.left, top: co.top, width: width, height: height
2788 };
2789 }
2790 },
2791
2792 resize: function(event, ui) {
2793 var that = $(this).data("resizable"), o = that.options,
2794 ps = that.containerSize, co = that.containerOffset, cs = that.size, cp = that.position,
2795 pRatio = that._aspectRatio || event.shiftKey, cop = { top:0, left:0 }, ce = that.containerElement;
2796
2797 if (ce[0] != document && (/static/).test(ce.css('position'))) cop = co;
2798
2799 if (cp.left < (that._helper ? co.left : 0)) {
2800 that.size.width = that.size.width + (that._helper ? (that.position.left - co.left) : (that.position.left - cop.left));
2801 if (pRatio) that.size.height = that.size.width / that.aspectRatio;
2802 that.position.left = o.helper ? co.left : 0;
2803 }
2804
2805 if (cp.top < (that._helper ? co.top : 0)) {
2806 that.size.height = that.size.height + (that._helper ? (that.position.top - co.top) : that.position.top);
2807 if (pRatio) that.size.width = that.size.height * that.aspectRatio;
2808 that.position.top = that._helper ? co.top : 0;
2809 }
2810
2811 that.offset.left = that.parentData.left+that.position.left;
2812 that.offset.top = that.parentData.top+that.position.top;
2813
2814 var woset = Math.abs( (that._helper ? that.offset.left - cop.left : (that.offset.left - cop.left)) + that.sizeDiff.width ),
2815 hoset = Math.abs( (that._helper ? that.offset.top - cop.top : (that.offset.top - co.top)) + that.sizeDiff.height );
2816
2817 var isParent = that.containerElement.get(0) == that.element.parent().get(0),
2818 isOffsetRelative = /relative|absolute/.test(that.containerElement.css('position'));
2819
2820 if(isParent && isOffsetRelative) woset -= that.parentData.left;
2821
2822 if (woset + that.size.width >= that.parentData.width) {
2823 that.size.width = that.parentData.width - woset;
2824 if (pRatio) that.size.height = that.size.width / that.aspectRatio;
2825 }
2826
2827 if (hoset + that.size.height >= that.parentData.height) {
2828 that.size.height = that.parentData.height - hoset;
2829 if (pRatio) that.size.width = that.size.height * that.aspectRatio;
2830 }
2831 },
2832
2833 stop: function(event, ui){
2834 var that = $(this).data("resizable"), o = that.options, cp = that.position,
2835 co = that.containerOffset, cop = that.containerPosition, ce = that.containerElement;
2836
2837 var helper = $(that.helper), ho = helper.offset(), w = helper.outerWidth() - that.sizeDiff.width, h = helper.outerHeight() - that.sizeDiff.height;
2838
2839 if (that._helper && !o.animate && (/relative/).test(ce.css('position')))
2840 $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
2841
2842 if (that._helper && !o.animate && (/static/).test(ce.css('position')))
2843 $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
2844
2845 }
2846});
2847
2848$.ui.plugin.add("resizable", "ghost", {
2849
2850 start: function(event, ui) {
2851
2852 var that = $(this).data("resizable"), o = that.options, cs = that.size;
2853
2854 that.ghost = that.originalElement.clone();
2855 that.ghost
2856 .css({ opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 })
2857 .addClass('ui-resizable-ghost')
2858 .addClass(typeof o.ghost == 'string' ? o.ghost : '');
2859
2860 that.ghost.appendTo(that.helper);
2861
2862 },
2863
2864 resize: function(event, ui){
2865 var that = $(this).data("resizable"), o = that.options;
2866 if (that.ghost) that.ghost.css({ position: 'relative', height: that.size.height, width: that.size.width });
2867 },
2868
2869 stop: function(event, ui){
2870 var that = $(this).data("resizable"), o = that.options;
2871 if (that.ghost && that.helper) that.helper.get(0).removeChild(that.ghost.get(0));
2872 }
2873
2874});
2875
2876$.ui.plugin.add("resizable", "grid", {
2877
2878 resize: function(event, ui) {
2879 var that = $(this).data("resizable"), o = that.options, cs = that.size, os = that.originalSize, op = that.originalPosition, a = that.axis, ratio = o._aspectRatio || event.shiftKey;
2880 o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid;
2881 var ox = Math.round((cs.width - os.width) / (o.grid[0]||1)) * (o.grid[0]||1), oy = Math.round((cs.height - os.height) / (o.grid[1]||1)) * (o.grid[1]||1);
2882
2883 if (/^(se|s|e)$/.test(a)) {
2884 that.size.width = os.width + ox;
2885 that.size.height = os.height + oy;
2886 }
2887 else if (/^(ne)$/.test(a)) {
2888 that.size.width = os.width + ox;
2889 that.size.height = os.height + oy;
2890 that.position.top = op.top - oy;
2891 }
2892 else if (/^(sw)$/.test(a)) {
2893 that.size.width = os.width + ox;
2894 that.size.height = os.height + oy;
2895 that.position.left = op.left - ox;
2896 }
2897 else {
2898 that.size.width = os.width + ox;
2899 that.size.height = os.height + oy;
2900 that.position.top = op.top - oy;
2901 that.position.left = op.left - ox;
2902 }
2903 }
2904
2905});
2906
2907var num = function(v) {
2908 return parseInt(v, 10) || 0;
2909};
2910
2911var isNumber = function(value) {
2912 return !isNaN(parseInt(value, 10));
2913};
2914
2915})(jQuery);
2916
2917(function( $, undefined ) {
2918
2919$.widget("ui.selectable", $.ui.mouse, {
2920 version: "1.9.2",
2921 options: {
2922 appendTo: 'body',
2923 autoRefresh: true,
2924 distance: 0,
2925 filter: '*',
2926 tolerance: 'touch'
2927 },
2928 _create: function() {
2929 var that = this;
2930
2931 this.element.addClass("ui-selectable");
2932
2933 this.dragged = false;
2934
2935 // cache selectee children based on filter
2936 var selectees;
2937 this.refresh = function() {
2938 selectees = $(that.options.filter, that.element[0]);
2939 selectees.addClass("ui-selectee");
2940 selectees.each(function() {
2941 var $this = $(this);
2942 var pos = $this.offset();
2943 $.data(this, "selectable-item", {
2944 element: this,
2945 $element: $this,
2946 left: pos.left,
2947 top: pos.top,
2948 right: pos.left + $this.outerWidth(),
2949 bottom: pos.top + $this.outerHeight(),
2950 startselected: false,
2951 selected: $this.hasClass('ui-selected'),
2952 selecting: $this.hasClass('ui-selecting'),
2953 unselecting: $this.hasClass('ui-unselecting')
2954 });
2955 });
2956 };
2957 this.refresh();
2958
2959 this.selectees = selectees.addClass("ui-selectee");
2960
2961 this._mouseInit();
2962
2963 this.helper = $("<div class='ui-selectable-helper'></div>");
2964 },
2965
2966 _destroy: function() {
2967 this.selectees
2968 .removeClass("ui-selectee")
2969 .removeData("selectable-item");
2970 this.element
2971 .removeClass("ui-selectable ui-selectable-disabled");
2972 this._mouseDestroy();
2973 },
2974
2975 _mouseStart: function(event) {
2976 var that = this;
2977
2978 this.opos = [event.pageX, event.pageY];
2979
2980 if (this.options.disabled)
2981 return;
2982
2983 var options = this.options;
2984
2985 this.selectees = $(options.filter, this.element[0]);
2986
2987 this._trigger("start", event);
2988
2989 $(options.appendTo).append(this.helper);
2990 // position helper (lasso)
2991 this.helper.css({
2992 "left": event.clientX,
2993 "top": event.clientY,
2994 "width": 0,
2995 "height": 0
2996 });
2997
2998 if (options.autoRefresh) {
2999 this.refresh();
3000 }
3001
3002 this.selectees.filter('.ui-selected').each(function() {
3003 var selectee = $.data(this, "selectable-item");
3004 selectee.startselected = true;
3005 if (!event.metaKey && !event.ctrlKey) {
3006 selectee.$element.removeClass('ui-selected');
3007 selectee.selected = false;
3008 selectee.$element.addClass('ui-unselecting');
3009 selectee.unselecting = true;
3010 // selectable UNSELECTING callback
3011 that._trigger("unselecting", event, {
3012 unselecting: selectee.element
3013 });
3014 }
3015 });
3016
3017 $(event.target).parents().andSelf().each(function() {
3018 var selectee = $.data(this, "selectable-item");
3019 if (selectee) {
3020 var doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass('ui-selected');
3021 selectee.$element
3022 .removeClass(doSelect ? "ui-unselecting" : "ui-selected")
3023 .addClass(doSelect ? "ui-selecting" : "ui-unselecting");
3024 selectee.unselecting = !doSelect;
3025 selectee.selecting = doSelect;
3026 selectee.selected = doSelect;
3027 // selectable (UN)SELECTING callback
3028 if (doSelect) {
3029 that._trigger("selecting", event, {
3030 selecting: selectee.element
3031 });
3032 } else {
3033 that._trigger("unselecting", event, {
3034 unselecting: selectee.element
3035 });
3036 }
3037 return false;
3038 }
3039 });
3040
3041 },
3042
3043 _mouseDrag: function(event) {
3044 var that = this;
3045 this.dragged = true;
3046
3047 if (this.options.disabled)
3048 return;
3049
3050 var options = this.options;
3051
3052 var x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY;
3053 if (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; }
3054 if (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; }
3055 this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1});
3056
3057 this.selectees.each(function() {
3058 var selectee = $.data(this, "selectable-item");
3059 //prevent helper from being selected if appendTo: selectable
3060 if (!selectee || selectee.element == that.element[0])
3061 return;
3062 var hit = false;
3063 if (options.tolerance == 'touch') {
3064 hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
3065 } else if (options.tolerance == 'fit') {
3066 hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
3067 }
3068
3069 if (hit) {
3070 // SELECT
3071 if (selectee.selected) {
3072 selectee.$element.removeClass('ui-selected');
3073 selectee.selected = false;
3074 }
3075 if (selectee.unselecting) {
3076 selectee.$element.removeClass('ui-unselecting');
3077 selectee.unselecting = false;
3078 }
3079 if (!selectee.selecting) {
3080 selectee.$element.addClass('ui-selecting');
3081 selectee.selecting = true;
3082 // selectable SELECTING callback
3083 that._trigger("selecting", event, {
3084 selecting: selectee.element
3085 });
3086 }
3087 } else {
3088 // UNSELECT
3089 if (selectee.selecting) {
3090 if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
3091 selectee.$element.removeClass('ui-selecting');
3092 selectee.selecting = false;
3093 selectee.$element.addClass('ui-selected');
3094 selectee.selected = true;
3095 } else {
3096 selectee.$element.removeClass('ui-selecting');
3097 selectee.selecting = false;
3098 if (selectee.startselected) {
3099 selectee.$element.addClass('ui-unselecting');
3100 selectee.unselecting = true;
3101 }
3102 // selectable UNSELECTING callback
3103 that._trigger("unselecting", event, {
3104 unselecting: selectee.element
3105 });
3106 }
3107 }
3108 if (selectee.selected) {
3109 if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
3110 selectee.$element.removeClass('ui-selected');
3111 selectee.selected = false;
3112
3113 selectee.$element.addClass('ui-unselecting');
3114 selectee.unselecting = true;
3115 // selectable UNSELECTING callback
3116 that._trigger("unselecting", event, {
3117 unselecting: selectee.element
3118 });
3119 }
3120 }
3121 }
3122 });
3123
3124 return false;
3125 },
3126
3127 _mouseStop: function(event) {
3128 var that = this;
3129
3130 this.dragged = false;
3131
3132 var options = this.options;
3133
3134 $('.ui-unselecting', this.element[0]).each(function() {
3135 var selectee = $.data(this, "selectable-item");
3136 selectee.$element.removeClass('ui-unselecting');
3137 selectee.unselecting = false;
3138 selectee.startselected = false;
3139 that._trigger("unselected", event, {
3140 unselected: selectee.element
3141 });
3142 });
3143 $('.ui-selecting', this.element[0]).each(function() {
3144 var selectee = $.data(this, "selectable-item");
3145 selectee.$element.removeClass('ui-selecting').addClass('ui-selected');
3146 selectee.selecting = false;
3147 selectee.selected = true;
3148 selectee.startselected = true;
3149 that._trigger("selected", event, {
3150 selected: selectee.element
3151 });
3152 });
3153 this._trigger("stop", event);
3154
3155 this.helper.remove();
3156
3157 return false;
3158 }
3159
3160});
3161
3162})(jQuery);
3163
3164(function( $, undefined ) {
3165
3166$.widget("ui.sortable", $.ui.mouse, {
3167 version: "1.9.2",
3168 widgetEventPrefix: "sort",
3169 ready: false,
3170 options: {
3171 appendTo: "parent",
3172 axis: false,
3173 connectWith: false,
3174 containment: false,
3175 cursor: 'auto',
3176 cursorAt: false,
3177 dropOnEmpty: true,
3178 forcePlaceholderSize: false,
3179 forceHelperSize: false,
3180 grid: false,
3181 handle: false,
3182 helper: "original",
3183 items: '> *',
3184 opacity: false,
3185 placeholder: false,
3186 revert: false,
3187 scroll: true,
3188 scrollSensitivity: 20,
3189 scrollSpeed: 20,
3190 scope: "default",
3191 tolerance: "intersect",
3192 zIndex: 1000
3193 },
3194 _create: function() {
3195
3196 var o = this.options;
3197 this.containerCache = {};
3198 this.element.addClass("ui-sortable");
3199
3200 //Get the items
3201 this.refresh();
3202
3203 //Let's determine if the items are being displayed horizontally
3204 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;
3205
3206 //Let's determine the parent's offset
3207 this.offset = this.element.offset();
3208
3209 //Initialize mouse events for interaction
3210 this._mouseInit();
3211
3212 //We're ready to go
3213 this.ready = true
3214
3215 },
3216
3217 _destroy: function() {
3218 this.element
3219 .removeClass("ui-sortable ui-sortable-disabled");
3220 this._mouseDestroy();
3221
3222 for ( var i = this.items.length - 1; i >= 0; i-- )
3223 this.items[i].item.removeData(this.widgetName + "-item");
3224
3225 return this;
3226 },
3227
3228 _setOption: function(key, value){
3229 if ( key === "disabled" ) {
3230 this.options[ key ] = value;
3231
3232 this.widget().toggleClass( "ui-sortable-disabled", !!value );
3233 } else {
3234 // Don't call widget base _setOption for disable as it adds ui-state-disabled class
3235 $.Widget.prototype._setOption.apply(this, arguments);
3236 }
3237 },
3238
3239 _mouseCapture: function(event, overrideHandle) {
3240 var that = this;
3241
3242 if (this.reverting) {
3243 return false;
3244 }
3245
3246 if(this.options.disabled || this.options.type == 'static') return false;
3247
3248 //We have to refresh the items data once first
3249 this._refreshItems(event);
3250
3251 //Find out if the clicked node (or one of its parents) is a actual item in this.items
3252 var currentItem = null, nodes = $(event.target).parents().each(function() {
3253 if($.data(this, that.widgetName + '-item') == that) {
3254 currentItem = $(this);
3255 return false;
3256 }
3257 });
3258 if($.data(event.target, that.widgetName + '-item') == that) currentItem = $(event.target);
3259
3260 if(!currentItem) return false;
3261 if(this.options.handle && !overrideHandle) {
3262 var validHandle = false;
3263
3264 $(this.options.handle, currentItem).find("*").andSelf().each(function() { if(this == event.target) validHandle = true; });
3265 if(!validHandle) return false;
3266 }
3267
3268 this.currentItem = currentItem;
3269 this._removeCurrentsFromItems();
3270 return true;
3271
3272 },
3273
3274 _mouseStart: function(event, overrideHandle, noActivation) {
3275
3276 var o = this.options;
3277 this.currentContainer = this;
3278
3279 //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
3280 this.refreshPositions();
3281
3282 //Create and append the visible helper
3283 this.helper = this._createHelper(event);
3284
3285 //Cache the helper size
3286 this._cacheHelperProportions();
3287
3288 /*
3289 * - Position generation -
3290 * This block generates everything position related - it's the core of draggables.
3291 */
3292
3293 //Cache the margins of the original element
3294 this._cacheMargins();
3295
3296 //Get the next scrolling parent
3297 this.scrollParent = this.helper.scrollParent();
3298
3299 //The element's absolute position on the page minus margins
3300 this.offset = this.currentItem.offset();
3301 this.offset = {
3302 top: this.offset.top - this.margins.top,
3303 left: this.offset.left - this.margins.left
3304 };
3305
3306 $.extend(this.offset, {
3307 click: { //Where the click happened, relative to the element
3308 left: event.pageX - this.offset.left,
3309 top: event.pageY - this.offset.top
3310 },
3311 parent: this._getParentOffset(),
3312 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
3313 });
3314
3315 // Only after we got the offset, we can change the helper's position to absolute
3316 // TODO: Still need to figure out a way to make relative sorting possible
3317 this.helper.css("position", "absolute");
3318 this.cssPosition = this.helper.css("position");
3319
3320 //Generate the original position
3321 this.originalPosition = this._generatePosition(event);
3322 this.originalPageX = event.pageX;
3323 this.originalPageY = event.pageY;
3324
3325 //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
3326 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
3327
3328 //Cache the former DOM position
3329 this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
3330
3331 //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
3332 if(this.helper[0] != this.currentItem[0]) {
3333 this.currentItem.hide();
3334 }
3335
3336 //Create the placeholder
3337 this._createPlaceholder();
3338
3339 //Set a containment if given in the options
3340 if(o.containment)
3341 this._setContainment();
3342
3343 if(o.cursor) { // cursor option
3344 if ($('body').css("cursor")) this._storedCursor = $('body').css("cursor");
3345 $('body').css("cursor", o.cursor);
3346 }
3347
3348 if(o.opacity) { // opacity option
3349 if (this.helper.css("opacity")) this._storedOpacity = this.helper.css("opacity");
3350 this.helper.css("opacity", o.opacity);
3351 }
3352
3353 if(o.zIndex) { // zIndex option
3354 if (this.helper.css("zIndex")) this._storedZIndex = this.helper.css("zIndex");
3355 this.helper.css("zIndex", o.zIndex);
3356 }
3357
3358 //Prepare scrolling
3359 if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML')
3360 this.overflowOffset = this.scrollParent.offset();
3361
3362 //Call callbacks
3363 this._trigger("start", event, this._uiHash());
3364
3365 //Recache the helper size
3366 if(!this._preserveHelperProportions)
3367 this._cacheHelperProportions();
3368
3369
3370 //Post 'activate' events to possible containers
3371 if(!noActivation) {
3372 for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i]._trigger("activate", event, this._uiHash(this)); }
3373 }
3374
3375 //Prepare possible droppables
3376 if($.ui.ddmanager)
3377 $.ui.ddmanager.current = this;
3378
3379 if ($.ui.ddmanager && !o.dropBehaviour)
3380 $.ui.ddmanager.prepareOffsets(this, event);
3381
3382 this.dragging = true;
3383
3384 this.helper.addClass("ui-sortable-helper");
3385 this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
3386 return true;
3387
3388 },
3389
3390 _mouseDrag: function(event) {
3391
3392 //Compute the helpers position
3393 this.position = this._generatePosition(event);
3394 this.positionAbs = this._convertPositionTo("absolute");
3395
3396 if (!this.lastPositionAbs) {
3397 this.lastPositionAbs = this.positionAbs;
3398 }
3399
3400 //Do scrolling
3401 if(this.options.scroll) {
3402 var o = this.options, scrolled = false;
3403 if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') {
3404
3405 if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
3406 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
3407 else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity)
3408 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
3409
3410 if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
3411 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
3412 else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity)
3413 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
3414
3415 } else {
3416
3417 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
3418 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
3419 else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
3420 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
3421
3422 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
3423 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
3424 else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
3425 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
3426
3427 }
3428
3429 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
3430 $.ui.ddmanager.prepareOffsets(this, event);
3431 }
3432
3433 //Regenerate the absolute position used for position checks
3434 this.positionAbs = this._convertPositionTo("absolute");
3435
3436 //Set the helper position
3437 if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
3438 if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
3439
3440 //Rearrange
3441 for (var i = this.items.length - 1; i >= 0; i--) {
3442
3443 //Cache variables and intersection, continue if no intersection
3444 var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item);
3445 if (!intersection) continue;
3446
3447 // Only put the placeholder inside the current Container, skip all
3448 // items form other containers. This works because when moving
3449 // an item from one container to another the
3450 // currentContainer is switched before the placeholder is moved.
3451 //
3452 // Without this moving items in "sub-sortables" can cause the placeholder to jitter
3453 // beetween the outer and inner container.
3454 if (item.instance !== this.currentContainer) continue;
3455
3456 if (itemElement != this.currentItem[0] //cannot intersect with itself
3457 && this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before
3458 && !$.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked
3459 && (this.options.type == 'semi-dynamic' ? !$.contains(this.element[0], itemElement) : true)
3460 //&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container
3461 ) {
3462
3463 this.direction = intersection == 1 ? "down" : "up";
3464
3465 if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) {
3466 this._rearrange(event, item);
3467 } else {
3468 break;
3469 }
3470
3471 this._trigger("change", event, this._uiHash());
3472 break;
3473 }
3474 }
3475
3476 //Post events to containers
3477 this._contactContainers(event);
3478
3479 //Interconnect with droppables
3480 if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
3481
3482 //Call callbacks
3483 this._trigger('sort', event, this._uiHash());
3484
3485 this.lastPositionAbs = this.positionAbs;
3486 return false;
3487
3488 },
3489
3490 _mouseStop: function(event, noPropagation) {
3491
3492 if(!event) return;
3493
3494 //If we are using droppables, inform the manager about the drop
3495 if ($.ui.ddmanager && !this.options.dropBehaviour)
3496 $.ui.ddmanager.drop(this, event);
3497
3498 if(this.options.revert) {
3499 var that = this;
3500 var cur = this.placeholder.offset();
3501
3502 this.reverting = true;
3503
3504 $(this.helper).animate({
3505 left: cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft),
3506 top: cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop)
3507 }, parseInt(this.options.revert, 10) || 500, function() {
3508 that._clear(event);
3509 });
3510 } else {
3511 this._clear(event, noPropagation);
3512 }
3513
3514 return false;
3515
3516 },
3517
3518 cancel: function() {
3519
3520 if(this.dragging) {
3521
3522 this._mouseUp({ target: null });
3523
3524 if(this.options.helper == "original")
3525 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
3526 else
3527 this.currentItem.show();
3528
3529 //Post deactivating events to containers
3530 for (var i = this.containers.length - 1; i >= 0; i--){
3531 this.containers[i]._trigger("deactivate", null, this._uiHash(this));
3532 if(this.containers[i].containerCache.over) {
3533 this.containers[i]._trigger("out", null, this._uiHash(this));
3534 this.containers[i].containerCache.over = 0;
3535 }
3536 }
3537
3538 }
3539
3540 if (this.placeholder) {
3541 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
3542 if(this.placeholder[0].parentNode) this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
3543 if(this.options.helper != "original" && this.helper && this.helper[0].parentNode) this.helper.remove();
3544
3545 $.extend(this, {
3546 helper: null,
3547 dragging: false,
3548 reverting: false,
3549 _noFinalSort: null
3550 });
3551
3552 if(this.domPosition.prev) {
3553 $(this.domPosition.prev).after(this.currentItem);
3554 } else {
3555 $(this.domPosition.parent).prepend(this.currentItem);
3556 }
3557 }
3558
3559 return this;
3560
3561 },
3562
3563 serialize: function(o) {
3564
3565 var items = this._getItemsAsjQuery(o && o.connected);
3566 var str = []; o = o || {};
3567
3568 $(items).each(function() {
3569 var res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
3570 if(res) str.push((o.key || res[1]+'[]')+'='+(o.key && o.expression ? res[1] : res[2]));
3571 });
3572
3573 if(!str.length && o.key) {
3574 str.push(o.key + '=');
3575 }
3576
3577 return str.join('&');
3578
3579 },
3580
3581 toArray: function(o) {
3582
3583 var items = this._getItemsAsjQuery(o && o.connected);
3584 var ret = []; o = o || {};
3585
3586 items.each(function() { ret.push($(o.item || this).attr(o.attribute || 'id') || ''); });
3587 return ret;
3588
3589 },
3590
3591 /* Be careful with the following core functions */
3592 _intersectsWith: function(item) {
3593
3594 var x1 = this.positionAbs.left,
3595 x2 = x1 + this.helperProportions.width,
3596 y1 = this.positionAbs.top,
3597 y2 = y1 + this.helperProportions.height;
3598
3599 var l = item.left,
3600 r = l + item.width,
3601 t = item.top,
3602 b = t + item.height;
3603
3604 var dyClick = this.offset.click.top,
3605 dxClick = this.offset.click.left;
3606
3607 var isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r;
3608
3609 if( this.options.tolerance == "pointer"
3610 || this.options.forcePointerForContainers
3611 || (this.options.tolerance != "pointer" && this.helperProportions[this.floating ? 'width' : 'height'] > item[this.floating ? 'width' : 'height'])
3612 ) {
3613 return isOverElement;
3614 } else {
3615
3616 return (l < x1 + (this.helperProportions.width / 2) // Right Half
3617 && x2 - (this.helperProportions.width / 2) < r // Left Half
3618 && t < y1 + (this.helperProportions.height / 2) // Bottom Half
3619 && y2 - (this.helperProportions.height / 2) < b ); // Top Half
3620
3621 }
3622 },
3623
3624 _intersectsWithPointer: function(item) {
3625
3626 var isOverElementHeight = (this.options.axis === 'x') || $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
3627 isOverElementWidth = (this.options.axis === 'y') || $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
3628 isOverElement = isOverElementHeight && isOverElementWidth,
3629 verticalDirection = this._getDragVerticalDirection(),
3630 horizontalDirection = this._getDragHorizontalDirection();
3631
3632 if (!isOverElement)
3633 return false;
3634
3635 return this.floating ?
3636 ( ((horizontalDirection && horizontalDirection == "right") || verticalDirection == "down") ? 2 : 1 )
3637 : ( verticalDirection && (verticalDirection == "down" ? 2 : 1) );
3638
3639 },
3640
3641 _intersectsWithSides: function(item) {
3642
3643 var isOverBottomHalf = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
3644 isOverRightHalf = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
3645 verticalDirection = this._getDragVerticalDirection(),
3646 horizontalDirection = this._getDragHorizontalDirection();
3647
3648 if (this.floating && horizontalDirection) {
3649 return ((horizontalDirection == "right" && isOverRightHalf) || (horizontalDirection == "left" && !isOverRightHalf));
3650 } else {
3651 return verticalDirection && ((verticalDirection == "down" && isOverBottomHalf) || (verticalDirection == "up" && !isOverBottomHalf));
3652 }
3653
3654 },
3655
3656 _getDragVerticalDirection: function() {
3657 var delta = this.positionAbs.top - this.lastPositionAbs.top;
3658 return delta != 0 && (delta > 0 ? "down" : "up");
3659 },
3660
3661 _getDragHorizontalDirection: function() {
3662 var delta = this.positionAbs.left - this.lastPositionAbs.left;
3663 return delta != 0 && (delta > 0 ? "right" : "left");
3664 },
3665
3666 refresh: function(event) {
3667 this._refreshItems(event);
3668 this.refreshPositions();
3669 return this;
3670 },
3671
3672 _connectWith: function() {
3673 var options = this.options;
3674 return options.connectWith.constructor == String
3675 ? [options.connectWith]
3676 : options.connectWith;
3677 },
3678
3679 _getItemsAsjQuery: function(connected) {
3680
3681 var items = [];
3682 var queries = [];
3683 var connectWith = this._connectWith();
3684
3685 if(connectWith && connected) {
3686 for (var i = connectWith.length - 1; i >= 0; i--){
3687 var cur = $(connectWith[i]);
3688 for (var j = cur.length - 1; j >= 0; j--){
3689 var inst = $.data(cur[j], this.widgetName);
3690 if(inst && inst != this && !inst.options.disabled) {
3691 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]);
3692 }
3693 };
3694 };
3695 }
3696
3697 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]);
3698
3699 for (var i = queries.length - 1; i >= 0; i--){
3700 queries[i][0].each(function() {
3701 items.push(this);
3702 });
3703 };
3704
3705 return $(items);
3706
3707 },
3708
3709 _removeCurrentsFromItems: function() {
3710
3711 var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
3712
3713 this.items = $.grep(this.items, function (item) {
3714 for (var j=0; j < list.length; j++) {
3715 if(list[j] == item.item[0])
3716 return false;
3717 };
3718 return true;
3719 });
3720
3721 },
3722
3723 _refreshItems: function(event) {
3724
3725 this.items = [];
3726 this.containers = [this];
3727 var items = this.items;
3728 var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]];
3729 var connectWith = this._connectWith();
3730
3731 if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
3732 for (var i = connectWith.length - 1; i >= 0; i--){
3733 var cur = $(connectWith[i]);
3734 for (var j = cur.length - 1; j >= 0; j--){
3735 var inst = $.data(cur[j], this.widgetName);
3736 if(inst && inst != this && !inst.options.disabled) {
3737 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
3738 this.containers.push(inst);
3739 }
3740 };
3741 };
3742 }
3743
3744 for (var i = queries.length - 1; i >= 0; i--) {
3745 var targetData = queries[i][1];
3746 var _queries = queries[i][0];
3747
3748 for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) {
3749 var item = $(_queries[j]);
3750
3751 item.data(this.widgetName + '-item', targetData); // Data for target checking (mouse manager)
3752
3753 items.push({
3754 item: item,
3755 instance: targetData,
3756 width: 0, height: 0,
3757 left: 0, top: 0
3758 });
3759 };
3760 };
3761
3762 },
3763
3764 refreshPositions: function(fast) {
3765
3766 //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
3767 if(this.offsetParent && this.helper) {
3768 this.offset.parent = this._getParentOffset();
3769 }
3770
3771 for (var i = this.items.length - 1; i >= 0; i--){
3772 var item = this.items[i];
3773
3774 //We ignore calculating positions of all connected containers when we're not over them
3775 if(item.instance != this.currentContainer && this.currentContainer && item.item[0] != this.currentItem[0])
3776 continue;
3777
3778 var t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
3779
3780 if (!fast) {
3781 item.width = t.outerWidth();
3782 item.height = t.outerHeight();
3783 }
3784
3785 var p = t.offset();
3786 item.left = p.left;
3787 item.top = p.top;
3788 };
3789
3790 if(this.options.custom && this.options.custom.refreshContainers) {
3791 this.options.custom.refreshContainers.call(this);
3792 } else {
3793 for (var i = this.containers.length - 1; i >= 0; i--){
3794 var p = this.containers[i].element.offset();
3795 this.containers[i].containerCache.left = p.left;
3796 this.containers[i].containerCache.top = p.top;
3797 this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
3798 this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
3799 };
3800 }
3801
3802 return this;
3803 },
3804
3805 _createPlaceholder: function(that) {
3806 that = that || this;
3807 var o = that.options;
3808
3809 if(!o.placeholder || o.placeholder.constructor == String) {
3810 var className = o.placeholder;
3811 o.placeholder = {
3812 element: function() {
3813
3814 var el = $(document.createElement(that.currentItem[0].nodeName))
3815 .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
3816 .removeClass("ui-sortable-helper")[0];
3817
3818 if(!className)
3819 el.style.visibility = "hidden";
3820
3821 return el;
3822 },
3823 update: function(container, p) {
3824
3825 // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
3826 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
3827 if(className && !o.forcePlaceholderSize) return;
3828
3829 //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
3830 if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css('paddingTop')||0, 10) - parseInt(that.currentItem.css('paddingBottom')||0, 10)); };
3831 if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css('paddingLeft')||0, 10) - parseInt(that.currentItem.css('paddingRight')||0, 10)); };
3832 }
3833 };
3834 }
3835
3836 //Create the placeholder
3837 that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));
3838
3839 //Append it after the actual current item
3840 that.currentItem.after(that.placeholder);
3841
3842 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
3843 o.placeholder.update(that, that.placeholder);
3844
3845 },
3846
3847 _contactContainers: function(event) {
3848
3849 // get innermost container that intersects with item
3850 var innermostContainer = null, innermostIndex = null;
3851
3852
3853 for (var i = this.containers.length - 1; i >= 0; i--){
3854
3855 // never consider a container that's located within the item itself
3856 if($.contains(this.currentItem[0], this.containers[i].element[0]))
3857 continue;
3858
3859 if(this._intersectsWith(this.containers[i].containerCache)) {
3860
3861 // if we've already found a container and it's more "inner" than this, then continue
3862 if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0]))
3863 continue;
3864
3865 innermostContainer = this.containers[i];
3866 innermostIndex = i;
3867
3868 } else {
3869 // container doesn't intersect. trigger "out" event if necessary
3870 if(this.containers[i].containerCache.over) {
3871 this.containers[i]._trigger("out", event, this._uiHash(this));
3872 this.containers[i].containerCache.over = 0;
3873 }
3874 }
3875
3876 }
3877
3878 // if no intersecting containers found, return
3879 if(!innermostContainer) return;
3880
3881 // move the item into the container if it's not there already
3882 if(this.containers.length === 1) {
3883 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
3884 this.containers[innermostIndex].containerCache.over = 1;
3885 } else {
3886
3887 //When entering a new container, we will find the item with the least distance and append our item near it
3888 var dist = 10000; var itemWithLeastDistance = null;
3889 var posProperty = this.containers[innermostIndex].floating ? 'left' : 'top';
3890 var sizeProperty = this.containers[innermostIndex].floating ? 'width' : 'height';
3891 var base = this.positionAbs[posProperty] + this.offset.click[posProperty];
3892 for (var j = this.items.length - 1; j >= 0; j--) {
3893 if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) continue;
3894 if(this.items[j].item[0] == this.currentItem[0]) continue;
3895 var cur = this.items[j].item.offset()[posProperty];
3896 var nearBottom = false;
3897 if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){
3898 nearBottom = true;
3899 cur += this.items[j][sizeProperty];
3900 }
3901
3902 if(Math.abs(cur - base) < dist) {
3903 dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j];
3904 this.direction = nearBottom ? "up": "down";
3905 }
3906 }
3907
3908 if(!itemWithLeastDistance && !this.options.dropOnEmpty) //Check if dropOnEmpty is enabled
3909 return;
3910
3911 this.currentContainer = this.containers[innermostIndex];
3912 itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
3913 this._trigger("change", event, this._uiHash());
3914 this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
3915
3916 //Update the placeholder
3917 this.options.placeholder.update(this.currentContainer, this.placeholder);
3918
3919 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
3920 this.containers[innermostIndex].containerCache.over = 1;
3921 }
3922
3923
3924 },
3925
3926 _createHelper: function(event) {
3927
3928 var o = this.options;
3929 var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper == 'clone' ? this.currentItem.clone() : this.currentItem);
3930
3931 if(!helper.parents('body').length) //Add the helper to the DOM if that didn't happen already
3932 $(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
3933
3934 if(helper[0] == this.currentItem[0])
3935 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") };
3936
3937 if(helper[0].style.width == '' || o.forceHelperSize) helper.width(this.currentItem.width());
3938 if(helper[0].style.height == '' || o.forceHelperSize) helper.height(this.currentItem.height());
3939
3940 return helper;
3941
3942 },
3943
3944 _adjustOffsetFromHelper: function(obj) {
3945 if (typeof obj == 'string') {
3946 obj = obj.split(' ');
3947 }
3948 if ($.isArray(obj)) {
3949 obj = {left: +obj[0], top: +obj[1] || 0};
3950 }
3951 if ('left' in obj) {
3952 this.offset.click.left = obj.left + this.margins.left;
3953 }
3954 if ('right' in obj) {
3955 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
3956 }
3957 if ('top' in obj) {
3958 this.offset.click.top = obj.top + this.margins.top;
3959 }
3960 if ('bottom' in obj) {
3961 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
3962 }
3963 },
3964
3965 _getParentOffset: function() {
3966
3967
3968 //Get the offsetParent and cache its position
3969 this.offsetParent = this.helper.offsetParent();
3970 var po = this.offsetParent.offset();
3971
3972 // This is a special case where we need to modify a offset calculated on start, since the following happened:
3973 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
3974 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
3975 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
3976 if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
3977 po.left += this.scrollParent.scrollLeft();
3978 po.top += this.scrollParent.scrollTop();
3979 }
3980
3981 if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information
3982 || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.ui.ie)) //Ugly IE fix
3983 po = { top: 0, left: 0 };
3984
3985 return {
3986 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
3987 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
3988 };
3989
3990 },
3991
3992 _getRelativeOffset: function() {
3993
3994 if(this.cssPosition == "relative") {
3995 var p = this.currentItem.position();
3996 return {
3997 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
3998 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
3999 };
4000 } else {
4001 return { top: 0, left: 0 };
4002 }
4003
4004 },
4005
4006 _cacheMargins: function() {
4007 this.margins = {
4008 left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
4009 top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
4010 };
4011 },
4012
4013 _cacheHelperProportions: function() {
4014 this.helperProportions = {
4015 width: this.helper.outerWidth(),
4016 height: this.helper.outerHeight()
4017 };
4018 },
4019
4020 _setContainment: function() {
4021
4022 var o = this.options;
4023 if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
4024 if(o.containment == 'document' || o.containment == 'window') this.containment = [
4025 0 - this.offset.relative.left - this.offset.parent.left,
4026 0 - this.offset.relative.top - this.offset.parent.top,
4027 $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left,
4028 ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
4029 ];
4030
4031 if(!(/^(document|window|parent)$/).test(o.containment)) {
4032 var ce = $(o.containment)[0];
4033 var co = $(o.containment).offset();
4034 var over = ($(ce).css("overflow") != 'hidden');
4035
4036 this.containment = [
4037 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
4038 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
4039 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,
4040 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
4041 ];
4042 }
4043
4044 },
4045
4046 _convertPositionTo: function(d, pos) {
4047
4048 if(!pos) pos = this.position;
4049 var mod = d == "absolute" ? 1 : -1;
4050 var o = this.options, 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);
4051
4052 return {
4053 top: (
4054 pos.top // The absolute mouse position
4055 + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent
4056 + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border)
4057 - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
4058 ),
4059 left: (
4060 pos.left // The absolute mouse position
4061 + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent
4062 + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border)
4063 - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
4064 )
4065 };
4066
4067 },
4068
4069 _generatePosition: function(event) {
4070
4071 var o = this.options, 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);
4072
4073 // This is another very weird special case that only happens for relative elements:
4074 // 1. If the css position is relative
4075 // 2. and the scroll parent is the document or similar to the offset parent
4076 // we have to refresh the relative offset during the scroll so there are no jumps
4077 if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) {
4078 this.offset.relative = this._getRelativeOffset();
4079 }
4080
4081 var pageX = event.pageX;
4082 var pageY = event.pageY;
4083
4084 /*
4085 * - Position constraining -
4086 * Constrain the position to a mix of grid, containment.
4087 */
4088
4089 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
4090
4091 if(this.containment) {
4092 if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left;
4093 if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top;
4094 if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left;
4095 if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top;
4096 }
4097
4098 if(o.grid) {
4099 var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
4100 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;
4101
4102 var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
4103 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;
4104 }
4105
4106 }
4107
4108 return {
4109 top: (
4110 pageY // The absolute mouse position
4111 - this.offset.click.top // Click offset (relative to the element)
4112 - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent
4113 - this.offset.parent.top // The offsetParent's offset without borders (offset + border)
4114 + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
4115 ),
4116 left: (
4117 pageX // The absolute mouse position
4118 - this.offset.click.left // Click offset (relative to the element)
4119 - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent
4120 - this.offset.parent.left // The offsetParent's offset without borders (offset + border)
4121 + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
4122 )
4123 };
4124
4125 },
4126
4127 _rearrange: function(event, i, a, hardRefresh) {
4128
4129 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));
4130
4131 //Various things done here to improve the performance:
4132 // 1. we create a setTimeout, that calls refreshPositions
4133 // 2. on the instance, we have a counter variable, that get's higher after every append
4134 // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
4135 // 4. this lets only the last addition to the timeout stack through
4136 this.counter = this.counter ? ++this.counter : 1;
4137 var counter = this.counter;
4138
4139 this._delay(function() {
4140 if(counter == this.counter) this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
4141 });
4142
4143 },
4144
4145 _clear: function(event, noPropagation) {
4146
4147 this.reverting = false;
4148 // We delay all events that have to be triggered to after the point where the placeholder has been removed and
4149 // everything else normalized again
4150 var delayedTriggers = [];
4151
4152 // We first have to update the dom position of the actual currentItem
4153 // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
4154 if(!this._noFinalSort && this.currentItem.parent().length) this.placeholder.before(this.currentItem);
4155 this._noFinalSort = null;
4156
4157 if(this.helper[0] == this.currentItem[0]) {
4158 for(var i in this._storedCSS) {
4159 if(this._storedCSS[i] == 'auto' || this._storedCSS[i] == 'static') this._storedCSS[i] = '';
4160 }
4161 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
4162 } else {
4163 this.currentItem.show();
4164 }
4165
4166 if(this.fromOutside && !noPropagation) delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
4167 if((this.fromOutside || this.domPosition.prev != this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent != this.currentItem.parent()[0]) && !noPropagation) delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
4168
4169 // Check if the items Container has Changed and trigger appropriate
4170 // events.
4171 if (this !== this.currentContainer) {
4172 if(!noPropagation) {
4173 delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
4174 delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
4175 delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
4176 }
4177 }
4178
4179
4180 //Post events to containers
4181 for (var i = this.containers.length - 1; i >= 0; i--){
4182 if(!noPropagation) delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
4183 if(this.containers[i].containerCache.over) {
4184 delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
4185 this.containers[i].containerCache.over = 0;
4186 }
4187 }
4188
4189 //Do what was originally in plugins
4190 if(this._storedCursor) $('body').css("cursor", this._storedCursor); //Reset cursor
4191 if(this._storedOpacity) this.helper.css("opacity", this._storedOpacity); //Reset opacity
4192 if(this._storedZIndex) this.helper.css("zIndex", this._storedZIndex == 'auto' ? '' : this._storedZIndex); //Reset z-index
4193
4194 this.dragging = false;
4195 if(this.cancelHelperRemoval) {
4196 if(!noPropagation) {
4197 this._trigger("beforeStop", event, this._uiHash());
4198 for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events
4199 this._trigger("stop", event, this._uiHash());
4200 }
4201
4202 this.fromOutside = false;
4203 return false;
4204 }
4205
4206 if(!noPropagation) this._trigger("beforeStop", event, this._uiHash());
4207
4208 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
4209 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
4210
4211 if(this.helper[0] != this.currentItem[0]) this.helper.remove(); this.helper = null;
4212
4213 if(!noPropagation) {
4214 for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events
4215 this._trigger("stop", event, this._uiHash());
4216 }
4217
4218 this.fromOutside = false;
4219 return true;
4220
4221 },
4222
4223 _trigger: function() {
4224 if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
4225 this.cancel();
4226 }
4227 },
4228
4229 _uiHash: function(_inst) {
4230 var inst = _inst || this;
4231 return {
4232 helper: inst.helper,
4233 placeholder: inst.placeholder || $([]),
4234 position: inst.position,
4235 originalPosition: inst.originalPosition,
4236 offset: inst.positionAbs,
4237 item: inst.currentItem,
4238 sender: _inst ? _inst.element : null
4239 };
4240 }
4241
4242});
4243
4244})(jQuery);
4245
4246;(jQuery.effects || (function($, undefined) {
4247
4248var backCompat = $.uiBackCompat !== false,
4249 // prefix used for storing data on .data()
4250 dataSpace = "ui-effects-";
4251
4252$.effects = {
4253 effect: {}
4254};
4255
4256/*!
4257 * jQuery Color Animations v2.0.0
4258 * http://jquery.com/
4259 *
4260 * Copyright 2012 jQuery Foundation and other contributors
4261 * Released under the MIT license.
4262 * http://jquery.org/license
4263 *
4264 * Date: Mon Aug 13 13:41:02 2012 -0500
4265 */
4266(function( jQuery, undefined ) {
4267
4268 var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor".split(" "),
4269
4270 // plusequals test for += 100 -= 100
4271 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
4272 // a set of RE's that can match strings and generate color tuples.
4273 stringParsers = [{
4274 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,
4275 parse: function( execResult ) {
4276 return [
4277 execResult[ 1 ],
4278 execResult[ 2 ],
4279 execResult[ 3 ],
4280 execResult[ 4 ]
4281 ];
4282 }
4283 }, {
4284 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,
4285 parse: function( execResult ) {
4286 return [
4287 execResult[ 1 ] * 2.55,
4288 execResult[ 2 ] * 2.55,
4289 execResult[ 3 ] * 2.55,
4290 execResult[ 4 ]
4291 ];
4292 }
4293 }, {
4294 // this regex ignores A-F because it's compared against an already lowercased string
4295 re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
4296 parse: function( execResult ) {
4297 return [
4298 parseInt( execResult[ 1 ], 16 ),
4299 parseInt( execResult[ 2 ], 16 ),
4300 parseInt( execResult[ 3 ], 16 )
4301 ];
4302 }
4303 }, {
4304 // this regex ignores A-F because it's compared against an already lowercased string
4305 re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
4306 parse: function( execResult ) {
4307 return [
4308 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
4309 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
4310 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
4311 ];
4312 }
4313 }, {
4314 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,
4315 space: "hsla",
4316 parse: function( execResult ) {
4317 return [
4318 execResult[ 1 ],
4319 execResult[ 2 ] / 100,
4320 execResult[ 3 ] / 100,
4321 execResult[ 4 ]
4322 ];
4323 }
4324 }],
4325
4326 // jQuery.Color( )
4327 color = jQuery.Color = function( color, green, blue, alpha ) {
4328 return new jQuery.Color.fn.parse( color, green, blue, alpha );
4329 },
4330 spaces = {
4331 rgba: {
4332 props: {
4333 red: {
4334 idx: 0,
4335 type: "byte"
4336 },
4337 green: {
4338 idx: 1,
4339 type: "byte"
4340 },
4341 blue: {
4342 idx: 2,
4343 type: "byte"
4344 }
4345 }
4346 },
4347
4348 hsla: {
4349 props: {
4350 hue: {
4351 idx: 0,
4352 type: "degrees"
4353 },
4354 saturation: {
4355 idx: 1,
4356 type: "percent"
4357 },
4358 lightness: {
4359 idx: 2,
4360 type: "percent"
4361 }
4362 }
4363 }
4364 },
4365 propTypes = {
4366 "byte": {
4367 floor: true,
4368 max: 255
4369 },
4370 "percent": {
4371 max: 1
4372 },
4373 "degrees": {
4374 mod: 360,
4375 floor: true
4376 }
4377 },
4378 support = color.support = {},
4379
4380 // element for support tests
4381 supportElem = jQuery( "<p>" )[ 0 ],
4382
4383 // colors = jQuery.Color.names
4384 colors,
4385
4386 // local aliases of functions called often
4387 each = jQuery.each;
4388
4389// determine rgba support immediately
4390supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
4391support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
4392
4393// define cache name and alpha properties
4394// for rgba and hsla spaces
4395each( spaces, function( spaceName, space ) {
4396 space.cache = "_" + spaceName;
4397 space.props.alpha = {
4398 idx: 3,
4399 type: "percent",
4400 def: 1
4401 };
4402});
4403
4404function clamp( value, prop, allowEmpty ) {
4405 var type = propTypes[ prop.type ] || {};
4406
4407 if ( value == null ) {
4408 return (allowEmpty || !prop.def) ? null : prop.def;
4409 }
4410
4411 // ~~ is an short way of doing floor for positive numbers
4412 value = type.floor ? ~~value : parseFloat( value );
4413
4414 // IE will pass in empty strings as value for alpha,
4415 // which will hit this case
4416 if ( isNaN( value ) ) {
4417 return prop.def;
4418 }
4419
4420 if ( type.mod ) {
4421 // we add mod before modding to make sure that negatives values
4422 // get converted properly: -10 -> 350
4423 return (value + type.mod) % type.mod;
4424 }
4425
4426 // for now all property types without mod have min and max
4427 return 0 > value ? 0 : type.max < value ? type.max : value;
4428}
4429
4430function stringParse( string ) {
4431 var inst = color(),
4432 rgba = inst._rgba = [];
4433
4434 string = string.toLowerCase();
4435
4436 each( stringParsers, function( i, parser ) {
4437 var parsed,
4438 match = parser.re.exec( string ),
4439 values = match && parser.parse( match ),
4440 spaceName = parser.space || "rgba";
4441
4442 if ( values ) {
4443 parsed = inst[ spaceName ]( values );
4444
4445 // if this was an rgba parse the assignment might happen twice
4446 // oh well....
4447 inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
4448 rgba = inst._rgba = parsed._rgba;
4449
4450 // exit each( stringParsers ) here because we matched
4451 return false;
4452 }
4453 });
4454
4455 // Found a stringParser that handled it
4456 if ( rgba.length ) {
4457
4458 // if this came from a parsed string, force "transparent" when alpha is 0
4459 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
4460 if ( rgba.join() === "0,0,0,0" ) {
4461 jQuery.extend( rgba, colors.transparent );
4462 }
4463 return inst;
4464 }
4465
4466 // named colors
4467 return colors[ string ];
4468}
4469
4470color.fn = jQuery.extend( color.prototype, {
4471 parse: function( red, green, blue, alpha ) {
4472 if ( red === undefined ) {
4473 this._rgba = [ null, null, null, null ];
4474 return this;
4475 }
4476 if ( red.jquery || red.nodeType ) {
4477 red = jQuery( red ).css( green );
4478 green = undefined;
4479 }
4480
4481 var inst = this,
4482 type = jQuery.type( red ),
4483 rgba = this._rgba = [];
4484
4485 // more than 1 argument specified - assume ( red, green, blue, alpha )
4486 if ( green !== undefined ) {
4487 red = [ red, green, blue, alpha ];
4488 type = "array";
4489 }
4490
4491 if ( type === "string" ) {
4492 return this.parse( stringParse( red ) || colors._default );
4493 }
4494
4495 if ( type === "array" ) {
4496 each( spaces.rgba.props, function( key, prop ) {
4497 rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
4498 });
4499 return this;
4500 }
4501
4502 if ( type === "object" ) {
4503 if ( red instanceof color ) {
4504 each( spaces, function( spaceName, space ) {
4505 if ( red[ space.cache ] ) {
4506 inst[ space.cache ] = red[ space.cache ].slice();
4507 }
4508 });
4509 } else {
4510 each( spaces, function( spaceName, space ) {
4511 var cache = space.cache;
4512 each( space.props, function( key, prop ) {
4513
4514 // if the cache doesn't exist, and we know how to convert
4515 if ( !inst[ cache ] && space.to ) {
4516
4517 // if the value was null, we don't need to copy it
4518 // if the key was alpha, we don't need to copy it either
4519 if ( key === "alpha" || red[ key ] == null ) {
4520 return;
4521 }
4522 inst[ cache ] = space.to( inst._rgba );
4523 }
4524
4525 // this is the only case where we allow nulls for ALL properties.
4526 // call clamp with alwaysAllowEmpty
4527 inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
4528 });
4529
4530 // everything defined but alpha?
4531 if ( inst[ cache ] && $.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
4532 // use the default of 1
4533 inst[ cache ][ 3 ] = 1;
4534 if ( space.from ) {
4535 inst._rgba = space.from( inst[ cache ] );
4536 }
4537 }
4538 });
4539 }
4540 return this;
4541 }
4542 },
4543 is: function( compare ) {
4544 var is = color( compare ),
4545 same = true,
4546 inst = this;
4547
4548 each( spaces, function( _, space ) {
4549 var localCache,
4550 isCache = is[ space.cache ];
4551 if (isCache) {
4552 localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
4553 each( space.props, function( _, prop ) {
4554 if ( isCache[ prop.idx ] != null ) {
4555 same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
4556 return same;
4557 }
4558 });
4559 }
4560 return same;
4561 });
4562 return same;
4563 },
4564 _space: function() {
4565 var used = [],
4566 inst = this;
4567 each( spaces, function( spaceName, space ) {
4568 if ( inst[ space.cache ] ) {
4569 used.push( spaceName );
4570 }
4571 });
4572 return used.pop();
4573 },
4574 transition: function( other, distance ) {
4575 var end = color( other ),
4576 spaceName = end._space(),
4577 space = spaces[ spaceName ],
4578 startColor = this.alpha() === 0 ? color( "transparent" ) : this,
4579 start = startColor[ space.cache ] || space.to( startColor._rgba ),
4580 result = start.slice();
4581
4582 end = end[ space.cache ];
4583 each( space.props, function( key, prop ) {
4584 var index = prop.idx,
4585 startValue = start[ index ],
4586 endValue = end[ index ],
4587 type = propTypes[ prop.type ] || {};
4588
4589 // if null, don't override start value
4590 if ( endValue === null ) {
4591 return;
4592 }
4593 // if null - use end
4594 if ( startValue === null ) {
4595 result[ index ] = endValue;
4596 } else {
4597 if ( type.mod ) {
4598 if ( endValue - startValue > type.mod / 2 ) {
4599 startValue += type.mod;
4600 } else if ( startValue - endValue > type.mod / 2 ) {
4601 startValue -= type.mod;
4602 }
4603 }
4604 result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
4605 }
4606 });
4607 return this[ spaceName ]( result );
4608 },
4609 blend: function( opaque ) {
4610 // if we are already opaque - return ourself
4611 if ( this._rgba[ 3 ] === 1 ) {
4612 return this;
4613 }
4614
4615 var rgb = this._rgba.slice(),
4616 a = rgb.pop(),
4617 blend = color( opaque )._rgba;
4618
4619 return color( jQuery.map( rgb, function( v, i ) {
4620 return ( 1 - a ) * blend[ i ] + a * v;
4621 }));
4622 },
4623 toRgbaString: function() {
4624 var prefix = "rgba(",
4625 rgba = jQuery.map( this._rgba, function( v, i ) {
4626 return v == null ? ( i > 2 ? 1 : 0 ) : v;
4627 });
4628
4629 if ( rgba[ 3 ] === 1 ) {
4630 rgba.pop();
4631 prefix = "rgb(";
4632 }
4633
4634 return prefix + rgba.join() + ")";
4635 },
4636 toHslaString: function() {
4637 var prefix = "hsla(",
4638 hsla = jQuery.map( this.hsla(), function( v, i ) {
4639 if ( v == null ) {
4640 v = i > 2 ? 1 : 0;
4641 }
4642
4643 // catch 1 and 2
4644 if ( i && i < 3 ) {
4645 v = Math.round( v * 100 ) + "%";
4646 }
4647 return v;
4648 });
4649
4650 if ( hsla[ 3 ] === 1 ) {
4651 hsla.pop();
4652 prefix = "hsl(";
4653 }
4654 return prefix + hsla.join() + ")";
4655 },
4656 toHexString: function( includeAlpha ) {
4657 var rgba = this._rgba.slice(),
4658 alpha = rgba.pop();
4659
4660 if ( includeAlpha ) {
4661 rgba.push( ~~( alpha * 255 ) );
4662 }
4663
4664 return "#" + jQuery.map( rgba, function( v ) {
4665
4666 // default to 0 when nulls exist
4667 v = ( v || 0 ).toString( 16 );
4668 return v.length === 1 ? "0" + v : v;
4669 }).join("");
4670 },
4671 toString: function() {
4672 return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
4673 }
4674});
4675color.fn.parse.prototype = color.fn;
4676
4677// hsla conversions adapted from:
4678// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
4679
4680function hue2rgb( p, q, h ) {
4681 h = ( h + 1 ) % 1;
4682 if ( h * 6 < 1 ) {
4683 return p + (q - p) * h * 6;
4684 }
4685 if ( h * 2 < 1) {
4686 return q;
4687 }
4688 if ( h * 3 < 2 ) {
4689 return p + (q - p) * ((2/3) - h) * 6;
4690 }
4691 return p;
4692}
4693
4694spaces.hsla.to = function ( rgba ) {
4695 if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
4696 return [ null, null, null, rgba[ 3 ] ];
4697 }
4698 var r = rgba[ 0 ] / 255,
4699 g = rgba[ 1 ] / 255,
4700 b = rgba[ 2 ] / 255,
4701 a = rgba[ 3 ],
4702 max = Math.max( r, g, b ),
4703 min = Math.min( r, g, b ),
4704 diff = max - min,
4705 add = max + min,
4706 l = add * 0.5,
4707 h, s;
4708
4709 if ( min === max ) {
4710 h = 0;
4711 } else if ( r === max ) {
4712 h = ( 60 * ( g - b ) / diff ) + 360;
4713 } else if ( g === max ) {
4714 h = ( 60 * ( b - r ) / diff ) + 120;
4715 } else {
4716 h = ( 60 * ( r - g ) / diff ) + 240;
4717 }
4718
4719 if ( l === 0 || l === 1 ) {
4720 s = l;
4721 } else if ( l <= 0.5 ) {
4722 s = diff / add;
4723 } else {
4724 s = diff / ( 2 - add );
4725 }
4726 return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
4727};
4728
4729spaces.hsla.from = function ( hsla ) {
4730 if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
4731 return [ null, null, null, hsla[ 3 ] ];
4732 }
4733 var h = hsla[ 0 ] / 360,
4734 s = hsla[ 1 ],
4735 l = hsla[ 2 ],
4736 a = hsla[ 3 ],
4737 q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
4738 p = 2 * l - q;
4739
4740 return [
4741 Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
4742 Math.round( hue2rgb( p, q, h ) * 255 ),
4743 Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
4744 a
4745 ];
4746};
4747
4748
4749each( spaces, function( spaceName, space ) {
4750 var props = space.props,
4751 cache = space.cache,
4752 to = space.to,
4753 from = space.from;
4754
4755 // makes rgba() and hsla()
4756 color.fn[ spaceName ] = function( value ) {
4757
4758 // generate a cache for this space if it doesn't exist
4759 if ( to && !this[ cache ] ) {
4760 this[ cache ] = to( this._rgba );
4761 }
4762 if ( value === undefined ) {
4763 return this[ cache ].slice();
4764 }
4765
4766 var ret,
4767 type = jQuery.type( value ),
4768 arr = ( type === "array" || type === "object" ) ? value : arguments,
4769 local = this[ cache ].slice();
4770
4771 each( props, function( key, prop ) {
4772 var val = arr[ type === "object" ? key : prop.idx ];
4773 if ( val == null ) {
4774 val = local[ prop.idx ];
4775 }
4776 local[ prop.idx ] = clamp( val, prop );
4777 });
4778
4779 if ( from ) {
4780 ret = color( from( local ) );
4781 ret[ cache ] = local;
4782 return ret;
4783 } else {
4784 return color( local );
4785 }
4786 };
4787
4788 // makes red() green() blue() alpha() hue() saturation() lightness()
4789 each( props, function( key, prop ) {
4790 // alpha is included in more than one space
4791 if ( color.fn[ key ] ) {
4792 return;
4793 }
4794 color.fn[ key ] = function( value ) {
4795 var vtype = jQuery.type( value ),
4796 fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
4797 local = this[ fn ](),
4798 cur = local[ prop.idx ],
4799 match;
4800
4801 if ( vtype === "undefined" ) {
4802 return cur;
4803 }
4804
4805 if ( vtype === "function" ) {
4806 value = value.call( this, cur );
4807 vtype = jQuery.type( value );
4808 }
4809 if ( value == null && prop.empty ) {
4810 return this;
4811 }
4812 if ( vtype === "string" ) {
4813 match = rplusequals.exec( value );
4814 if ( match ) {
4815 value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
4816 }
4817 }
4818 local[ prop.idx ] = value;
4819 return this[ fn ]( local );
4820 };
4821 });
4822});
4823
4824// add .fx.step functions
4825each( stepHooks, function( i, hook ) {
4826 jQuery.cssHooks[ hook ] = {
4827 set: function( elem, value ) {
4828 var parsed, curElem,
4829 backgroundColor = "";
4830
4831 if ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) {
4832 value = color( parsed || value );
4833 if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
4834 curElem = hook === "backgroundColor" ? elem.parentNode : elem;
4835 while (
4836 (backgroundColor === "" || backgroundColor === "transparent") &&
4837 curElem && curElem.style
4838 ) {
4839 try {
4840 backgroundColor = jQuery.css( curElem, "backgroundColor" );
4841 curElem = curElem.parentNode;
4842 } catch ( e ) {
4843 }
4844 }
4845
4846 value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
4847 backgroundColor :
4848 "_default" );
4849 }
4850
4851 value = value.toRgbaString();
4852 }
4853 try {
4854 elem.style[ hook ] = value;
4855 } catch( error ) {
4856 // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
4857 }
4858 }
4859 };
4860 jQuery.fx.step[ hook ] = function( fx ) {
4861 if ( !fx.colorInit ) {
4862 fx.start = color( fx.elem, hook );
4863 fx.end = color( fx.end );
4864 fx.colorInit = true;
4865 }
4866 jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
4867 };
4868});
4869
4870jQuery.cssHooks.borderColor = {
4871 expand: function( value ) {
4872 var expanded = {};
4873
4874 each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
4875 expanded[ "border" + part + "Color" ] = value;
4876 });
4877 return expanded;
4878 }
4879};
4880
4881// Basic color names only.
4882// Usage of any of the other color names requires adding yourself or including
4883// jquery.color.svg-names.js.
4884colors = jQuery.Color.names = {
4885 // 4.1. Basic color keywords
4886 aqua: "#00ffff",
4887 black: "#000000",
4888 blue: "#0000ff",
4889 fuchsia: "#ff00ff",
4890 gray: "#808080",
4891 green: "#008000",
4892 lime: "#00ff00",
4893 maroon: "#800000",
4894 navy: "#000080",
4895 olive: "#808000",
4896 purple: "#800080",
4897 red: "#ff0000",
4898 silver: "#c0c0c0",
4899 teal: "#008080",
4900 white: "#ffffff",
4901 yellow: "#ffff00",
4902
4903 // 4.2.3. "transparent" color keyword
4904 transparent: [ null, null, null, 0 ],
4905
4906 _default: "#ffffff"
4907};
4908
4909})( jQuery );
4910
4911
4912
4913/******************************************************************************/
4914/****************************** CLASS ANIMATIONS ******************************/
4915/******************************************************************************/
4916(function() {
4917
4918var classAnimationActions = [ "add", "remove", "toggle" ],
4919 shorthandStyles = {
4920 border: 1,
4921 borderBottom: 1,
4922 borderColor: 1,
4923 borderLeft: 1,
4924 borderRight: 1,
4925 borderTop: 1,
4926 borderWidth: 1,
4927 margin: 1,
4928 padding: 1
4929 };
4930
4931$.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) {
4932 $.fx.step[ prop ] = function( fx ) {
4933 if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
4934 jQuery.style( fx.elem, prop, fx.end );
4935 fx.setAttr = true;
4936 }
4937 };
4938});
4939
4940function getElementStyles() {
4941 var style = this.ownerDocument.defaultView ?
4942 this.ownerDocument.defaultView.getComputedStyle( this, null ) :
4943 this.currentStyle,
4944 newStyle = {},
4945 key,
4946 len;
4947
4948 // webkit enumerates style porperties
4949 if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
4950 len = style.length;
4951 while ( len-- ) {
4952 key = style[ len ];
4953 if ( typeof style[ key ] === "string" ) {
4954 newStyle[ $.camelCase( key ) ] = style[ key ];
4955 }
4956 }
4957 } else {
4958 for ( key in style ) {
4959 if ( typeof style[ key ] === "string" ) {
4960 newStyle[ key ] = style[ key ];
4961 }
4962 }
4963 }
4964
4965 return newStyle;
4966}
4967
4968
4969function styleDifference( oldStyle, newStyle ) {
4970 var diff = {},
4971 name, value;
4972
4973 for ( name in newStyle ) {
4974 value = newStyle[ name ];
4975 if ( oldStyle[ name ] !== value ) {
4976 if ( !shorthandStyles[ name ] ) {
4977 if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
4978 diff[ name ] = value;
4979 }
4980 }
4981 }
4982 }
4983
4984 return diff;
4985}
4986
4987$.effects.animateClass = function( value, duration, easing, callback ) {
4988 var o = $.speed( duration, easing, callback );
4989
4990 return this.queue( function() {
4991 var animated = $( this ),
4992 baseClass = animated.attr( "class" ) || "",
4993 applyClassChange,
4994 allAnimations = o.children ? animated.find( "*" ).andSelf() : animated;
4995
4996 // map the animated objects to store the original styles.
4997 allAnimations = allAnimations.map(function() {
4998 var el = $( this );
4999 return {
5000 el: el,
5001 start: getElementStyles.call( this )
5002 };
5003 });
5004
5005 // apply class change
5006 applyClassChange = function() {
5007 $.each( classAnimationActions, function(i, action) {
5008 if ( value[ action ] ) {
5009 animated[ action + "Class" ]( value[ action ] );
5010 }
5011 });
5012 };
5013 applyClassChange();
5014
5015 // map all animated objects again - calculate new styles and diff
5016 allAnimations = allAnimations.map(function() {
5017 this.end = getElementStyles.call( this.el[ 0 ] );
5018 this.diff = styleDifference( this.start, this.end );
5019 return this;
5020 });
5021
5022 // apply original class
5023 animated.attr( "class", baseClass );
5024
5025 // map all animated objects again - this time collecting a promise
5026 allAnimations = allAnimations.map(function() {
5027 var styleInfo = this,
5028 dfd = $.Deferred(),
5029 opts = jQuery.extend({}, o, {
5030 queue: false,
5031 complete: function() {
5032 dfd.resolve( styleInfo );
5033 }
5034 });
5035
5036 this.el.animate( this.diff, opts );
5037 return dfd.promise();
5038 });
5039
5040 // once all animations have completed:
5041 $.when.apply( $, allAnimations.get() ).done(function() {
5042
5043 // set the final class
5044 applyClassChange();
5045
5046 // for each animated element,
5047 // clear all css properties that were animated
5048 $.each( arguments, function() {
5049 var el = this.el;
5050 $.each( this.diff, function(key) {
5051 el.css( key, '' );
5052 });
5053 });
5054
5055 // this is guarnteed to be there if you use jQuery.speed()
5056 // it also handles dequeuing the next anim...
5057 o.complete.call( animated[ 0 ] );
5058 });
5059 });
5060};
5061
5062$.fn.extend({
5063 _addClass: $.fn.addClass,
5064 addClass: function( classNames, speed, easing, callback ) {
5065 return speed ?
5066 $.effects.animateClass.call( this,
5067 { add: classNames }, speed, easing, callback ) :
5068 this._addClass( classNames );
5069 },
5070
5071 _removeClass: $.fn.removeClass,
5072 removeClass: function( classNames, speed, easing, callback ) {
5073 return speed ?
5074 $.effects.animateClass.call( this,
5075 { remove: classNames }, speed, easing, callback ) :
5076 this._removeClass( classNames );
5077 },
5078
5079 _toggleClass: $.fn.toggleClass,
5080 toggleClass: function( classNames, force, speed, easing, callback ) {
5081 if ( typeof force === "boolean" || force === undefined ) {
5082 if ( !speed ) {
5083 // without speed parameter
5084 return this._toggleClass( classNames, force );
5085 } else {
5086 return $.effects.animateClass.call( this,
5087 (force ? { add: classNames } : { remove: classNames }),
5088 speed, easing, callback );
5089 }
5090 } else {
5091 // without force parameter
5092 return $.effects.animateClass.call( this,
5093 { toggle: classNames }, force, speed, easing );
5094 }
5095 },
5096
5097 switchClass: function( remove, add, speed, easing, callback) {
5098 return $.effects.animateClass.call( this, {
5099 add: add,
5100 remove: remove
5101 }, speed, easing, callback );
5102 }
5103});
5104
5105})();
5106
5107/******************************************************************************/
5108/*********************************** EFFECTS **********************************/
5109/******************************************************************************/
5110
5111(function() {
5112
5113$.extend( $.effects, {
5114 version: "1.9.2",
5115
5116 // Saves a set of properties in a data storage
5117 save: function( element, set ) {
5118 for( var i=0; i < set.length; i++ ) {
5119 if ( set[ i ] !== null ) {
5120 element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
5121 }
5122 }
5123 },
5124
5125 // Restores a set of previously saved properties from a data storage
5126 restore: function( element, set ) {
5127 var val, i;
5128 for( i=0; i < set.length; i++ ) {
5129 if ( set[ i ] !== null ) {
5130 val = element.data( dataSpace + set[ i ] );
5131 // support: jQuery 1.6.2
5132 // http://bugs.jquery.com/ticket/9917
5133 // jQuery 1.6.2 incorrectly returns undefined for any falsy value.
5134 // We can't differentiate between "" and 0 here, so we just assume
5135 // empty string since it's likely to be a more common value...
5136 if ( val === undefined ) {
5137 val = "";
5138 }
5139 element.css( set[ i ], val );
5140 }
5141 }
5142 },
5143
5144 setMode: function( el, mode ) {
5145 if (mode === "toggle") {
5146 mode = el.is( ":hidden" ) ? "show" : "hide";
5147 }
5148 return mode;
5149 },
5150
5151 // Translates a [top,left] array into a baseline value
5152 // this should be a little more flexible in the future to handle a string & hash
5153 getBaseline: function( origin, original ) {
5154 var y, x;
5155 switch ( origin[ 0 ] ) {
5156 case "top": y = 0; break;
5157 case "middle": y = 0.5; break;
5158 case "bottom": y = 1; break;
5159 default: y = origin[ 0 ] / original.height;
5160 }
5161 switch ( origin[ 1 ] ) {
5162 case "left": x = 0; break;
5163 case "center": x = 0.5; break;
5164 case "right": x = 1; break;
5165 default: x = origin[ 1 ] / original.width;
5166 }
5167 return {
5168 x: x,
5169 y: y
5170 };
5171 },
5172
5173 // Wraps the element around a wrapper that copies position properties
5174 createWrapper: function( element ) {
5175
5176 // if the element is already wrapped, return it
5177 if ( element.parent().is( ".ui-effects-wrapper" )) {
5178 return element.parent();
5179 }
5180
5181 // wrap the element
5182 var props = {
5183 width: element.outerWidth(true),
5184 height: element.outerHeight(true),
5185 "float": element.css( "float" )
5186 },
5187 wrapper = $( "<div></div>" )
5188 .addClass( "ui-effects-wrapper" )
5189 .css({
5190 fontSize: "100%",
5191 background: "transparent",
5192 border: "none",
5193 margin: 0,
5194 padding: 0
5195 }),
5196 // Store the size in case width/height are defined in % - Fixes #5245
5197 size = {
5198 width: element.width(),
5199 height: element.height()
5200 },
5201 active = document.activeElement;
5202
5203 // support: Firefox
5204 // Firefox incorrectly exposes anonymous content
5205 // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
5206 try {
5207 active.id;
5208 } catch( e ) {
5209 active = document.body;
5210 }
5211
5212 element.wrap( wrapper );
5213
5214 // Fixes #7595 - Elements lose focus when wrapped.
5215 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
5216 $( active ).focus();
5217 }
5218
5219 wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element
5220
5221 // transfer positioning properties to the wrapper
5222 if ( element.css( "position" ) === "static" ) {
5223 wrapper.css({ position: "relative" });
5224 element.css({ position: "relative" });
5225 } else {
5226 $.extend( props, {
5227 position: element.css( "position" ),
5228 zIndex: element.css( "z-index" )
5229 });
5230 $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
5231 props[ pos ] = element.css( pos );
5232 if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
5233 props[ pos ] = "auto";
5234 }
5235 });
5236 element.css({
5237 position: "relative",
5238 top: 0,
5239 left: 0,
5240 right: "auto",
5241 bottom: "auto"
5242 });
5243 }
5244 element.css(size);
5245
5246 return wrapper.css( props ).show();
5247 },
5248
5249 removeWrapper: function( element ) {
5250 var active = document.activeElement;
5251
5252 if ( element.parent().is( ".ui-effects-wrapper" ) ) {
5253 element.parent().replaceWith( element );
5254
5255 // Fixes #7595 - Elements lose focus when wrapped.
5256 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
5257 $( active ).focus();
5258 }
5259 }
5260
5261
5262 return element;
5263 },
5264
5265 setTransition: function( element, list, factor, value ) {
5266 value = value || {};
5267 $.each( list, function( i, x ) {
5268 var unit = element.cssUnit( x );
5269 if ( unit[ 0 ] > 0 ) {
5270 value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
5271 }
5272 });
5273 return value;
5274 }
5275});
5276
5277// return an effect options object for the given parameters:
5278function _normalizeArguments( effect, options, speed, callback ) {
5279
5280 // allow passing all options as the first parameter
5281 if ( $.isPlainObject( effect ) ) {
5282 options = effect;
5283 effect = effect.effect;
5284 }
5285
5286 // convert to an object
5287 effect = { effect: effect };
5288
5289 // catch (effect, null, ...)
5290 if ( options == null ) {
5291 options = {};
5292 }
5293
5294 // catch (effect, callback)
5295 if ( $.isFunction( options ) ) {
5296 callback = options;
5297 speed = null;
5298 options = {};
5299 }
5300
5301 // catch (effect, speed, ?)
5302 if ( typeof options === "number" || $.fx.speeds[ options ] ) {
5303 callback = speed;
5304 speed = options;
5305 options = {};
5306 }
5307
5308 // catch (effect, options, callback)
5309 if ( $.isFunction( speed ) ) {
5310 callback = speed;
5311 speed = null;
5312 }
5313
5314 // add options to effect
5315 if ( options ) {
5316 $.extend( effect, options );
5317 }
5318
5319 speed = speed || options.duration;
5320 effect.duration = $.fx.off ? 0 :
5321 typeof speed === "number" ? speed :
5322 speed in $.fx.speeds ? $.fx.speeds[ speed ] :
5323 $.fx.speeds._default;
5324
5325 effect.complete = callback || options.complete;
5326
5327 return effect;
5328}
5329
5330function standardSpeed( speed ) {
5331 // valid standard speeds
5332 if ( !speed || typeof speed === "number" || $.fx.speeds[ speed ] ) {
5333 return true;
5334 }
5335
5336 // invalid strings - treat as "normal" speed
5337 if ( typeof speed === "string" && !$.effects.effect[ speed ] ) {
5338 // TODO: remove in 2.0 (#7115)
5339 if ( backCompat && $.effects[ speed ] ) {
5340 return false;
5341 }
5342 return true;
5343 }
5344
5345 return false;
5346}
5347
5348$.fn.extend({
5349 effect: function( /* effect, options, speed, callback */ ) {
5350 var args = _normalizeArguments.apply( this, arguments ),
5351 mode = args.mode,
5352 queue = args.queue,
5353 effectMethod = $.effects.effect[ args.effect ],
5354
5355 // DEPRECATED: remove in 2.0 (#7115)
5356 oldEffectMethod = !effectMethod && backCompat && $.effects[ args.effect ];
5357
5358 if ( $.fx.off || !( effectMethod || oldEffectMethod ) ) {
5359 // delegate to the original method (e.g., .show()) if possible
5360 if ( mode ) {
5361 return this[ mode ]( args.duration, args.complete );
5362 } else {
5363 return this.each( function() {
5364 if ( args.complete ) {
5365 args.complete.call( this );
5366 }
5367 });
5368 }
5369 }
5370
5371 function run( next ) {
5372 var elem = $( this ),
5373 complete = args.complete,
5374 mode = args.mode;
5375
5376 function done() {
5377 if ( $.isFunction( complete ) ) {
5378 complete.call( elem[0] );
5379 }
5380 if ( $.isFunction( next ) ) {
5381 next();
5382 }
5383 }
5384
5385 // if the element is hiddden and mode is hide,
5386 // or element is visible and mode is show
5387 if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
5388 done();
5389 } else {
5390 effectMethod.call( elem[0], args, done );
5391 }
5392 }
5393
5394 // TODO: remove this check in 2.0, effectMethod will always be true
5395 if ( effectMethod ) {
5396 return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
5397 } else {
5398 // DEPRECATED: remove in 2.0 (#7115)
5399 return oldEffectMethod.call(this, {
5400 options: args,
5401 duration: args.duration,
5402 callback: args.complete,
5403 mode: args.mode
5404 });
5405 }
5406 },
5407
5408 _show: $.fn.show,
5409 show: function( speed ) {
5410 if ( standardSpeed( speed ) ) {
5411 return this._show.apply( this, arguments );
5412 } else {
5413 var args = _normalizeArguments.apply( this, arguments );
5414 args.mode = "show";
5415 return this.effect.call( this, args );
5416 }
5417 },
5418
5419 _hide: $.fn.hide,
5420 hide: function( speed ) {
5421 if ( standardSpeed( speed ) ) {
5422 return this._hide.apply( this, arguments );
5423 } else {
5424 var args = _normalizeArguments.apply( this, arguments );
5425 args.mode = "hide";
5426 return this.effect.call( this, args );
5427 }
5428 },
5429
5430 // jQuery core overloads toggle and creates _toggle
5431 __toggle: $.fn.toggle,
5432 toggle: function( speed ) {
5433 if ( standardSpeed( speed ) || typeof speed === "boolean" || $.isFunction( speed ) ) {
5434 return this.__toggle.apply( this, arguments );
5435 } else {
5436 var args = _normalizeArguments.apply( this, arguments );
5437 args.mode = "toggle";
5438 return this.effect.call( this, args );
5439 }
5440 },
5441
5442 // helper functions
5443 cssUnit: function(key) {
5444 var style = this.css( key ),
5445 val = [];
5446
5447 $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
5448 if ( style.indexOf( unit ) > 0 ) {
5449 val = [ parseFloat( style ), unit ];
5450 }
5451 });
5452 return val;
5453 }
5454});
5455
5456})();
5457
5458/******************************************************************************/
5459/*********************************** EASING ***********************************/
5460/******************************************************************************/
5461
5462(function() {
5463
5464// based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
5465
5466var baseEasings = {};
5467
5468$.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
5469 baseEasings[ name ] = function( p ) {
5470 return Math.pow( p, i + 2 );
5471 };
5472});
5473
5474$.extend( baseEasings, {
5475 Sine: function ( p ) {
5476 return 1 - Math.cos( p * Math.PI / 2 );
5477 },
5478 Circ: function ( p ) {
5479 return 1 - Math.sqrt( 1 - p * p );
5480 },
5481 Elastic: function( p ) {
5482 return p === 0 || p === 1 ? p :
5483 -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 );
5484 },
5485 Back: function( p ) {
5486 return p * p * ( 3 * p - 2 );
5487 },
5488 Bounce: function ( p ) {
5489 var pow2,
5490 bounce = 4;
5491
5492 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
5493 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
5494 }
5495});
5496
5497$.each( baseEasings, function( name, easeIn ) {
5498 $.easing[ "easeIn" + name ] = easeIn;
5499 $.easing[ "easeOut" + name ] = function( p ) {
5500 return 1 - easeIn( 1 - p );
5501 };
5502 $.easing[ "easeInOut" + name ] = function( p ) {
5503 return p < 0.5 ?
5504 easeIn( p * 2 ) / 2 :
5505 1 - easeIn( p * -2 + 2 ) / 2;
5506 };
5507});
5508
5509})();
5510
5511})(jQuery));
5512
5513(function( $, undefined ) {
5514
5515var uid = 0,
5516 hideProps = {},
5517 showProps = {};
5518
5519hideProps.height = hideProps.paddingTop = hideProps.paddingBottom =
5520 hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide";
5521showProps.height = showProps.paddingTop = showProps.paddingBottom =
5522 showProps.borderTopWidth = showProps.borderBottomWidth = "show";
5523
5524$.widget( "ui.accordion", {
5525 version: "1.9.2",
5526 options: {
5527 active: 0,
5528 animate: {},
5529 collapsible: false,
5530 event: "click",
5531 header: "> li > :first-child,> :not(li):even",
5532 heightStyle: "auto",
5533 icons: {
5534 activeHeader: "ui-icon-triangle-1-s",
5535 header: "ui-icon-triangle-1-e"
5536 },
5537
5538 // callbacks
5539 activate: null,
5540 beforeActivate: null
5541 },
5542
5543 _create: function() {
5544 var accordionId = this.accordionId = "ui-accordion-" +
5545 (this.element.attr( "id" ) || ++uid),
5546 options = this.options;
5547
5548 this.prevShow = this.prevHide = $();
5549 this.element.addClass( "ui-accordion ui-widget ui-helper-reset" );
5550
5551 this.headers = this.element.find( options.header )
5552 .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" );
5553 this._hoverable( this.headers );
5554 this._focusable( this.headers );
5555
5556 this.headers.next()
5557 .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
5558 .hide();
5559
5560 // don't allow collapsible: false and active: false / null
5561 if ( !options.collapsible && (options.active === false || options.active == null) ) {
5562 options.active = 0;
5563 }
5564 // handle negative values
5565 if ( options.active < 0 ) {
5566 options.active += this.headers.length;
5567 }
5568 this.active = this._findActive( options.active )
5569 .addClass( "ui-accordion-header-active ui-state-active" )
5570 .toggleClass( "ui-corner-all ui-corner-top" );
5571 this.active.next()
5572 .addClass( "ui-accordion-content-active" )
5573 .show();
5574
5575 this._createIcons();
5576 this.refresh();
5577
5578 // ARIA
5579 this.element.attr( "role", "tablist" );
5580
5581 this.headers
5582 .attr( "role", "tab" )
5583 .each(function( i ) {
5584 var header = $( this ),
5585 headerId = header.attr( "id" ),
5586 panel = header.next(),
5587 panelId = panel.attr( "id" );
5588 if ( !headerId ) {
5589 headerId = accordionId + "-header-" + i;
5590 header.attr( "id", headerId );
5591 }
5592 if ( !panelId ) {
5593 panelId = accordionId + "-panel-" + i;
5594 panel.attr( "id", panelId );
5595 }
5596 header.attr( "aria-controls", panelId );
5597 panel.attr( "aria-labelledby", headerId );
5598 })
5599 .next()
5600 .attr( "role", "tabpanel" );
5601
5602 this.headers
5603 .not( this.active )
5604 .attr({
5605 "aria-selected": "false",
5606 tabIndex: -1
5607 })
5608 .next()
5609 .attr({
5610 "aria-expanded": "false",
5611 "aria-hidden": "true"
5612 })
5613 .hide();
5614
5615 // make sure at least one header is in the tab order
5616 if ( !this.active.length ) {
5617 this.headers.eq( 0 ).attr( "tabIndex", 0 );
5618 } else {
5619 this.active.attr({
5620 "aria-selected": "true",
5621 tabIndex: 0
5622 })
5623 .next()
5624 .attr({
5625 "aria-expanded": "true",
5626 "aria-hidden": "false"
5627 });
5628 }
5629
5630 this._on( this.headers, { keydown: "_keydown" });
5631 this._on( this.headers.next(), { keydown: "_panelKeyDown" });
5632 this._setupEvents( options.event );
5633 },
5634
5635 _getCreateEventData: function() {
5636 return {
5637 header: this.active,
5638 content: !this.active.length ? $() : this.active.next()
5639 };
5640 },
5641
5642 _createIcons: function() {
5643 var icons = this.options.icons;
5644 if ( icons ) {
5645 $( "<span>" )
5646 .addClass( "ui-accordion-header-icon ui-icon " + icons.header )
5647 .prependTo( this.headers );
5648 this.active.children( ".ui-accordion-header-icon" )
5649 .removeClass( icons.header )
5650 .addClass( icons.activeHeader );
5651 this.headers.addClass( "ui-accordion-icons" );
5652 }
5653 },
5654
5655 _destroyIcons: function() {
5656 this.headers
5657 .removeClass( "ui-accordion-icons" )
5658 .children( ".ui-accordion-header-icon" )
5659 .remove();
5660 },
5661
5662 _destroy: function() {
5663 var contents;
5664
5665 // clean up main element
5666 this.element
5667 .removeClass( "ui-accordion ui-widget ui-helper-reset" )
5668 .removeAttr( "role" );
5669
5670 // clean up headers
5671 this.headers
5672 .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" )
5673 .removeAttr( "role" )
5674 .removeAttr( "aria-selected" )
5675 .removeAttr( "aria-controls" )
5676 .removeAttr( "tabIndex" )
5677 .each(function() {
5678 if ( /^ui-accordion/.test( this.id ) ) {
5679 this.removeAttribute( "id" );
5680 }
5681 });
5682 this._destroyIcons();
5683
5684 // clean up content panels
5685 contents = this.headers.next()
5686 .css( "display", "" )
5687 .removeAttr( "role" )
5688 .removeAttr( "aria-expanded" )
5689 .removeAttr( "aria-hidden" )
5690 .removeAttr( "aria-labelledby" )
5691 .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" )
5692 .each(function() {
5693 if ( /^ui-accordion/.test( this.id ) ) {
5694 this.removeAttribute( "id" );
5695 }
5696 });
5697 if ( this.options.heightStyle !== "content" ) {
5698 contents.css( "height", "" );
5699 }
5700 },
5701
5702 _setOption: function( key, value ) {
5703 if ( key === "active" ) {
5704 // _activate() will handle invalid values and update this.options
5705 this._activate( value );
5706 return;
5707 }
5708
5709 if ( key === "event" ) {
5710 if ( this.options.event ) {
5711 this._off( this.headers, this.options.event );
5712 }
5713 this._setupEvents( value );
5714 }
5715
5716 this._super( key, value );
5717
5718 // setting collapsible: false while collapsed; open first panel
5719 if ( key === "collapsible" && !value && this.options.active === false ) {
5720 this._activate( 0 );
5721 }
5722
5723 if ( key === "icons" ) {
5724 this._destroyIcons();
5725 if ( value ) {
5726 this._createIcons();
5727 }
5728 }
5729
5730 // #5332 - opacity doesn't cascade to positioned elements in IE
5731 // so we need to add the disabled class to the headers and panels
5732 if ( key === "disabled" ) {
5733 this.headers.add( this.headers.next() )
5734 .toggleClass( "ui-state-disabled", !!value );
5735 }
5736 },
5737
5738 _keydown: function( event ) {
5739 if ( event.altKey || event.ctrlKey ) {
5740 return;
5741 }
5742
5743 var keyCode = $.ui.keyCode,
5744 length = this.headers.length,
5745 currentIndex = this.headers.index( event.target ),
5746 toFocus = false;
5747
5748 switch ( event.keyCode ) {
5749 case keyCode.RIGHT:
5750 case keyCode.DOWN:
5751 toFocus = this.headers[ ( currentIndex + 1 ) % length ];
5752 break;
5753 case keyCode.LEFT:
5754 case keyCode.UP:
5755 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
5756 break;
5757 case keyCode.SPACE:
5758 case keyCode.ENTER:
5759 this._eventHandler( event );
5760 break;
5761 case keyCode.HOME:
5762 toFocus = this.headers[ 0 ];
5763 break;
5764 case keyCode.END:
5765 toFocus = this.headers[ length - 1 ];
5766 break;
5767 }
5768
5769 if ( toFocus ) {
5770 $( event.target ).attr( "tabIndex", -1 );
5771 $( toFocus ).attr( "tabIndex", 0 );
5772 toFocus.focus();
5773 event.preventDefault();
5774 }
5775 },
5776
5777 _panelKeyDown : function( event ) {
5778 if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
5779 $( event.currentTarget ).prev().focus();
5780 }
5781 },
5782
5783 refresh: function() {
5784 var maxHeight, overflow,
5785 heightStyle = this.options.heightStyle,
5786 parent = this.element.parent();
5787
5788
5789 if ( heightStyle === "fill" ) {
5790 // IE 6 treats height like minHeight, so we need to turn off overflow
5791 // in order to get a reliable height
5792 // we use the minHeight support test because we assume that only
5793 // browsers that don't support minHeight will treat height as minHeight
5794 if ( !$.support.minHeight ) {
5795 overflow = parent.css( "overflow" );
5796 parent.css( "overflow", "hidden");
5797 }
5798 maxHeight = parent.height();
5799 this.element.siblings( ":visible" ).each(function() {
5800 var elem = $( this ),
5801 position = elem.css( "position" );
5802
5803 if ( position === "absolute" || position === "fixed" ) {
5804 return;
5805 }
5806 maxHeight -= elem.outerHeight( true );
5807 });
5808 if ( overflow ) {
5809 parent.css( "overflow", overflow );
5810 }
5811
5812 this.headers.each(function() {
5813 maxHeight -= $( this ).outerHeight( true );
5814 });
5815
5816 this.headers.next()
5817 .each(function() {
5818 $( this ).height( Math.max( 0, maxHeight -
5819 $( this ).innerHeight() + $( this ).height() ) );
5820 })
5821 .css( "overflow", "auto" );
5822 } else if ( heightStyle === "auto" ) {
5823 maxHeight = 0;
5824 this.headers.next()
5825 .each(function() {
5826 maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
5827 })
5828 .height( maxHeight );
5829 }
5830 },
5831
5832 _activate: function( index ) {
5833 var active = this._findActive( index )[ 0 ];
5834
5835 // trying to activate the already active panel
5836 if ( active === this.active[ 0 ] ) {
5837 return;
5838 }
5839
5840 // trying to collapse, simulate a click on the currently active header
5841 active = active || this.active[ 0 ];
5842
5843 this._eventHandler({
5844 target: active,
5845 currentTarget: active,
5846 preventDefault: $.noop
5847 });
5848 },
5849
5850 _findActive: function( selector ) {
5851 return typeof selector === "number" ? this.headers.eq( selector ) : $();
5852 },
5853
5854 _setupEvents: function( event ) {
5855 var events = {};
5856 if ( !event ) {
5857 return;
5858 }
5859 $.each( event.split(" "), function( index, eventName ) {
5860 events[ eventName ] = "_eventHandler";
5861 });
5862 this._on( this.headers, events );
5863 },
5864
5865 _eventHandler: function( event ) {
5866 var options = this.options,
5867 active = this.active,
5868 clicked = $( event.currentTarget ),
5869 clickedIsActive = clicked[ 0 ] === active[ 0 ],
5870 collapsing = clickedIsActive && options.collapsible,
5871 toShow = collapsing ? $() : clicked.next(),
5872 toHide = active.next(),
5873 eventData = {
5874 oldHeader: active,
5875 oldPanel: toHide,
5876 newHeader: collapsing ? $() : clicked,
5877 newPanel: toShow
5878 };
5879
5880 event.preventDefault();
5881
5882 if (
5883 // click on active header, but not collapsible
5884 ( clickedIsActive && !options.collapsible ) ||
5885 // allow canceling activation
5886 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
5887 return;
5888 }
5889
5890 options.active = collapsing ? false : this.headers.index( clicked );
5891
5892 // when the call to ._toggle() comes after the class changes
5893 // it causes a very odd bug in IE 8 (see #6720)
5894 this.active = clickedIsActive ? $() : clicked;
5895 this._toggle( eventData );
5896
5897 // switch classes
5898 // corner classes on the previously active header stay after the animation
5899 active.removeClass( "ui-accordion-header-active ui-state-active" );
5900 if ( options.icons ) {
5901 active.children( ".ui-accordion-header-icon" )
5902 .removeClass( options.icons.activeHeader )
5903 .addClass( options.icons.header );
5904 }
5905
5906 if ( !clickedIsActive ) {
5907 clicked
5908 .removeClass( "ui-corner-all" )
5909 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" );
5910 if ( options.icons ) {
5911 clicked.children( ".ui-accordion-header-icon" )
5912 .removeClass( options.icons.header )
5913 .addClass( options.icons.activeHeader );
5914 }
5915
5916 clicked
5917 .next()
5918 .addClass( "ui-accordion-content-active" );
5919 }
5920 },
5921
5922 _toggle: function( data ) {
5923 var toShow = data.newPanel,
5924 toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
5925
5926 // handle activating a panel during the animation for another activation
5927 this.prevShow.add( this.prevHide ).stop( true, true );
5928 this.prevShow = toShow;
5929 this.prevHide = toHide;
5930
5931 if ( this.options.animate ) {
5932 this._animate( toShow, toHide, data );
5933 } else {
5934 toHide.hide();
5935 toShow.show();
5936 this._toggleComplete( data );
5937 }
5938
5939 toHide.attr({
5940 "aria-expanded": "false",
5941 "aria-hidden": "true"
5942 });
5943 toHide.prev().attr( "aria-selected", "false" );
5944 // if we're switching panels, remove the old header from the tab order
5945 // if we're opening from collapsed state, remove the previous header from the tab order
5946 // if we're collapsing, then keep the collapsing header in the tab order
5947 if ( toShow.length && toHide.length ) {
5948 toHide.prev().attr( "tabIndex", -1 );
5949 } else if ( toShow.length ) {
5950 this.headers.filter(function() {
5951 return $( this ).attr( "tabIndex" ) === 0;
5952 })
5953 .attr( "tabIndex", -1 );
5954 }
5955
5956 toShow
5957 .attr({
5958 "aria-expanded": "true",
5959 "aria-hidden": "false"
5960 })
5961 .prev()
5962 .attr({
5963 "aria-selected": "true",
5964 tabIndex: 0
5965 });
5966 },
5967
5968 _animate: function( toShow, toHide, data ) {
5969 var total, easing, duration,
5970 that = this,
5971 adjust = 0,
5972 down = toShow.length &&
5973 ( !toHide.length || ( toShow.index() < toHide.index() ) ),
5974 animate = this.options.animate || {},
5975 options = down && animate.down || animate,
5976 complete = function() {
5977 that._toggleComplete( data );
5978 };
5979
5980 if ( typeof options === "number" ) {
5981 duration = options;
5982 }
5983 if ( typeof options === "string" ) {
5984 easing = options;
5985 }
5986 // fall back from options to animation in case of partial down settings
5987 easing = easing || options.easing || animate.easing;
5988 duration = duration || options.duration || animate.duration;
5989
5990 if ( !toHide.length ) {
5991 return toShow.animate( showProps, duration, easing, complete );
5992 }
5993 if ( !toShow.length ) {
5994 return toHide.animate( hideProps, duration, easing, complete );
5995 }
5996
5997 total = toShow.show().outerHeight();
5998 toHide.animate( hideProps, {
5999 duration: duration,
6000 easing: easing,
6001 step: function( now, fx ) {
6002 fx.now = Math.round( now );
6003 }
6004 });
6005 toShow
6006 .hide()
6007 .animate( showProps, {
6008 duration: duration,
6009 easing: easing,
6010 complete: complete,
6011 step: function( now, fx ) {
6012 fx.now = Math.round( now );
6013 if ( fx.prop !== "height" ) {
6014 adjust += fx.now;
6015 } else if ( that.options.heightStyle !== "content" ) {
6016 fx.now = Math.round( total - toHide.outerHeight() - adjust );
6017 adjust = 0;
6018 }
6019 }
6020 });
6021 },
6022
6023 _toggleComplete: function( data ) {
6024 var toHide = data.oldPanel;
6025
6026 toHide
6027 .removeClass( "ui-accordion-content-active" )
6028 .prev()
6029 .removeClass( "ui-corner-top" )
6030 .addClass( "ui-corner-all" );
6031
6032 // Work around for rendering bug in IE (#5421)
6033 if ( toHide.length ) {
6034 toHide.parent()[0].className = toHide.parent()[0].className;
6035 }
6036
6037 this._trigger( "activate", null, data );
6038 }
6039});
6040
6041
6042
6043// DEPRECATED
6044if ( $.uiBackCompat !== false ) {
6045 // navigation options
6046 (function( $, prototype ) {
6047 $.extend( prototype.options, {
6048 navigation: false,
6049 navigationFilter: function() {
6050 return this.href.toLowerCase() === location.href.toLowerCase();
6051 }
6052 });
6053
6054 var _create = prototype._create;
6055 prototype._create = function() {
6056 if ( this.options.navigation ) {
6057 var that = this,
6058 headers = this.element.find( this.options.header ),
6059 content = headers.next(),
6060 current = headers.add( content )
6061 .find( "a" )
6062 .filter( this.options.navigationFilter )
6063 [ 0 ];
6064 if ( current ) {
6065 headers.add( content ).each( function( index ) {
6066 if ( $.contains( this, current ) ) {
6067 that.options.active = Math.floor( index / 2 );
6068 return false;
6069 }
6070 });
6071 }
6072 }
6073 _create.call( this );
6074 };
6075 }( jQuery, jQuery.ui.accordion.prototype ) );
6076
6077 // height options
6078 (function( $, prototype ) {
6079 $.extend( prototype.options, {
6080 heightStyle: null, // remove default so we fall back to old values
6081 autoHeight: true, // use heightStyle: "auto"
6082 clearStyle: false, // use heightStyle: "content"
6083 fillSpace: false // use heightStyle: "fill"
6084 });
6085
6086 var _create = prototype._create,
6087 _setOption = prototype._setOption;
6088
6089 $.extend( prototype, {
6090 _create: function() {
6091 this.options.heightStyle = this.options.heightStyle ||
6092 this._mergeHeightStyle();
6093
6094 _create.call( this );
6095 },
6096
6097 _setOption: function( key ) {
6098 if ( key === "autoHeight" || key === "clearStyle" || key === "fillSpace" ) {
6099 this.options.heightStyle = this._mergeHeightStyle();
6100 }
6101 _setOption.apply( this, arguments );
6102 },
6103
6104 _mergeHeightStyle: function() {
6105 var options = this.options;
6106
6107 if ( options.fillSpace ) {
6108 return "fill";
6109 }
6110
6111 if ( options.clearStyle ) {
6112 return "content";
6113 }
6114
6115 if ( options.autoHeight ) {
6116 return "auto";
6117 }
6118 }
6119 });
6120 }( jQuery, jQuery.ui.accordion.prototype ) );
6121
6122 // icon options
6123 (function( $, prototype ) {
6124 $.extend( prototype.options.icons, {
6125 activeHeader: null, // remove default so we fall back to old values
6126 headerSelected: "ui-icon-triangle-1-s"
6127 });
6128
6129 var _createIcons = prototype._createIcons;
6130 prototype._createIcons = function() {
6131 if ( this.options.icons ) {
6132 this.options.icons.activeHeader = this.options.icons.activeHeader ||
6133 this.options.icons.headerSelected;
6134 }
6135 _createIcons.call( this );
6136 };
6137 }( jQuery, jQuery.ui.accordion.prototype ) );
6138
6139 // expanded active option, activate method
6140 (function( $, prototype ) {
6141 prototype.activate = prototype._activate;
6142
6143 var _findActive = prototype._findActive;
6144 prototype._findActive = function( index ) {
6145 if ( index === -1 ) {
6146 index = false;
6147 }
6148 if ( index && typeof index !== "number" ) {
6149 index = this.headers.index( this.headers.filter( index ) );
6150 if ( index === -1 ) {
6151 index = false;
6152 }
6153 }
6154 return _findActive.call( this, index );
6155 };
6156 }( jQuery, jQuery.ui.accordion.prototype ) );
6157
6158 // resize method
6159 jQuery.ui.accordion.prototype.resize = jQuery.ui.accordion.prototype.refresh;
6160
6161 // change events
6162 (function( $, prototype ) {
6163 $.extend( prototype.options, {
6164 change: null,
6165 changestart: null
6166 });
6167
6168 var _trigger = prototype._trigger;
6169 prototype._trigger = function( type, event, data ) {
6170 var ret = _trigger.apply( this, arguments );
6171 if ( !ret ) {
6172 return false;
6173 }
6174
6175 if ( type === "beforeActivate" ) {
6176 ret = _trigger.call( this, "changestart", event, {
6177 oldHeader: data.oldHeader,
6178 oldContent: data.oldPanel,
6179 newHeader: data.newHeader,
6180 newContent: data.newPanel
6181 });
6182 } else if ( type === "activate" ) {
6183 ret = _trigger.call( this, "change", event, {
6184 oldHeader: data.oldHeader,
6185 oldContent: data.oldPanel,
6186 newHeader: data.newHeader,
6187 newContent: data.newPanel
6188 });
6189 }
6190 return ret;
6191 };
6192 }( jQuery, jQuery.ui.accordion.prototype ) );
6193
6194 // animated option
6195 // NOTE: this only provides support for "slide", "bounceslide", and easings
6196 // not the full $.ui.accordion.animations API
6197 (function( $, prototype ) {
6198 $.extend( prototype.options, {
6199 animate: null,
6200 animated: "slide"
6201 });
6202
6203 var _create = prototype._create;
6204 prototype._create = function() {
6205 var options = this.options;
6206 if ( options.animate === null ) {
6207 if ( !options.animated ) {
6208 options.animate = false;
6209 } else if ( options.animated === "slide" ) {
6210 options.animate = 300;
6211 } else if ( options.animated === "bounceslide" ) {
6212 options.animate = {
6213 duration: 200,
6214 down: {
6215 easing: "easeOutBounce",
6216 duration: 1000
6217 }
6218 };
6219 } else {
6220 options.animate = options.animated;
6221 }
6222 }
6223
6224 _create.call( this );
6225 };
6226 }( jQuery, jQuery.ui.accordion.prototype ) );
6227}
6228
6229})( jQuery );
6230
6231(function( $, undefined ) {
6232
6233// used to prevent race conditions with remote data sources
6234var requestIndex = 0;
6235
6236$.widget( "ui.autocomplete", {
6237 version: "1.9.2",
6238 defaultElement: "<input>",
6239 options: {
6240 appendTo: "body",
6241 autoFocus: false,
6242 delay: 300,
6243 minLength: 1,
6244 position: {
6245 my: "left top",
6246 at: "left bottom",
6247 collision: "none"
6248 },
6249 source: null,
6250
6251 // callbacks
6252 change: null,
6253 close: null,
6254 focus: null,
6255 open: null,
6256 response: null,
6257 search: null,
6258 select: null
6259 },
6260
6261 pending: 0,
6262
6263 _create: function() {
6264 // Some browsers only repeat keydown events, not keypress events,
6265 // so we use the suppressKeyPress flag to determine if we've already
6266 // handled the keydown event. #7269
6267 // Unfortunately the code for & in keypress is the same as the up arrow,
6268 // so we use the suppressKeyPressRepeat flag to avoid handling keypress
6269 // events when we know the keydown event was used to modify the
6270 // search term. #7799
6271 var suppressKeyPress, suppressKeyPressRepeat, suppressInput;
6272
6273 this.isMultiLine = this._isMultiLine();
6274 this.valueMethod = this.element[ this.element.is( "input,textarea" ) ? "val" : "text" ];
6275 this.isNewMenu = true;
6276
6277 this.element
6278 .addClass( "ui-autocomplete-input" )
6279 .attr( "autocomplete", "off" );
6280
6281 this._on( this.element, {
6282 keydown: function( event ) {
6283 if ( this.element.prop( "readOnly" ) ) {
6284 suppressKeyPress = true;
6285 suppressInput = true;
6286 suppressKeyPressRepeat = true;
6287 return;
6288 }
6289
6290 suppressKeyPress = false;
6291 suppressInput = false;
6292 suppressKeyPressRepeat = false;
6293 var keyCode = $.ui.keyCode;
6294 switch( event.keyCode ) {
6295 case keyCode.PAGE_UP:
6296 suppressKeyPress = true;
6297 this._move( "previousPage", event );
6298 break;
6299 case keyCode.PAGE_DOWN:
6300 suppressKeyPress = true;
6301 this._move( "nextPage", event );
6302 break;
6303 case keyCode.UP:
6304 suppressKeyPress = true;
6305 this._keyEvent( "previous", event );
6306 break;
6307 case keyCode.DOWN:
6308 suppressKeyPress = true;
6309 this._keyEvent( "next", event );
6310 break;
6311 case keyCode.ENTER:
6312 case keyCode.NUMPAD_ENTER:
6313 // when menu is open and has focus
6314 if ( this.menu.active ) {
6315 // #6055 - Opera still allows the keypress to occur
6316 // which causes forms to submit
6317 suppressKeyPress = true;
6318 event.preventDefault();
6319 this.menu.select( event );
6320 }
6321 break;
6322 case keyCode.TAB:
6323 if ( this.menu.active ) {
6324 this.menu.select( event );
6325 }
6326 break;
6327 case keyCode.ESCAPE:
6328 if ( this.menu.element.is( ":visible" ) ) {
6329 this._value( this.term );
6330 this.close( event );
6331 // Different browsers have different default behavior for escape
6332 // Single press can mean undo or clear
6333 // Double press in IE means clear the whole form
6334 event.preventDefault();
6335 }
6336 break;
6337 default:
6338 suppressKeyPressRepeat = true;
6339 // search timeout should be triggered before the input value is changed
6340 this._searchTimeout( event );
6341 break;
6342 }
6343 },
6344 keypress: function( event ) {
6345 if ( suppressKeyPress ) {
6346 suppressKeyPress = false;
6347 event.preventDefault();
6348 return;
6349 }
6350 if ( suppressKeyPressRepeat ) {
6351 return;
6352 }
6353
6354 // replicate some key handlers to allow them to repeat in Firefox and Opera
6355 var keyCode = $.ui.keyCode;
6356 switch( event.keyCode ) {
6357 case keyCode.PAGE_UP:
6358 this._move( "previousPage", event );
6359 break;
6360 case keyCode.PAGE_DOWN:
6361 this._move( "nextPage", event );
6362 break;
6363 case keyCode.UP:
6364 this._keyEvent( "previous", event );
6365 break;
6366 case keyCode.DOWN:
6367 this._keyEvent( "next", event );
6368 break;
6369 }
6370 },
6371 input: function( event ) {
6372 if ( suppressInput ) {
6373 suppressInput = false;
6374 event.preventDefault();
6375 return;
6376 }
6377 this._searchTimeout( event );
6378 },
6379 focus: function() {
6380 this.selectedItem = null;
6381 this.previous = this._value();
6382 },
6383 blur: function( event ) {
6384 if ( this.cancelBlur ) {
6385 delete this.cancelBlur;
6386 return;
6387 }
6388
6389 clearTimeout( this.searching );
6390 this.close( event );
6391 this._change( event );
6392 }
6393 });
6394
6395 this._initSource();
6396 this.menu = $( "<ul>" )
6397 .addClass( "ui-autocomplete" )
6398 .appendTo( this.document.find( this.options.appendTo || "body" )[ 0 ] )
6399 .menu({
6400 // custom key handling for now
6401 input: $(),
6402 // disable ARIA support, the live region takes care of that
6403 role: null
6404 })
6405 .zIndex( this.element.zIndex() + 1 )
6406 .hide()
6407 .data( "menu" );
6408
6409 this._on( this.menu.element, {
6410 mousedown: function( event ) {
6411 // prevent moving focus out of the text field
6412 event.preventDefault();
6413
6414 // IE doesn't prevent moving focus even with event.preventDefault()
6415 // so we set a flag to know when we should ignore the blur event
6416 this.cancelBlur = true;
6417 this._delay(function() {
6418 delete this.cancelBlur;
6419 });
6420
6421 // clicking on the scrollbar causes focus to shift to the body
6422 // but we can't detect a mouseup or a click immediately afterward
6423 // so we have to track the next mousedown and close the menu if
6424 // the user clicks somewhere outside of the autocomplete
6425 var menuElement = this.menu.element[ 0 ];
6426 if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
6427 this._delay(function() {
6428 var that = this;
6429 this.document.one( "mousedown", function( event ) {
6430 if ( event.target !== that.element[ 0 ] &&
6431 event.target !== menuElement &&
6432 !$.contains( menuElement, event.target ) ) {
6433 that.close();
6434 }
6435 });
6436 });
6437 }
6438 },
6439 menufocus: function( event, ui ) {
6440 // #7024 - Prevent accidental activation of menu items in Firefox
6441 if ( this.isNewMenu ) {
6442 this.isNewMenu = false;
6443 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
6444 this.menu.blur();
6445
6446 this.document.one( "mousemove", function() {
6447 $( event.target ).trigger( event.originalEvent );
6448 });
6449
6450 return;
6451 }
6452 }
6453
6454 // back compat for _renderItem using item.autocomplete, via #7810
6455 // TODO remove the fallback, see #8156
6456 var item = ui.item.data( "ui-autocomplete-item" ) || ui.item.data( "item.autocomplete" );
6457 if ( false !== this._trigger( "focus", event, { item: item } ) ) {
6458 // use value to match what will end up in the input, if it was a key event
6459 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
6460 this._value( item.value );
6461 }
6462 } else {
6463 // Normally the input is populated with the item's value as the
6464 // menu is navigated, causing screen readers to notice a change and
6465 // announce the item. Since the focus event was canceled, this doesn't
6466 // happen, so we update the live region so that screen readers can
6467 // still notice the change and announce it.
6468 this.liveRegion.text( item.value );
6469 }
6470 },
6471 menuselect: function( event, ui ) {
6472 // back compat for _renderItem using item.autocomplete, via #7810
6473 // TODO remove the fallback, see #8156
6474 var item = ui.item.data( "ui-autocomplete-item" ) || ui.item.data( "item.autocomplete" ),
6475 previous = this.previous;
6476
6477 // only trigger when focus was lost (click on menu)
6478 if ( this.element[0] !== this.document[0].activeElement ) {
6479 this.element.focus();
6480 this.previous = previous;
6481 // #6109 - IE triggers two focus events and the second
6482 // is asynchronous, so we need to reset the previous
6483 // term synchronously and asynchronously :-(
6484 this._delay(function() {
6485 this.previous = previous;
6486 this.selectedItem = item;
6487 });
6488 }
6489
6490 if ( false !== this._trigger( "select", event, { item: item } ) ) {
6491 this._value( item.value );
6492 }
6493 // reset the term after the select event
6494 // this allows custom select handling to work properly
6495 this.term = this._value();
6496
6497 this.close( event );
6498 this.selectedItem = item;
6499 }
6500 });
6501
6502 this.liveRegion = $( "<span>", {
6503 role: "status",
6504 "aria-live": "polite"
6505 })
6506 .addClass( "ui-helper-hidden-accessible" )
6507 .insertAfter( this.element );
6508
6509 if ( $.fn.bgiframe ) {
6510 this.menu.element.bgiframe();
6511 }
6512
6513 // turning off autocomplete prevents the browser from remembering the
6514 // value when navigating through history, so we re-enable autocomplete
6515 // if the page is unloaded before the widget is destroyed. #7790
6516 this._on( this.window, {
6517 beforeunload: function() {
6518 this.element.removeAttr( "autocomplete" );
6519 }
6520 });
6521 },
6522
6523 _destroy: function() {
6524 clearTimeout( this.searching );
6525 this.element
6526 .removeClass( "ui-autocomplete-input" )
6527 .removeAttr( "autocomplete" );
6528 this.menu.element.remove();
6529 this.liveRegion.remove();
6530 },
6531
6532 _setOption: function( key, value ) {
6533 this._super( key, value );
6534 if ( key === "source" ) {
6535 this._initSource();
6536 }
6537 if ( key === "appendTo" ) {
6538 this.menu.element.appendTo( this.document.find( value || "body" )[0] );
6539 }
6540 if ( key === "disabled" && value && this.xhr ) {
6541 this.xhr.abort();
6542 }
6543 },
6544
6545 _isMultiLine: function() {
6546 // Textareas are always multi-line
6547 if ( this.element.is( "textarea" ) ) {
6548 return true;
6549 }
6550 // Inputs are always single-line, even if inside a contentEditable element
6551 // IE also treats inputs as contentEditable
6552 if ( this.element.is( "input" ) ) {
6553 return false;
6554 }
6555 // All other element types are determined by whether or not they're contentEditable
6556 return this.element.prop( "isContentEditable" );
6557 },
6558
6559 _initSource: function() {
6560 var array, url,
6561 that = this;
6562 if ( $.isArray(this.options.source) ) {
6563 array = this.options.source;
6564 this.source = function( request, response ) {
6565 response( $.ui.autocomplete.filter( array, request.term ) );
6566 };
6567 } else if ( typeof this.options.source === "string" ) {
6568 url = this.options.source;
6569 this.source = function( request, response ) {
6570 if ( that.xhr ) {
6571 that.xhr.abort();
6572 }
6573 that.xhr = $.ajax({
6574 url: url,
6575 data: request,
6576 dataType: "json",
6577 success: function( data ) {
6578 response( data );
6579 },
6580 error: function() {
6581 response( [] );
6582 }
6583 });
6584 };
6585 } else {
6586 this.source = this.options.source;
6587 }
6588 },
6589
6590 _searchTimeout: function( event ) {
6591 clearTimeout( this.searching );
6592 this.searching = this._delay(function() {
6593 // only search if the value has changed
6594 if ( this.term !== this._value() ) {
6595 this.selectedItem = null;
6596 this.search( null, event );
6597 }
6598 }, this.options.delay );
6599 },
6600
6601 search: function( value, event ) {
6602 value = value != null ? value : this._value();
6603
6604 // always save the actual value, not the one passed as an argument
6605 this.term = this._value();
6606
6607 if ( value.length < this.options.minLength ) {
6608 return this.close( event );
6609 }
6610
6611 if ( this._trigger( "search", event ) === false ) {
6612 return;
6613 }
6614
6615 return this._search( value );
6616 },
6617
6618 _search: function( value ) {
6619 this.pending++;
6620 this.element.addClass( "ui-autocomplete-loading" );
6621 this.cancelSearch = false;
6622
6623 this.source( { term: value }, this._response() );
6624 },
6625
6626 _response: function() {
6627 var that = this,
6628 index = ++requestIndex;
6629
6630 return function( content ) {
6631 if ( index === requestIndex ) {
6632 that.__response( content );
6633 }
6634
6635 that.pending--;
6636 if ( !that.pending ) {
6637 that.element.removeClass( "ui-autocomplete-loading" );
6638 }
6639 };
6640 },
6641
6642 __response: function( content ) {
6643 if ( content ) {
6644 content = this._normalize( content );
6645 }
6646 this._trigger( "response", null, { content: content } );
6647 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
6648 this._suggest( content );
6649 this._trigger( "open" );
6650 } else {
6651 // use ._close() instead of .close() so we don't cancel future searches
6652 this._close();
6653 }
6654 },
6655
6656 close: function( event ) {
6657 this.cancelSearch = true;
6658 this._close( event );
6659 },
6660
6661 _close: function( event ) {
6662 if ( this.menu.element.is( ":visible" ) ) {
6663 this.menu.element.hide();
6664 this.menu.blur();
6665 this.isNewMenu = true;
6666 this._trigger( "close", event );
6667 }
6668 },
6669
6670 _change: function( event ) {
6671 if ( this.previous !== this._value() ) {
6672 this._trigger( "change", event, { item: this.selectedItem } );
6673 }
6674 },
6675
6676 _normalize: function( items ) {
6677 // assume all items have the right format when the first item is complete
6678 if ( items.length && items[0].label && items[0].value ) {
6679 return items;
6680 }
6681 return $.map( items, function( item ) {
6682 if ( typeof item === "string" ) {
6683 return {
6684 label: item,
6685 value: item
6686 };
6687 }
6688 return $.extend({
6689 label: item.label || item.value,
6690 value: item.value || item.label
6691 }, item );
6692 });
6693 },
6694
6695 _suggest: function( items ) {
6696 var ul = this.menu.element
6697 .empty()
6698 .zIndex( this.element.zIndex() + 1 );
6699 this._renderMenu( ul, items );
6700 this.menu.refresh();
6701
6702 // size and position menu
6703 ul.show();
6704 this._resizeMenu();
6705 ul.position( $.extend({
6706 of: this.element
6707 }, this.options.position ));
6708
6709 if ( this.options.autoFocus ) {
6710 this.menu.next();
6711 }
6712 },
6713
6714 _resizeMenu: function() {
6715 var ul = this.menu.element;
6716 ul.outerWidth( Math.max(
6717 // Firefox wraps long text (possibly a rounding bug)
6718 // so we add 1px to avoid the wrapping (#7513)
6719 ul.width( "" ).outerWidth() + 1,
6720 this.element.outerWidth()
6721 ) );
6722 },
6723
6724 _renderMenu: function( ul, items ) {
6725 var that = this;
6726 $.each( items, function( index, item ) {
6727 that._renderItemData( ul, item );
6728 });
6729 },
6730
6731 _renderItemData: function( ul, item ) {
6732 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
6733 },
6734
6735 _renderItem: function( ul, item ) {
6736 return $( "<li>" )
6737 .append( $( "<a>" ).text( item.label ) )
6738 .appendTo( ul );
6739 },
6740
6741 _move: function( direction, event ) {
6742 if ( !this.menu.element.is( ":visible" ) ) {
6743 this.search( null, event );
6744 return;
6745 }
6746 if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
6747 this.menu.isLastItem() && /^next/.test( direction ) ) {
6748 this._value( this.term );
6749 this.menu.blur();
6750 return;
6751 }
6752 this.menu[ direction ]( event );
6753 },
6754
6755 widget: function() {
6756 return this.menu.element;
6757 },
6758
6759 _value: function() {
6760 return this.valueMethod.apply( this.element, arguments );
6761 },
6762
6763 _keyEvent: function( keyEvent, event ) {
6764 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
6765 this._move( keyEvent, event );
6766
6767 // prevents moving cursor to beginning/end of the text field in some browsers
6768 event.preventDefault();
6769 }
6770 }
6771});
6772
6773$.extend( $.ui.autocomplete, {
6774 escapeRegex: function( value ) {
6775 return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
6776 },
6777 filter: function(array, term) {
6778 var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
6779 return $.grep( array, function(value) {
6780 return matcher.test( value.label || value.value || value );
6781 });
6782 }
6783});
6784
6785
6786// live region extension, adding a `messages` option
6787// NOTE: This is an experimental API. We are still investigating
6788// a full solution for string manipulation and internationalization.
6789$.widget( "ui.autocomplete", $.ui.autocomplete, {
6790 options: {
6791 messages: {
6792 noResults: "No search results.",
6793 results: function( amount ) {
6794 return amount + ( amount > 1 ? " results are" : " result is" ) +
6795 " available, use up and down arrow keys to navigate.";
6796 }
6797 }
6798 },
6799
6800 __response: function( content ) {
6801 var message;
6802 this._superApply( arguments );
6803 if ( this.options.disabled || this.cancelSearch ) {
6804 return;
6805 }
6806 if ( content && content.length ) {
6807 message = this.options.messages.results( content.length );
6808 } else {
6809 message = this.options.messages.noResults;
6810 }
6811 this.liveRegion.text( message );
6812 }
6813});
6814
6815
6816}( jQuery ));
6817
6818(function( $, undefined ) {
6819
6820var lastActive, startXPos, startYPos, clickDragged,
6821 baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
6822 stateClasses = "ui-state-hover ui-state-active ",
6823 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",
6824 formResetHandler = function() {
6825 var buttons = $( this ).find( ":ui-button" );
6826 setTimeout(function() {
6827 buttons.button( "refresh" );
6828 }, 1 );
6829 },
6830 radioGroup = function( radio ) {
6831 var name = radio.name,
6832 form = radio.form,
6833 radios = $( [] );
6834 if ( name ) {
6835 if ( form ) {
6836 radios = $( form ).find( "[name='" + name + "']" );
6837 } else {
6838 radios = $( "[name='" + name + "']", radio.ownerDocument )
6839 .filter(function() {
6840 return !this.form;
6841 });
6842 }
6843 }
6844 return radios;
6845 };
6846
6847$.widget( "ui.button", {
6848 version: "1.9.2",
6849 defaultElement: "<button>",
6850 options: {
6851 disabled: null,
6852 text: true,
6853 label: null,
6854 icons: {
6855 primary: null,
6856 secondary: null
6857 }
6858 },
6859 _create: function() {
6860 this.element.closest( "form" )
6861 .unbind( "reset" + this.eventNamespace )
6862 .bind( "reset" + this.eventNamespace, formResetHandler );
6863
6864 if ( typeof this.options.disabled !== "boolean" ) {
6865 this.options.disabled = !!this.element.prop( "disabled" );
6866 } else {
6867 this.element.prop( "disabled", this.options.disabled );
6868 }
6869
6870 this._determineButtonType();
6871 this.hasTitle = !!this.buttonElement.attr( "title" );
6872
6873 var that = this,
6874 options = this.options,
6875 toggleButton = this.type === "checkbox" || this.type === "radio",
6876 activeClass = !toggleButton ? "ui-state-active" : "",
6877 focusClass = "ui-state-focus";
6878
6879 if ( options.label === null ) {
6880 options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html());
6881 }
6882
6883 this._hoverable( this.buttonElement );
6884
6885 this.buttonElement
6886 .addClass( baseClasses )
6887 .attr( "role", "button" )
6888 .bind( "mouseenter" + this.eventNamespace, function() {
6889 if ( options.disabled ) {
6890 return;
6891 }
6892 if ( this === lastActive ) {
6893 $( this ).addClass( "ui-state-active" );
6894 }
6895 })
6896 .bind( "mouseleave" + this.eventNamespace, function() {
6897 if ( options.disabled ) {
6898 return;
6899 }
6900 $( this ).removeClass( activeClass );
6901 })
6902 .bind( "click" + this.eventNamespace, function( event ) {
6903 if ( options.disabled ) {
6904 event.preventDefault();
6905 event.stopImmediatePropagation();
6906 }
6907 });
6908
6909 this.element
6910 .bind( "focus" + this.eventNamespace, function() {
6911 // no need to check disabled, focus won't be triggered anyway
6912 that.buttonElement.addClass( focusClass );
6913 })
6914 .bind( "blur" + this.eventNamespace, function() {
6915 that.buttonElement.removeClass( focusClass );
6916 });
6917
6918 if ( toggleButton ) {
6919 this.element.bind( "change" + this.eventNamespace, function() {
6920 if ( clickDragged ) {
6921 return;
6922 }
6923 that.refresh();
6924 });
6925 // if mouse moves between mousedown and mouseup (drag) set clickDragged flag
6926 // prevents issue where button state changes but checkbox/radio checked state
6927 // does not in Firefox (see ticket #6970)
6928 this.buttonElement
6929 .bind( "mousedown" + this.eventNamespace, function( event ) {
6930 if ( options.disabled ) {
6931 return;
6932 }
6933 clickDragged = false;
6934 startXPos = event.pageX;
6935 startYPos = event.pageY;
6936 })
6937 .bind( "mouseup" + this.eventNamespace, function( event ) {
6938 if ( options.disabled ) {
6939 return;
6940 }
6941 if ( startXPos !== event.pageX || startYPos !== event.pageY ) {
6942 clickDragged = true;
6943 }
6944 });
6945 }
6946
6947 if ( this.type === "checkbox" ) {
6948 this.buttonElement.bind( "click" + this.eventNamespace, function() {
6949 if ( options.disabled || clickDragged ) {
6950 return false;
6951 }
6952 $( this ).toggleClass( "ui-state-active" );
6953 that.buttonElement.attr( "aria-pressed", that.element[0].checked );
6954 });
6955 } else if ( this.type === "radio" ) {
6956 this.buttonElement.bind( "click" + this.eventNamespace, function() {
6957 if ( options.disabled || clickDragged ) {
6958 return false;
6959 }
6960 $( this ).addClass( "ui-state-active" );
6961 that.buttonElement.attr( "aria-pressed", "true" );
6962
6963 var radio = that.element[ 0 ];
6964 radioGroup( radio )
6965 .not( radio )
6966 .map(function() {
6967 return $( this ).button( "widget" )[ 0 ];
6968 })
6969 .removeClass( "ui-state-active" )
6970 .attr( "aria-pressed", "false" );
6971 });
6972 } else {
6973 this.buttonElement
6974 .bind( "mousedown" + this.eventNamespace, function() {
6975 if ( options.disabled ) {
6976 return false;
6977 }
6978 $( this ).addClass( "ui-state-active" );
6979 lastActive = this;
6980 that.document.one( "mouseup", function() {
6981 lastActive = null;
6982 });
6983 })
6984 .bind( "mouseup" + this.eventNamespace, function() {
6985 if ( options.disabled ) {
6986 return false;
6987 }
6988 $( this ).removeClass( "ui-state-active" );
6989 })
6990 .bind( "keydown" + this.eventNamespace, function(event) {
6991 if ( options.disabled ) {
6992 return false;
6993 }
6994 if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) {
6995 $( this ).addClass( "ui-state-active" );
6996 }
6997 })
6998 .bind( "keyup" + this.eventNamespace, function() {
6999 $( this ).removeClass( "ui-state-active" );
7000 });
7001
7002 if ( this.buttonElement.is("a") ) {
7003 this.buttonElement.keyup(function(event) {
7004 if ( event.keyCode === $.ui.keyCode.SPACE ) {
7005 // TODO pass through original event correctly (just as 2nd argument doesn't work)
7006 $( this ).click();
7007 }
7008 });
7009 }
7010 }
7011
7012 // TODO: pull out $.Widget's handling for the disabled option into
7013 // $.Widget.prototype._setOptionDisabled so it's easy to proxy and can
7014 // be overridden by individual plugins
7015 this._setOption( "disabled", options.disabled );
7016 this._resetButton();
7017 },
7018
7019 _determineButtonType: function() {
7020 var ancestor, labelSelector, checked;
7021
7022 if ( this.element.is("[type=checkbox]") ) {
7023 this.type = "checkbox";
7024 } else if ( this.element.is("[type=radio]") ) {
7025 this.type = "radio";
7026 } else if ( this.element.is("input") ) {
7027 this.type = "input";
7028 } else {
7029 this.type = "button";
7030 }
7031
7032 if ( this.type === "checkbox" || this.type === "radio" ) {
7033 // we don't search against the document in case the element
7034 // is disconnected from the DOM
7035 ancestor = this.element.parents().last();
7036 labelSelector = "label[for='" + this.element.attr("id") + "']";
7037 this.buttonElement = ancestor.find( labelSelector );
7038 if ( !this.buttonElement.length ) {
7039 ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
7040 this.buttonElement = ancestor.filter( labelSelector );
7041 if ( !this.buttonElement.length ) {
7042 this.buttonElement = ancestor.find( labelSelector );
7043 }
7044 }
7045 this.element.addClass( "ui-helper-hidden-accessible" );
7046
7047 checked = this.element.is( ":checked" );
7048 if ( checked ) {
7049 this.buttonElement.addClass( "ui-state-active" );
7050 }
7051 this.buttonElement.prop( "aria-pressed", checked );
7052 } else {
7053 this.buttonElement = this.element;
7054 }
7055 },
7056
7057 widget: function() {
7058 return this.buttonElement;
7059 },
7060
7061 _destroy: function() {
7062 this.element
7063 .removeClass( "ui-helper-hidden-accessible" );
7064 this.buttonElement
7065 .removeClass( baseClasses + " " + stateClasses + " " + typeClasses )
7066 .removeAttr( "role" )
7067 .removeAttr( "aria-pressed" )
7068 .html( this.buttonElement.find(".ui-button-text").html() );
7069
7070 if ( !this.hasTitle ) {
7071 this.buttonElement.removeAttr( "title" );
7072 }
7073 },
7074
7075 _setOption: function( key, value ) {
7076 this._super( key, value );
7077 if ( key === "disabled" ) {
7078 if ( value ) {
7079 this.element.prop( "disabled", true );
7080 } else {
7081 this.element.prop( "disabled", false );
7082 }
7083 return;
7084 }
7085 this._resetButton();
7086 },
7087
7088 refresh: function() {
7089 //See #8237 & #8828
7090 var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" );
7091
7092 if ( isDisabled !== this.options.disabled ) {
7093 this._setOption( "disabled", isDisabled );
7094 }
7095 if ( this.type === "radio" ) {
7096 radioGroup( this.element[0] ).each(function() {
7097 if ( $( this ).is( ":checked" ) ) {
7098 $( this ).button( "widget" )
7099 .addClass( "ui-state-active" )
7100 .attr( "aria-pressed", "true" );
7101 } else {
7102 $( this ).button( "widget" )
7103 .removeClass( "ui-state-active" )
7104 .attr( "aria-pressed", "false" );
7105 }
7106 });
7107 } else if ( this.type === "checkbox" ) {
7108 if ( this.element.is( ":checked" ) ) {
7109 this.buttonElement
7110 .addClass( "ui-state-active" )
7111 .attr( "aria-pressed", "true" );
7112 } else {
7113 this.buttonElement
7114 .removeClass( "ui-state-active" )
7115 .attr( "aria-pressed", "false" );
7116 }
7117 }
7118 },
7119
7120 _resetButton: function() {
7121 if ( this.type === "input" ) {
7122 if ( this.options.label ) {
7123 this.element.val( this.options.label );
7124 }
7125 return;
7126 }
7127 var buttonElement = this.buttonElement.removeClass( typeClasses ),
7128 buttonText = $( "<span></span>", this.document[0] )
7129 .addClass( "ui-button-text" )
7130 .html( this.options.label )
7131 .appendTo( buttonElement.empty() )
7132 .text(),
7133 icons = this.options.icons,
7134 multipleIcons = icons.primary && icons.secondary,
7135 buttonClasses = [];
7136
7137 if ( icons.primary || icons.secondary ) {
7138 if ( this.options.text ) {
7139 buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
7140 }
7141
7142 if ( icons.primary ) {
7143 buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
7144 }
7145
7146 if ( icons.secondary ) {
7147 buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
7148 }
7149
7150 if ( !this.options.text ) {
7151 buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );
7152
7153 if ( !this.hasTitle ) {
7154 buttonElement.attr( "title", $.trim( buttonText ) );
7155 }
7156 }
7157 } else {
7158 buttonClasses.push( "ui-button-text-only" );
7159 }
7160 buttonElement.addClass( buttonClasses.join( " " ) );
7161 }
7162});
7163
7164$.widget( "ui.buttonset", {
7165 version: "1.9.2",
7166 options: {
7167 items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(button)"
7168 },
7169
7170 _create: function() {
7171 this.element.addClass( "ui-buttonset" );
7172 },
7173
7174 _init: function() {
7175 this.refresh();
7176 },
7177
7178 _setOption: function( key, value ) {
7179 if ( key === "disabled" ) {
7180 this.buttons.button( "option", key, value );
7181 }
7182
7183 this._super( key, value );
7184 },
7185
7186 refresh: function() {
7187 var rtl = this.element.css( "direction" ) === "rtl";
7188
7189 this.buttons = this.element.find( this.options.items )
7190 .filter( ":ui-button" )
7191 .button( "refresh" )
7192 .end()
7193 .not( ":ui-button" )
7194 .button()
7195 .end()
7196 .map(function() {
7197 return $( this ).button( "widget" )[ 0 ];
7198 })
7199 .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
7200 .filter( ":first" )
7201 .addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
7202 .end()
7203 .filter( ":last" )
7204 .addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
7205 .end()
7206 .end();
7207 },
7208
7209 _destroy: function() {
7210 this.element.removeClass( "ui-buttonset" );
7211 this.buttons
7212 .map(function() {
7213 return $( this ).button( "widget" )[ 0 ];
7214 })
7215 .removeClass( "ui-corner-left ui-corner-right" )
7216 .end()
7217 .button( "destroy" );
7218 }
7219});
7220
7221}( jQuery ) );
7222
7223(function( $, undefined ) {
7224
7225$.extend($.ui, { datepicker: { version: "1.9.2" } });
7226
7227var PROP_NAME = 'datepicker';
7228var dpuuid = new Date().getTime();
7229var instActive;
7230
7231/* Date picker manager.
7232 Use the singleton instance of this class, $.datepicker, to interact with the date picker.
7233 Settings for (groups of) date pickers are maintained in an instance object,
7234 allowing multiple different settings on the same page. */
7235
7236function Datepicker() {
7237 this.debug = false; // Change this to true to start debugging
7238 this._curInst = null; // The current instance in use
7239 this._keyEvent = false; // If the last event was a key event
7240 this._disabledInputs = []; // List of date picker inputs that have been disabled
7241 this._datepickerShowing = false; // True if the popup picker is showing , false if not
7242 this._inDialog = false; // True if showing within a "dialog", false if not
7243 this._mainDivId = 'ui-datepicker-div'; // The ID of the main datepicker division
7244 this._inlineClass = 'ui-datepicker-inline'; // The name of the inline marker class
7245 this._appendClass = 'ui-datepicker-append'; // The name of the append marker class
7246 this._triggerClass = 'ui-datepicker-trigger'; // The name of the trigger marker class
7247 this._dialogClass = 'ui-datepicker-dialog'; // The name of the dialog marker class
7248 this._disableClass = 'ui-datepicker-disabled'; // The name of the disabled covering marker class
7249 this._unselectableClass = 'ui-datepicker-unselectable'; // The name of the unselectable cell marker class
7250 this._currentClass = 'ui-datepicker-current-day'; // The name of the current day marker class
7251 this._dayOverClass = 'ui-datepicker-days-cell-over'; // The name of the day hover marker class
7252 this.regional = []; // Available regional settings, indexed by language code
7253 this.regional[''] = { // Default regional settings
7254 closeText: 'Done', // Display text for close link
7255 prevText: 'Prev', // Display text for previous month link
7256 nextText: 'Next', // Display text for next month link
7257 currentText: 'Today', // Display text for current month link
7258 monthNames: ['January','February','March','April','May','June',
7259 'July','August','September','October','November','December'], // Names of months for drop-down and formatting
7260 monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting
7261 dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting
7262 dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting
7263 dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday
7264 weekHeader: 'Wk', // Column header for week of the year
7265 dateFormat: 'mm/dd/yy', // See format options on parseDate
7266 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
7267 isRTL: false, // True if right-to-left language, false if left-to-right
7268 showMonthAfterYear: false, // True if the year select precedes month, false for month then year
7269 yearSuffix: '' // Additional text to append to the year in the month headers
7270 };
7271 this._defaults = { // Global defaults for all the date picker instances
7272 showOn: 'focus', // 'focus' for popup on focus,
7273 // 'button' for trigger button, or 'both' for either
7274 showAnim: 'fadeIn', // Name of jQuery animation for popup
7275 showOptions: {}, // Options for enhanced animations
7276 defaultDate: null, // Used when field is blank: actual date,
7277 // +/-number for offset from today, null for today
7278 appendText: '', // Display text following the input box, e.g. showing the format
7279 buttonText: '...', // Text for trigger button
7280 buttonImage: '', // URL for trigger button image
7281 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
7282 hideIfNoPrevNext: false, // True to hide next/previous month links
7283 // if not applicable, false to just disable them
7284 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
7285 gotoCurrent: false, // True if today link goes back to current selection instead
7286 changeMonth: false, // True if month can be selected directly, false if only prev/next
7287 changeYear: false, // True if year can be selected directly, false if only prev/next
7288 yearRange: 'c-10:c+10', // Range of years to display in drop-down,
7289 // either relative to today's year (-nn:+nn), relative to currently displayed year
7290 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
7291 showOtherMonths: false, // True to show dates in other months, false to leave blank
7292 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
7293 showWeek: false, // True to show week of the year, false to not show it
7294 calculateWeek: this.iso8601Week, // How to calculate the week of the year,
7295 // takes a Date and returns the number of the week for it
7296 shortYearCutoff: '+10', // Short year values < this are in the current century,
7297 // > this are in the previous century,
7298 // string value starting with '+' for current year + value
7299 minDate: null, // The earliest selectable date, or null for no limit
7300 maxDate: null, // The latest selectable date, or null for no limit
7301 duration: 'fast', // Duration of display/closure
7302 beforeShowDay: null, // Function that takes a date and returns an array with
7303 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '',
7304 // [2] = cell title (optional), e.g. $.datepicker.noWeekends
7305 beforeShow: null, // Function that takes an input field and
7306 // returns a set of custom settings for the date picker
7307 onSelect: null, // Define a callback function when a date is selected
7308 onChangeMonthYear: null, // Define a callback function when the month or year is changed
7309 onClose: null, // Define a callback function when the datepicker is closed
7310 numberOfMonths: 1, // Number of months to show at a time
7311 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
7312 stepMonths: 1, // Number of months to step back/forward
7313 stepBigMonths: 12, // Number of months to step back/forward for the big links
7314 altField: '', // Selector for an alternate field to store selected dates into
7315 altFormat: '', // The date format to use for the alternate field
7316 constrainInput: true, // The input is constrained by the current date format
7317 showButtonPanel: false, // True to show button panel, false to not show it
7318 autoSize: false, // True to size the input for the date format, false to leave as is
7319 disabled: false // The initial disabled state
7320 };
7321 $.extend(this._defaults, this.regional['']);
7322 this.dpDiv = bindHover($('<div id="' + this._mainDivId + '" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'));
7323}
7324
7325$.extend(Datepicker.prototype, {
7326 /* Class name added to elements to indicate already configured with a date picker. */
7327 markerClassName: 'hasDatepicker',
7328
7329 //Keep track of the maximum number of rows displayed (see #7043)
7330 maxRows: 4,
7331
7332 /* Debug logging (if enabled). */
7333 log: function () {
7334 if (this.debug)
7335 console.log.apply('', arguments);
7336 },
7337
7338 // TODO rename to "widget" when switching to widget factory
7339 _widgetDatepicker: function() {
7340 return this.dpDiv;
7341 },
7342
7343 /* Override the default settings for all instances of the date picker.
7344 @param settings object - the new settings to use as defaults (anonymous object)
7345 @return the manager object */
7346 setDefaults: function(settings) {
7347 extendRemove(this._defaults, settings || {});
7348 return this;
7349 },
7350
7351 /* Attach the date picker to a jQuery selection.
7352 @param target element - the target input field or division or span
7353 @param settings object - the new settings to use for this date picker instance (anonymous) */
7354 _attachDatepicker: function(target, settings) {
7355 // check for settings on the control itself - in namespace 'date:'
7356 var inlineSettings = null;
7357 for (var attrName in this._defaults) {
7358 var attrValue = target.getAttribute('date:' + attrName);
7359 if (attrValue) {
7360 inlineSettings = inlineSettings || {};
7361 try {
7362 inlineSettings[attrName] = eval(attrValue);
7363 } catch (err) {
7364 inlineSettings[attrName] = attrValue;
7365 }
7366 }
7367 }
7368 var nodeName = target.nodeName.toLowerCase();
7369 var inline = (nodeName == 'div' || nodeName == 'span');
7370 if (!target.id) {
7371 this.uuid += 1;
7372 target.id = 'dp' + this.uuid;
7373 }
7374 var inst = this._newInst($(target), inline);
7375 inst.settings = $.extend({}, settings || {}, inlineSettings || {});
7376 if (nodeName == 'input') {
7377 this._connectDatepicker(target, inst);
7378 } else if (inline) {
7379 this._inlineDatepicker(target, inst);
7380 }
7381 },
7382
7383 /* Create a new instance object. */
7384 _newInst: function(target, inline) {
7385 var id = target[0].id.replace(/([^A-Za-z0-9_-])/g, '\\\\$1'); // escape jQuery meta chars
7386 return {id: id, input: target, // associated target
7387 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
7388 drawMonth: 0, drawYear: 0, // month being drawn
7389 inline: inline, // is datepicker inline or not
7390 dpDiv: (!inline ? this.dpDiv : // presentation div
7391 bindHover($('<div class="' + this._inlineClass + ' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')))};
7392 },
7393
7394 /* Attach the date picker to an input field. */
7395 _connectDatepicker: function(target, inst) {
7396 var input = $(target);
7397 inst.append = $([]);
7398 inst.trigger = $([]);
7399 if (input.hasClass(this.markerClassName))
7400 return;
7401 this._attachments(input, inst);
7402 input.addClass(this.markerClassName).keydown(this._doKeyDown).
7403 keypress(this._doKeyPress).keyup(this._doKeyUp).
7404 bind("setData.datepicker", function(event, key, value) {
7405 inst.settings[key] = value;
7406 }).bind("getData.datepicker", function(event, key) {
7407 return this._get(inst, key);
7408 });
7409 this._autoSize(inst);
7410 $.data(target, PROP_NAME, inst);
7411 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
7412 if( inst.settings.disabled ) {
7413 this._disableDatepicker( target );
7414 }
7415 },
7416
7417 /* Make attachments based on settings. */
7418 _attachments: function(input, inst) {
7419 var appendText = this._get(inst, 'appendText');
7420 var isRTL = this._get(inst, 'isRTL');
7421 if (inst.append)
7422 inst.append.remove();
7423 if (appendText) {
7424 inst.append = $('<span class="' + this._appendClass + '">' + appendText + '</span>');
7425 input[isRTL ? 'before' : 'after'](inst.append);
7426 }
7427 input.unbind('focus', this._showDatepicker);
7428 if (inst.trigger)
7429 inst.trigger.remove();
7430 var showOn = this._get(inst, 'showOn');
7431 if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field
7432 input.focus(this._showDatepicker);
7433 if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked
7434 var buttonText = this._get(inst, 'buttonText');
7435 var buttonImage = this._get(inst, 'buttonImage');
7436 inst.trigger = $(this._get(inst, 'buttonImageOnly') ?
7437 $('<img/>').addClass(this._triggerClass).
7438 attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
7439 $('<button type="button"></button>').addClass(this._triggerClass).
7440 html(buttonImage == '' ? buttonText : $('<img/>').attr(
7441 { src:buttonImage, alt:buttonText, title:buttonText })));
7442 input[isRTL ? 'before' : 'after'](inst.trigger);
7443 inst.trigger.click(function() {
7444 if ($.datepicker._datepickerShowing && $.datepicker._lastInput == input[0])
7445 $.datepicker._hideDatepicker();
7446 else if ($.datepicker._datepickerShowing && $.datepicker._lastInput != input[0]) {
7447 $.datepicker._hideDatepicker();
7448 $.datepicker._showDatepicker(input[0]);
7449 } else
7450 $.datepicker._showDatepicker(input[0]);
7451 return false;
7452 });
7453 }
7454 },
7455
7456 /* Apply the maximum length for the date format. */
7457 _autoSize: function(inst) {
7458 if (this._get(inst, 'autoSize') && !inst.inline) {
7459 var date = new Date(2009, 12 - 1, 20); // Ensure double digits
7460 var dateFormat = this._get(inst, 'dateFormat');
7461 if (dateFormat.match(/[DM]/)) {
7462 var findMax = function(names) {
7463 var max = 0;
7464 var maxI = 0;
7465 for (var i = 0; i < names.length; i++) {
7466 if (names[i].length > max) {
7467 max = names[i].length;
7468 maxI = i;
7469 }
7470 }
7471 return maxI;
7472 };
7473 date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
7474 'monthNames' : 'monthNamesShort'))));
7475 date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
7476 'dayNames' : 'dayNamesShort'))) + 20 - date.getDay());
7477 }
7478 inst.input.attr('size', this._formatDate(inst, date).length);
7479 }
7480 },
7481
7482 /* Attach an inline date picker to a div. */
7483 _inlineDatepicker: function(target, inst) {
7484 var divSpan = $(target);
7485 if (divSpan.hasClass(this.markerClassName))
7486 return;
7487 divSpan.addClass(this.markerClassName).append(inst.dpDiv).
7488 bind("setData.datepicker", function(event, key, value){
7489 inst.settings[key] = value;
7490 }).bind("getData.datepicker", function(event, key){
7491 return this._get(inst, key);
7492 });
7493 $.data(target, PROP_NAME, inst);
7494 this._setDate(inst, this._getDefaultDate(inst), true);
7495 this._updateDatepicker(inst);
7496 this._updateAlternate(inst);
7497 //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
7498 if( inst.settings.disabled ) {
7499 this._disableDatepicker( target );
7500 }
7501 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
7502 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
7503 inst.dpDiv.css( "display", "block" );
7504 },
7505
7506 /* Pop-up the date picker in a "dialog" box.
7507 @param input element - ignored
7508 @param date string or Date - the initial date to display
7509 @param onSelect function - the function to call when a date is selected
7510 @param settings object - update the dialog date picker instance's settings (anonymous object)
7511 @param pos int[2] - coordinates for the dialog's position within the screen or
7512 event - with x/y coordinates or
7513 leave empty for default (screen centre)
7514 @return the manager object */
7515 _dialogDatepicker: function(input, date, onSelect, settings, pos) {
7516 var inst = this._dialogInst; // internal instance
7517 if (!inst) {
7518 this.uuid += 1;
7519 var id = 'dp' + this.uuid;
7520 this._dialogInput = $('<input type="text" id="' + id +
7521 '" style="position: absolute; top: -100px; width: 0px;"/>');
7522 this._dialogInput.keydown(this._doKeyDown);
7523 $('body').append(this._dialogInput);
7524 inst = this._dialogInst = this._newInst(this._dialogInput, false);
7525 inst.settings = {};
7526 $.data(this._dialogInput[0], PROP_NAME, inst);
7527 }
7528 extendRemove(inst.settings, settings || {});
7529 date = (date && date.constructor == Date ? this._formatDate(inst, date) : date);
7530 this._dialogInput.val(date);
7531
7532 this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
7533 if (!this._pos) {
7534 var browserWidth = document.documentElement.clientWidth;
7535 var browserHeight = document.documentElement.clientHeight;
7536 var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
7537 var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
7538 this._pos = // should use actual width/height below
7539 [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
7540 }
7541
7542 // move input on screen for focus, but hidden behind dialog
7543 this._dialogInput.css('left', (this._pos[0] + 20) + 'px').css('top', this._pos[1] + 'px');
7544 inst.settings.onSelect = onSelect;
7545 this._inDialog = true;
7546 this.dpDiv.addClass(this._dialogClass);
7547 this._showDatepicker(this._dialogInput[0]);
7548 if ($.blockUI)
7549 $.blockUI(this.dpDiv);
7550 $.data(this._dialogInput[0], PROP_NAME, inst);
7551 return this;
7552 },
7553
7554 /* Detach a datepicker from its control.
7555 @param target element - the target input field or division or span */
7556 _destroyDatepicker: function(target) {
7557 var $target = $(target);
7558 var inst = $.data(target, PROP_NAME);
7559 if (!$target.hasClass(this.markerClassName)) {
7560 return;
7561 }
7562 var nodeName = target.nodeName.toLowerCase();
7563 $.removeData(target, PROP_NAME);
7564 if (nodeName == 'input') {
7565 inst.append.remove();
7566 inst.trigger.remove();
7567 $target.removeClass(this.markerClassName).
7568 unbind('focus', this._showDatepicker).
7569 unbind('keydown', this._doKeyDown).
7570 unbind('keypress', this._doKeyPress).
7571 unbind('keyup', this._doKeyUp);
7572 } else if (nodeName == 'div' || nodeName == 'span')
7573 $target.removeClass(this.markerClassName).empty();
7574 },
7575
7576 /* Enable the date picker to a jQuery selection.
7577 @param target element - the target input field or division or span */
7578 _enableDatepicker: function(target) {
7579 var $target = $(target);
7580 var inst = $.data(target, PROP_NAME);
7581 if (!$target.hasClass(this.markerClassName)) {
7582 return;
7583 }
7584 var nodeName = target.nodeName.toLowerCase();
7585 if (nodeName == 'input') {
7586 target.disabled = false;
7587 inst.trigger.filter('button').
7588 each(function() { this.disabled = false; }).end().
7589 filter('img').css({opacity: '1.0', cursor: ''});
7590 }
7591 else if (nodeName == 'div' || nodeName == 'span') {
7592 var inline = $target.children('.' + this._inlineClass);
7593 inline.children().removeClass('ui-state-disabled');
7594 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
7595 prop("disabled", false);
7596 }
7597 this._disabledInputs = $.map(this._disabledInputs,
7598 function(value) { return (value == target ? null : value); }); // delete entry
7599 },
7600
7601 /* Disable the date picker to a jQuery selection.
7602 @param target element - the target input field or division or span */
7603 _disableDatepicker: function(target) {
7604 var $target = $(target);
7605 var inst = $.data(target, PROP_NAME);
7606 if (!$target.hasClass(this.markerClassName)) {
7607 return;
7608 }
7609 var nodeName = target.nodeName.toLowerCase();
7610 if (nodeName == 'input') {
7611 target.disabled = true;
7612 inst.trigger.filter('button').
7613 each(function() { this.disabled = true; }).end().
7614 filter('img').css({opacity: '0.5', cursor: 'default'});
7615 }
7616 else if (nodeName == 'div' || nodeName == 'span') {
7617 var inline = $target.children('.' + this._inlineClass);
7618 inline.children().addClass('ui-state-disabled');
7619 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
7620 prop("disabled", true);
7621 }
7622 this._disabledInputs = $.map(this._disabledInputs,
7623 function(value) { return (value == target ? null : value); }); // delete entry
7624 this._disabledInputs[this._disabledInputs.length] = target;
7625 },
7626
7627 /* Is the first field in a jQuery collection disabled as a datepicker?
7628 @param target element - the target input field or division or span
7629 @return boolean - true if disabled, false if enabled */
7630 _isDisabledDatepicker: function(target) {
7631 if (!target) {
7632 return false;
7633 }
7634 for (var i = 0; i < this._disabledInputs.length; i++) {
7635 if (this._disabledInputs[i] == target)
7636 return true;
7637 }
7638 return false;
7639 },
7640
7641 /* Retrieve the instance data for the target control.
7642 @param target element - the target input field or division or span
7643 @return object - the associated instance data
7644 @throws error if a jQuery problem getting data */
7645 _getInst: function(target) {
7646 try {
7647 return $.data(target, PROP_NAME);
7648 }
7649 catch (err) {
7650 throw 'Missing instance data for this datepicker';
7651 }
7652 },
7653
7654 /* Update or retrieve the settings for a date picker attached to an input field or division.
7655 @param target element - the target input field or division or span
7656 @param name object - the new settings to update or
7657 string - the name of the setting to change or retrieve,
7658 when retrieving also 'all' for all instance settings or
7659 'defaults' for all global defaults
7660 @param value any - the new value for the setting
7661 (omit if above is an object or to retrieve a value) */
7662 _optionDatepicker: function(target, name, value) {
7663 var inst = this._getInst(target);
7664 if (arguments.length == 2 && typeof name == 'string') {
7665 return (name == 'defaults' ? $.extend({}, $.datepicker._defaults) :
7666 (inst ? (name == 'all' ? $.extend({}, inst.settings) :
7667 this._get(inst, name)) : null));
7668 }
7669 var settings = name || {};
7670 if (typeof name == 'string') {
7671 settings = {};
7672 settings[name] = value;
7673 }
7674 if (inst) {
7675 if (this._curInst == inst) {
7676 this._hideDatepicker();
7677 }
7678 var date = this._getDateDatepicker(target, true);
7679 var minDate = this._getMinMaxDate(inst, 'min');
7680 var maxDate = this._getMinMaxDate(inst, 'max');
7681 extendRemove(inst.settings, settings);
7682 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
7683 if (minDate !== null && settings['dateFormat'] !== undefined && settings['minDate'] === undefined)
7684 inst.settings.minDate = this._formatDate(inst, minDate);
7685 if (maxDate !== null && settings['dateFormat'] !== undefined && settings['maxDate'] === undefined)
7686 inst.settings.maxDate = this._formatDate(inst, maxDate);
7687 this._attachments($(target), inst);
7688 this._autoSize(inst);
7689 this._setDate(inst, date);
7690 this._updateAlternate(inst);
7691 this._updateDatepicker(inst);
7692 }
7693 },
7694
7695 // change method deprecated
7696 _changeDatepicker: function(target, name, value) {
7697 this._optionDatepicker(target, name, value);
7698 },
7699
7700 /* Redraw the date picker attached to an input field or division.
7701 @param target element - the target input field or division or span */
7702 _refreshDatepicker: function(target) {
7703 var inst = this._getInst(target);
7704 if (inst) {
7705 this._updateDatepicker(inst);
7706 }
7707 },
7708
7709 /* Set the dates for a jQuery selection.
7710 @param target element - the target input field or division or span
7711 @param date Date - the new date */
7712 _setDateDatepicker: function(target, date) {
7713 var inst = this._getInst(target);
7714 if (inst) {
7715 this._setDate(inst, date);
7716 this._updateDatepicker(inst);
7717 this._updateAlternate(inst);
7718 }
7719 },
7720
7721 /* Get the date(s) for the first entry in a jQuery selection.
7722 @param target element - the target input field or division or span
7723 @param noDefault boolean - true if no default date is to be used
7724 @return Date - the current date */
7725 _getDateDatepicker: function(target, noDefault) {
7726 var inst = this._getInst(target);
7727 if (inst && !inst.inline)
7728 this._setDateFromField(inst, noDefault);
7729 return (inst ? this._getDate(inst) : null);
7730 },
7731
7732 /* Handle keystrokes. */
7733 _doKeyDown: function(event) {
7734 var inst = $.datepicker._getInst(event.target);
7735 var handled = true;
7736 var isRTL = inst.dpDiv.is('.ui-datepicker-rtl');
7737 inst._keyEvent = true;
7738 if ($.datepicker._datepickerShowing)
7739 switch (event.keyCode) {
7740 case 9: $.datepicker._hideDatepicker();
7741 handled = false;
7742 break; // hide on tab out
7743 case 13: var sel = $('td.' + $.datepicker._dayOverClass + ':not(.' +
7744 $.datepicker._currentClass + ')', inst.dpDiv);
7745 if (sel[0])
7746 $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
7747 var onSelect = $.datepicker._get(inst, 'onSelect');
7748 if (onSelect) {
7749 var dateStr = $.datepicker._formatDate(inst);
7750
7751 // trigger custom callback
7752 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
7753 }
7754 else
7755 $.datepicker._hideDatepicker();
7756 return false; // don't submit the form
7757 break; // select the value on enter
7758 case 27: $.datepicker._hideDatepicker();
7759 break; // hide on escape
7760 case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
7761 -$.datepicker._get(inst, 'stepBigMonths') :
7762 -$.datepicker._get(inst, 'stepMonths')), 'M');
7763 break; // previous month/year on page up/+ ctrl
7764 case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
7765 +$.datepicker._get(inst, 'stepBigMonths') :
7766 +$.datepicker._get(inst, 'stepMonths')), 'M');
7767 break; // next month/year on page down/+ ctrl
7768 case 35: if (event.ctrlKey || event.metaKey) $.datepicker._clearDate(event.target);
7769 handled = event.ctrlKey || event.metaKey;
7770 break; // clear on ctrl or command +end
7771 case 36: if (event.ctrlKey || event.metaKey) $.datepicker._gotoToday(event.target);
7772 handled = event.ctrlKey || event.metaKey;
7773 break; // current on ctrl or command +home
7774 case 37: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), 'D');
7775 handled = event.ctrlKey || event.metaKey;
7776 // -1 day on ctrl or command +left
7777 if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ?
7778 -$.datepicker._get(inst, 'stepBigMonths') :
7779 -$.datepicker._get(inst, 'stepMonths')), 'M');
7780 // next month/year on alt +left on Mac
7781 break;
7782 case 38: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, -7, 'D');
7783 handled = event.ctrlKey || event.metaKey;
7784 break; // -1 week on ctrl or command +up
7785 case 39: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), 'D');
7786 handled = event.ctrlKey || event.metaKey;
7787 // +1 day on ctrl or command +right
7788 if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ?
7789 +$.datepicker._get(inst, 'stepBigMonths') :
7790 +$.datepicker._get(inst, 'stepMonths')), 'M');
7791 // next month/year on alt +right
7792 break;
7793 case 40: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, +7, 'D');
7794 handled = event.ctrlKey || event.metaKey;
7795 break; // +1 week on ctrl or command +down
7796 default: handled = false;
7797 }
7798 else if (event.keyCode == 36 && event.ctrlKey) // display the date picker on ctrl+home
7799 $.datepicker._showDatepicker(this);
7800 else {
7801 handled = false;
7802 }
7803 if (handled) {
7804 event.preventDefault();
7805 event.stopPropagation();
7806 }
7807 },
7808
7809 /* Filter entered characters - based on date format. */
7810 _doKeyPress: function(event) {
7811 var inst = $.datepicker._getInst(event.target);
7812 if ($.datepicker._get(inst, 'constrainInput')) {
7813 var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat'));
7814 var chr = String.fromCharCode(event.charCode == undefined ? event.keyCode : event.charCode);
7815 return event.ctrlKey || event.metaKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1);
7816 }
7817 },
7818
7819 /* Synchronise manual entry and field/alternate field. */
7820 _doKeyUp: function(event) {
7821 var inst = $.datepicker._getInst(event.target);
7822 if (inst.input.val() != inst.lastVal) {
7823 try {
7824 var date = $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'),
7825 (inst.input ? inst.input.val() : null),
7826 $.datepicker._getFormatConfig(inst));
7827 if (date) { // only if valid
7828 $.datepicker._setDateFromField(inst);
7829 $.datepicker._updateAlternate(inst);
7830 $.datepicker._updateDatepicker(inst);
7831 }
7832 }
7833 catch (err) {
7834 $.datepicker.log(err);
7835 }
7836 }
7837 return true;
7838 },
7839
7840 /* Pop-up the date picker for a given input field.
7841 If false returned from beforeShow event handler do not show.
7842 @param input element - the input field attached to the date picker or
7843 event - if triggered by focus */
7844 _showDatepicker: function(input) {
7845 input = input.target || input;
7846 if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger
7847 input = $('input', input.parentNode)[0];
7848 if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here
7849 return;
7850 var inst = $.datepicker._getInst(input);
7851 if ($.datepicker._curInst && $.datepicker._curInst != inst) {
7852 $.datepicker._curInst.dpDiv.stop(true, true);
7853 if ( inst && $.datepicker._datepickerShowing ) {
7854 $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
7855 }
7856 }
7857 var beforeShow = $.datepicker._get(inst, 'beforeShow');
7858 var beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
7859 if(beforeShowSettings === false){
7860 //false
7861 return;
7862 }
7863 extendRemove(inst.settings, beforeShowSettings);
7864 inst.lastVal = null;
7865 $.datepicker._lastInput = input;
7866 $.datepicker._setDateFromField(inst);
7867 if ($.datepicker._inDialog) // hide cursor
7868 input.value = '';
7869 if (!$.datepicker._pos) { // position below input
7870 $.datepicker._pos = $.datepicker._findPos(input);
7871 $.datepicker._pos[1] += input.offsetHeight; // add the height
7872 }
7873 var isFixed = false;
7874 $(input).parents().each(function() {
7875 isFixed |= $(this).css('position') == 'fixed';
7876 return !isFixed;
7877 });
7878 var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
7879 $.datepicker._pos = null;
7880 //to avoid flashes on Firefox
7881 inst.dpDiv.empty();
7882 // determine sizing offscreen
7883 inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'});
7884 $.datepicker._updateDatepicker(inst);
7885 // fix width for dynamic number of date pickers
7886 // and adjust position before showing
7887 offset = $.datepicker._checkOffset(inst, offset, isFixed);
7888 inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
7889 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none',
7890 left: offset.left + 'px', top: offset.top + 'px'});
7891 if (!inst.inline) {
7892 var showAnim = $.datepicker._get(inst, 'showAnim');
7893 var duration = $.datepicker._get(inst, 'duration');
7894 var postProcess = function() {
7895 var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only
7896 if( !! cover.length ){
7897 var borders = $.datepicker._getBorders(inst.dpDiv);
7898 cover.css({left: -borders[0], top: -borders[1],
7899 width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()});
7900 }
7901 };
7902 inst.dpDiv.zIndex($(input).zIndex()+1);
7903 $.datepicker._datepickerShowing = true;
7904
7905 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
7906 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) )
7907 inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);
7908 else
7909 inst.dpDiv[showAnim || 'show']((showAnim ? duration : null), postProcess);
7910 if (!showAnim || !duration)
7911 postProcess();
7912 if (inst.input.is(':visible') && !inst.input.is(':disabled'))
7913 inst.input.focus();
7914 $.datepicker._curInst = inst;
7915 }
7916 },
7917
7918 /* Generate the date picker content. */
7919 _updateDatepicker: function(inst) {
7920 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
7921 var borders = $.datepicker._getBorders(inst.dpDiv);
7922 instActive = inst; // for delegate hover events
7923 inst.dpDiv.empty().append(this._generateHTML(inst));
7924 this._attachHandlers(inst);
7925 var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only
7926 if( !!cover.length ){ //avoid call to outerXXXX() when not in IE6
7927 cover.css({left: -borders[0], top: -borders[1], width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()})
7928 }
7929 inst.dpDiv.find('.' + this._dayOverClass + ' a').mouseover();
7930 var numMonths = this._getNumberOfMonths(inst);
7931 var cols = numMonths[1];
7932 var width = 17;
7933 inst.dpDiv.removeClass('ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4').width('');
7934 if (cols > 1)
7935 inst.dpDiv.addClass('ui-datepicker-multi-' + cols).css('width', (width * cols) + 'em');
7936 inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') +
7937 'Class']('ui-datepicker-multi');
7938 inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') +
7939 'Class']('ui-datepicker-rtl');
7940 if (inst == $.datepicker._curInst && $.datepicker._datepickerShowing && inst.input &&
7941 // #6694 - don't focus the input if it's already focused
7942 // this breaks the change event in IE
7943 inst.input.is(':visible') && !inst.input.is(':disabled') && inst.input[0] != document.activeElement)
7944 inst.input.focus();
7945 // deffered render of the years select (to avoid flashes on Firefox)
7946 if( inst.yearshtml ){
7947 var origyearshtml = inst.yearshtml;
7948 setTimeout(function(){
7949 //assure that inst.yearshtml didn't change.
7950 if( origyearshtml === inst.yearshtml && inst.yearshtml ){
7951 inst.dpDiv.find('select.ui-datepicker-year:first').replaceWith(inst.yearshtml);
7952 }
7953 origyearshtml = inst.yearshtml = null;
7954 }, 0);
7955 }
7956 },
7957
7958 /* Retrieve the size of left and top borders for an element.
7959 @param elem (jQuery object) the element of interest
7960 @return (number[2]) the left and top borders */
7961 _getBorders: function(elem) {
7962 var convert = function(value) {
7963 return {thin: 1, medium: 2, thick: 3}[value] || value;
7964 };
7965 return [parseFloat(convert(elem.css('border-left-width'))),
7966 parseFloat(convert(elem.css('border-top-width')))];
7967 },
7968
7969 /* Check positioning to remain on screen. */
7970 _checkOffset: function(inst, offset, isFixed) {
7971 var dpWidth = inst.dpDiv.outerWidth();
7972 var dpHeight = inst.dpDiv.outerHeight();
7973 var inputWidth = inst.input ? inst.input.outerWidth() : 0;
7974 var inputHeight = inst.input ? inst.input.outerHeight() : 0;
7975 var viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft());
7976 var viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
7977
7978 offset.left -= (this._get(inst, 'isRTL') ? (dpWidth - inputWidth) : 0);
7979 offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0;
7980 offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
7981
7982 // now check if datepicker is showing outside window viewport - move to a better place if so.
7983 offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
7984 Math.abs(offset.left + dpWidth - viewWidth) : 0);
7985 offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
7986 Math.abs(dpHeight + inputHeight) : 0);
7987
7988 return offset;
7989 },
7990
7991 /* Find an object's position on the screen. */
7992 _findPos: function(obj) {
7993 var inst = this._getInst(obj);
7994 var isRTL = this._get(inst, 'isRTL');
7995 while (obj && (obj.type == 'hidden' || obj.nodeType != 1 || $.expr.filters.hidden(obj))) {
7996 obj = obj[isRTL ? 'previousSibling' : 'nextSibling'];
7997 }
7998 var position = $(obj).offset();
7999 return [position.left, position.top];
8000 },
8001
8002 /* Hide the date picker from view.
8003 @param input element - the input field attached to the date picker */
8004 _hideDatepicker: function(input) {
8005 var inst = this._curInst;
8006 if (!inst || (input && inst != $.data(input, PROP_NAME)))
8007 return;
8008 if (this._datepickerShowing) {
8009 var showAnim = this._get(inst, 'showAnim');
8010 var duration = this._get(inst, 'duration');
8011 var postProcess = function() {
8012 $.datepicker._tidyDialog(inst);
8013 };
8014
8015 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
8016 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) )
8017 inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);
8018 else
8019 inst.dpDiv[(showAnim == 'slideDown' ? 'slideUp' :
8020 (showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))]((showAnim ? duration : null), postProcess);
8021 if (!showAnim)
8022 postProcess();
8023 this._datepickerShowing = false;
8024 var onClose = this._get(inst, 'onClose');
8025 if (onClose)
8026 onClose.apply((inst.input ? inst.input[0] : null),
8027 [(inst.input ? inst.input.val() : ''), inst]);
8028 this._lastInput = null;
8029 if (this._inDialog) {
8030 this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' });
8031 if ($.blockUI) {
8032 $.unblockUI();
8033 $('body').append(this.dpDiv);
8034 }
8035 }
8036 this._inDialog = false;
8037 }
8038 },
8039
8040 /* Tidy up after a dialog display. */
8041 _tidyDialog: function(inst) {
8042 inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker-calendar');
8043 },
8044
8045 /* Close date picker if clicked elsewhere. */
8046 _checkExternalClick: function(event) {
8047 if (!$.datepicker._curInst)
8048 return;
8049
8050 var $target = $(event.target),
8051 inst = $.datepicker._getInst($target[0]);
8052
8053 if ( ( ( $target[0].id != $.datepicker._mainDivId &&
8054 $target.parents('#' + $.datepicker._mainDivId).length == 0 &&
8055 !$target.hasClass($.datepicker.markerClassName) &&
8056 !$target.closest("." + $.datepicker._triggerClass).length &&
8057 $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
8058 ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst != inst ) )
8059 $.datepicker._hideDatepicker();
8060 },
8061
8062 /* Adjust one of the date sub-fields. */
8063 _adjustDate: function(id, offset, period) {
8064 var target = $(id);
8065 var inst = this._getInst(target[0]);
8066 if (this._isDisabledDatepicker(target[0])) {
8067 return;
8068 }
8069 this._adjustInstDate(inst, offset +
8070 (period == 'M' ? this._get(inst, 'showCurrentAtPos') : 0), // undo positioning
8071 period);
8072 this._updateDatepicker(inst);
8073 },
8074
8075 /* Action for current link. */
8076 _gotoToday: function(id) {
8077 var target = $(id);
8078 var inst = this._getInst(target[0]);
8079 if (this._get(inst, 'gotoCurrent') && inst.currentDay) {
8080 inst.selectedDay = inst.currentDay;
8081 inst.drawMonth = inst.selectedMonth = inst.currentMonth;
8082 inst.drawYear = inst.selectedYear = inst.currentYear;
8083 }
8084 else {
8085 var date = new Date();
8086 inst.selectedDay = date.getDate();
8087 inst.drawMonth = inst.selectedMonth = date.getMonth();
8088 inst.drawYear = inst.selectedYear = date.getFullYear();
8089 }
8090 this._notifyChange(inst);
8091 this._adjustDate(target);
8092 },
8093
8094 /* Action for selecting a new month/year. */
8095 _selectMonthYear: function(id, select, period) {
8096 var target = $(id);
8097 var inst = this._getInst(target[0]);
8098 inst['selected' + (period == 'M' ? 'Month' : 'Year')] =
8099 inst['draw' + (period == 'M' ? 'Month' : 'Year')] =
8100 parseInt(select.options[select.selectedIndex].value,10);
8101 this._notifyChange(inst);
8102 this._adjustDate(target);
8103 },
8104
8105 /* Action for selecting a day. */
8106 _selectDay: function(id, month, year, td) {
8107 var target = $(id);
8108 if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
8109 return;
8110 }
8111 var inst = this._getInst(target[0]);
8112 inst.selectedDay = inst.currentDay = $('a', td).html();
8113 inst.selectedMonth = inst.currentMonth = month;
8114 inst.selectedYear = inst.currentYear = year;
8115 this._selectDate(id, this._formatDate(inst,
8116 inst.currentDay, inst.currentMonth, inst.currentYear));
8117 },
8118
8119 /* Erase the input field and hide the date picker. */
8120 _clearDate: function(id) {
8121 var target = $(id);
8122 var inst = this._getInst(target[0]);
8123 this._selectDate(target, '');
8124 },
8125
8126 /* Update the input field with the selected date. */
8127 _selectDate: function(id, dateStr) {
8128 var target = $(id);
8129 var inst = this._getInst(target[0]);
8130 dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
8131 if (inst.input)
8132 inst.input.val(dateStr);
8133 this._updateAlternate(inst);
8134 var onSelect = this._get(inst, 'onSelect');
8135 if (onSelect)
8136 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
8137 else if (inst.input)
8138 inst.input.trigger('change'); // fire the change event
8139 if (inst.inline)
8140 this._updateDatepicker(inst);
8141 else {
8142 this._hideDatepicker();
8143 this._lastInput = inst.input[0];
8144 if (typeof(inst.input[0]) != 'object')
8145 inst.input.focus(); // restore focus
8146 this._lastInput = null;
8147 }
8148 },
8149
8150 /* Update any alternate field to synchronise with the main field. */
8151 _updateAlternate: function(inst) {
8152 var altField = this._get(inst, 'altField');
8153 if (altField) { // update alternate field too
8154 var altFormat = this._get(inst, 'altFormat') || this._get(inst, 'dateFormat');
8155 var date = this._getDate(inst);
8156 var dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
8157 $(altField).each(function() { $(this).val(dateStr); });
8158 }
8159 },
8160
8161 /* Set as beforeShowDay function to prevent selection of weekends.
8162 @param date Date - the date to customise
8163 @return [boolean, string] - is this date selectable?, what is its CSS class? */
8164 noWeekends: function(date) {
8165 var day = date.getDay();
8166 return [(day > 0 && day < 6), ''];
8167 },
8168
8169 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
8170 @param date Date - the date to get the week for
8171 @return number - the number of the week within the year that contains this date */
8172 iso8601Week: function(date) {
8173 var checkDate = new Date(date.getTime());
8174 // Find Thursday of this week starting on Monday
8175 checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
8176 var time = checkDate.getTime();
8177 checkDate.setMonth(0); // Compare with Jan 1
8178 checkDate.setDate(1);
8179 return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
8180 },
8181
8182 /* Parse a string value into a date object.
8183 See formatDate below for the possible formats.
8184
8185 @param format string - the expected format of the date
8186 @param value string - the date in the above format
8187 @param settings Object - attributes include:
8188 shortYearCutoff number - the cutoff year for determining the century (optional)
8189 dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
8190 dayNames string[7] - names of the days from Sunday (optional)
8191 monthNamesShort string[12] - abbreviated names of the months (optional)
8192 monthNames string[12] - names of the months (optional)
8193 @return Date - the extracted date value or null if value is blank */
8194 parseDate: function (format, value, settings) {
8195 if (format == null || value == null)
8196 throw 'Invalid arguments';
8197 value = (typeof value == 'object' ? value.toString() : value + '');
8198 if (value == '')
8199 return null;
8200 var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff;
8201 shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff :
8202 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
8203 var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
8204 var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
8205 var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
8206 var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
8207 var year = -1;
8208 var month = -1;
8209 var day = -1;
8210 var doy = -1;
8211 var literal = false;
8212 // Check whether a format character is doubled
8213 var lookAhead = function(match) {
8214 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
8215 if (matches)
8216 iFormat++;
8217 return matches;
8218 };
8219 // Extract a number from the string value
8220 var getNumber = function(match) {
8221 var isDoubled = lookAhead(match);
8222 var size = (match == '@' ? 14 : (match == '!' ? 20 :
8223 (match == 'y' && isDoubled ? 4 : (match == 'o' ? 3 : 2))));
8224 var digits = new RegExp('^\\d{1,' + size + '}');
8225 var num = value.substring(iValue).match(digits);
8226 if (!num)
8227 throw 'Missing number at position ' + iValue;
8228 iValue += num[0].length;
8229 return parseInt(num[0], 10);
8230 };
8231 // Extract a name from the string value and convert to an index
8232 var getName = function(match, shortNames, longNames) {
8233 var names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
8234 return [ [k, v] ];
8235 }).sort(function (a, b) {
8236 return -(a[1].length - b[1].length);
8237 });
8238 var index = -1;
8239 $.each(names, function (i, pair) {
8240 var name = pair[1];
8241 if (value.substr(iValue, name.length).toLowerCase() == name.toLowerCase()) {
8242 index = pair[0];
8243 iValue += name.length;
8244 return false;
8245 }
8246 });
8247 if (index != -1)
8248 return index + 1;
8249 else
8250 throw 'Unknown name at position ' + iValue;
8251 };
8252 // Confirm that a literal character matches the string value
8253 var checkLiteral = function() {
8254 if (value.charAt(iValue) != format.charAt(iFormat))
8255 throw 'Unexpected literal at position ' + iValue;
8256 iValue++;
8257 };
8258 var iValue = 0;
8259 for (var iFormat = 0; iFormat < format.length; iFormat++) {
8260 if (literal)
8261 if (format.charAt(iFormat) == "'" && !lookAhead("'"))
8262 literal = false;
8263 else
8264 checkLiteral();
8265 else
8266 switch (format.charAt(iFormat)) {
8267 case 'd':
8268 day = getNumber('d');
8269 break;
8270 case 'D':
8271 getName('D', dayNamesShort, dayNames);
8272 break;
8273 case 'o':
8274 doy = getNumber('o');
8275 break;
8276 case 'm':
8277 month = getNumber('m');
8278 break;
8279 case 'M':
8280 month = getName('M', monthNamesShort, monthNames);
8281 break;
8282 case 'y':
8283 year = getNumber('y');
8284 break;
8285 case '@':
8286 var date = new Date(getNumber('@'));
8287 year = date.getFullYear();
8288 month = date.getMonth() + 1;
8289 day = date.getDate();
8290 break;
8291 case '!':
8292 var date = new Date((getNumber('!') - this._ticksTo1970) / 10000);
8293 year = date.getFullYear();
8294 month = date.getMonth() + 1;
8295 day = date.getDate();
8296 break;
8297 case "'":
8298 if (lookAhead("'"))
8299 checkLiteral();
8300 else
8301 literal = true;
8302 break;
8303 default:
8304 checkLiteral();
8305 }
8306 }
8307 if (iValue < value.length){
8308 var extra = value.substr(iValue);
8309 if (!/^\s+/.test(extra)) {
8310 throw "Extra/unparsed characters found in date: " + extra;
8311 }
8312 }
8313 if (year == -1)
8314 year = new Date().getFullYear();
8315 else if (year < 100)
8316 year += new Date().getFullYear() - new Date().getFullYear() % 100 +
8317 (year <= shortYearCutoff ? 0 : -100);
8318 if (doy > -1) {
8319 month = 1;
8320 day = doy;
8321 do {
8322 var dim = this._getDaysInMonth(year, month - 1);
8323 if (day <= dim)
8324 break;
8325 month++;
8326 day -= dim;
8327 } while (true);
8328 }
8329 var date = this._daylightSavingAdjust(new Date(year, month - 1, day));
8330 if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day)
8331 throw 'Invalid date'; // E.g. 31/02/00
8332 return date;
8333 },
8334
8335 /* Standard date formats. */
8336 ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601)
8337 COOKIE: 'D, dd M yy',
8338 ISO_8601: 'yy-mm-dd',
8339 RFC_822: 'D, d M y',
8340 RFC_850: 'DD, dd-M-y',
8341 RFC_1036: 'D, d M y',
8342 RFC_1123: 'D, d M yy',
8343 RFC_2822: 'D, d M yy',
8344 RSS: 'D, d M y', // RFC 822
8345 TICKS: '!',
8346 TIMESTAMP: '@',
8347 W3C: 'yy-mm-dd', // ISO 8601
8348
8349 _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
8350 Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
8351
8352 /* Format a date object into a string value.
8353 The format can be combinations of the following:
8354 d - day of month (no leading zero)
8355 dd - day of month (two digit)
8356 o - day of year (no leading zeros)
8357 oo - day of year (three digit)
8358 D - day name short
8359 DD - day name long
8360 m - month of year (no leading zero)
8361 mm - month of year (two digit)
8362 M - month name short
8363 MM - month name long
8364 y - year (two digit)
8365 yy - year (four digit)
8366 @ - Unix timestamp (ms since 01/01/1970)
8367 ! - Windows ticks (100ns since 01/01/0001)
8368 '...' - literal text
8369 '' - single quote
8370
8371 @param format string - the desired format of the date
8372 @param date Date - the date value to format
8373 @param settings Object - attributes include:
8374 dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
8375 dayNames string[7] - names of the days from Sunday (optional)
8376 monthNamesShort string[12] - abbreviated names of the months (optional)
8377 monthNames string[12] - names of the months (optional)
8378 @return string - the date in the above format */
8379 formatDate: function (format, date, settings) {
8380 if (!date)
8381 return '';
8382 var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
8383 var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
8384 var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
8385 var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
8386 // Check whether a format character is doubled
8387 var lookAhead = function(match) {
8388 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
8389 if (matches)
8390 iFormat++;
8391 return matches;
8392 };
8393 // Format a number, with leading zero if necessary
8394 var formatNumber = function(match, value, len) {
8395 var num = '' + value;
8396 if (lookAhead(match))
8397 while (num.length < len)
8398 num = '0' + num;
8399 return num;
8400 };
8401 // Format a name, short or long as requested
8402 var formatName = function(match, value, shortNames, longNames) {
8403 return (lookAhead(match) ? longNames[value] : shortNames[value]);
8404 };
8405 var output = '';
8406 var literal = false;
8407 if (date)
8408 for (var iFormat = 0; iFormat < format.length; iFormat++) {
8409 if (literal)
8410 if (format.charAt(iFormat) == "'" && !lookAhead("'"))
8411 literal = false;
8412 else
8413 output += format.charAt(iFormat);
8414 else
8415 switch (format.charAt(iFormat)) {
8416 case 'd':
8417 output += formatNumber('d', date.getDate(), 2);
8418 break;
8419 case 'D':
8420 output += formatName('D', date.getDay(), dayNamesShort, dayNames);
8421 break;
8422 case 'o':
8423 output += formatNumber('o',
8424 Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
8425 break;
8426 case 'm':
8427 output += formatNumber('m', date.getMonth() + 1, 2);
8428 break;
8429 case 'M':
8430 output += formatName('M', date.getMonth(), monthNamesShort, monthNames);
8431 break;
8432 case 'y':
8433 output += (lookAhead('y') ? date.getFullYear() :
8434 (date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100);
8435 break;
8436 case '@':
8437 output += date.getTime();
8438 break;
8439 case '!':
8440 output += date.getTime() * 10000 + this._ticksTo1970;
8441 break;
8442 case "'":
8443 if (lookAhead("'"))
8444 output += "'";
8445 else
8446 literal = true;
8447 break;
8448 default:
8449 output += format.charAt(iFormat);
8450 }
8451 }
8452 return output;
8453 },
8454
8455 /* Extract all possible characters from the date format. */
8456 _possibleChars: function (format) {
8457 var chars = '';
8458 var literal = false;
8459 // Check whether a format character is doubled
8460 var lookAhead = function(match) {
8461 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
8462 if (matches)
8463 iFormat++;
8464 return matches;
8465 };
8466 for (var iFormat = 0; iFormat < format.length; iFormat++)
8467 if (literal)
8468 if (format.charAt(iFormat) == "'" && !lookAhead("'"))
8469 literal = false;
8470 else
8471 chars += format.charAt(iFormat);
8472 else
8473 switch (format.charAt(iFormat)) {
8474 case 'd': case 'm': case 'y': case '@':
8475 chars += '0123456789';
8476 break;
8477 case 'D': case 'M':
8478 return null; // Accept anything
8479 case "'":
8480 if (lookAhead("'"))
8481 chars += "'";
8482 else
8483 literal = true;
8484 break;
8485 default:
8486 chars += format.charAt(iFormat);
8487 }
8488 return chars;
8489 },
8490
8491 /* Get a setting value, defaulting if necessary. */
8492 _get: function(inst, name) {
8493 return inst.settings[name] !== undefined ?
8494 inst.settings[name] : this._defaults[name];
8495 },
8496
8497 /* Parse existing date and initialise date picker. */
8498 _setDateFromField: function(inst, noDefault) {
8499 if (inst.input.val() == inst.lastVal) {
8500 return;
8501 }
8502 var dateFormat = this._get(inst, 'dateFormat');
8503 var dates = inst.lastVal = inst.input ? inst.input.val() : null;
8504 var date, defaultDate;
8505 date = defaultDate = this._getDefaultDate(inst);
8506 var settings = this._getFormatConfig(inst);
8507 try {
8508 date = this.parseDate(dateFormat, dates, settings) || defaultDate;
8509 } catch (event) {
8510 this.log(event);
8511 dates = (noDefault ? '' : dates);
8512 }
8513 inst.selectedDay = date.getDate();
8514 inst.drawMonth = inst.selectedMonth = date.getMonth();
8515 inst.drawYear = inst.selectedYear = date.getFullYear();
8516 inst.currentDay = (dates ? date.getDate() : 0);
8517 inst.currentMonth = (dates ? date.getMonth() : 0);
8518 inst.currentYear = (dates ? date.getFullYear() : 0);
8519 this._adjustInstDate(inst);
8520 },
8521
8522 /* Retrieve the default date shown on opening. */
8523 _getDefaultDate: function(inst) {
8524 return this._restrictMinMax(inst,
8525 this._determineDate(inst, this._get(inst, 'defaultDate'), new Date()));
8526 },
8527
8528 /* A date may be specified as an exact value or a relative one. */
8529 _determineDate: function(inst, date, defaultDate) {
8530 var offsetNumeric = function(offset) {
8531 var date = new Date();
8532 date.setDate(date.getDate() + offset);
8533 return date;
8534 };
8535 var offsetString = function(offset) {
8536 try {
8537 return $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'),
8538 offset, $.datepicker._getFormatConfig(inst));
8539 }
8540 catch (e) {
8541 // Ignore
8542 }
8543 var date = (offset.toLowerCase().match(/^c/) ?
8544 $.datepicker._getDate(inst) : null) || new Date();
8545 var year = date.getFullYear();
8546 var month = date.getMonth();
8547 var day = date.getDate();
8548 var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g;
8549 var matches = pattern.exec(offset);
8550 while (matches) {
8551 switch (matches[2] || 'd') {
8552 case 'd' : case 'D' :
8553 day += parseInt(matches[1],10); break;
8554 case 'w' : case 'W' :
8555 day += parseInt(matches[1],10) * 7; break;
8556 case 'm' : case 'M' :
8557 month += parseInt(matches[1],10);
8558 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
8559 break;
8560 case 'y': case 'Y' :
8561 year += parseInt(matches[1],10);
8562 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
8563 break;
8564 }
8565 matches = pattern.exec(offset);
8566 }
8567 return new Date(year, month, day);
8568 };
8569 var newDate = (date == null || date === '' ? defaultDate : (typeof date == 'string' ? offsetString(date) :
8570 (typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
8571 newDate = (newDate && newDate.toString() == 'Invalid Date' ? defaultDate : newDate);
8572 if (newDate) {
8573 newDate.setHours(0);
8574 newDate.setMinutes(0);
8575 newDate.setSeconds(0);
8576 newDate.setMilliseconds(0);
8577 }
8578 return this._daylightSavingAdjust(newDate);
8579 },
8580
8581 /* Handle switch to/from daylight saving.
8582 Hours may be non-zero on daylight saving cut-over:
8583 > 12 when midnight changeover, but then cannot generate
8584 midnight datetime, so jump to 1AM, otherwise reset.
8585 @param date (Date) the date to check
8586 @return (Date) the corrected date */
8587 _daylightSavingAdjust: function(date) {
8588 if (!date) return null;
8589 date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
8590 return date;
8591 },
8592
8593 /* Set the date(s) directly. */
8594 _setDate: function(inst, date, noChange) {
8595 var clear = !date;
8596 var origMonth = inst.selectedMonth;
8597 var origYear = inst.selectedYear;
8598 var newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
8599 inst.selectedDay = inst.currentDay = newDate.getDate();
8600 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
8601 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
8602 if ((origMonth != inst.selectedMonth || origYear != inst.selectedYear) && !noChange)
8603 this._notifyChange(inst);
8604 this._adjustInstDate(inst);
8605 if (inst.input) {
8606 inst.input.val(clear ? '' : this._formatDate(inst));
8607 }
8608 },
8609
8610 /* Retrieve the date(s) directly. */
8611 _getDate: function(inst) {
8612 var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null :
8613 this._daylightSavingAdjust(new Date(
8614 inst.currentYear, inst.currentMonth, inst.currentDay)));
8615 return startDate;
8616 },
8617
8618 /* Attach the onxxx handlers. These are declared statically so
8619 * they work with static code transformers like Caja.
8620 */
8621 _attachHandlers: function(inst) {
8622 var stepMonths = this._get(inst, 'stepMonths');
8623 var id = '#' + inst.id.replace( /\\\\/g, "\\" );
8624 inst.dpDiv.find('[data-handler]').map(function () {
8625 var handler = {
8626 prev: function () {
8627 window['DP_jQuery_' + dpuuid].datepicker._adjustDate(id, -stepMonths, 'M');
8628 },
8629 next: function () {
8630 window['DP_jQuery_' + dpuuid].datepicker._adjustDate(id, +stepMonths, 'M');
8631 },
8632 hide: function () {
8633 window['DP_jQuery_' + dpuuid].datepicker._hideDatepicker();
8634 },
8635 today: function () {
8636 window['DP_jQuery_' + dpuuid].datepicker._gotoToday(id);
8637 },
8638 selectDay: function () {
8639 window['DP_jQuery_' + dpuuid].datepicker._selectDay(id, +this.getAttribute('data-month'), +this.getAttribute('data-year'), this);
8640 return false;
8641 },
8642 selectMonth: function () {
8643 window['DP_jQuery_' + dpuuid].datepicker._selectMonthYear(id, this, 'M');
8644 return false;
8645 },
8646 selectYear: function () {
8647 window['DP_jQuery_' + dpuuid].datepicker._selectMonthYear(id, this, 'Y');
8648 return false;
8649 }
8650 };
8651 $(this).bind(this.getAttribute('data-event'), handler[this.getAttribute('data-handler')]);
8652 });
8653 },
8654
8655 /* Generate the HTML for the current state of the date picker. */
8656 _generateHTML: function(inst) {
8657 var today = new Date();
8658 today = this._daylightSavingAdjust(
8659 new Date(today.getFullYear(), today.getMonth(), today.getDate())); // clear time
8660 var isRTL = this._get(inst, 'isRTL');
8661 var showButtonPanel = this._get(inst, 'showButtonPanel');
8662 var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext');
8663 var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat');
8664 var numMonths = this._getNumberOfMonths(inst);
8665 var showCurrentAtPos = this._get(inst, 'showCurrentAtPos');
8666 var stepMonths = this._get(inst, 'stepMonths');
8667 var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1);
8668 var currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
8669 new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
8670 var minDate = this._getMinMaxDate(inst, 'min');
8671 var maxDate = this._getMinMaxDate(inst, 'max');
8672 var drawMonth = inst.drawMonth - showCurrentAtPos;
8673 var drawYear = inst.drawYear;
8674 if (drawMonth < 0) {
8675 drawMonth += 12;
8676 drawYear--;
8677 }
8678 if (maxDate) {
8679 var maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
8680 maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
8681 maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
8682 while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
8683 drawMonth--;
8684 if (drawMonth < 0) {
8685 drawMonth = 11;
8686 drawYear--;
8687 }
8688 }
8689 }
8690 inst.drawMonth = drawMonth;
8691 inst.drawYear = drawYear;
8692 var prevText = this._get(inst, 'prevText');
8693 prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
8694 this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
8695 this._getFormatConfig(inst)));
8696 var prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
8697 '<a class="ui-datepicker-prev ui-corner-all" data-handler="prev" data-event="click"' +
8698 ' title="' + prevText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'e' : 'w') + '">' + prevText + '</span></a>' :
8699 (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>'));
8700 var nextText = this._get(inst, 'nextText');
8701 nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
8702 this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
8703 this._getFormatConfig(inst)));
8704 var next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
8705 '<a class="ui-datepicker-next ui-corner-all" data-handler="next" data-event="click"' +
8706 ' title="' + nextText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'w' : 'e') + '">' + nextText + '</span></a>' :
8707 (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>'));
8708 var currentText = this._get(inst, 'currentText');
8709 var gotoDate = (this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today);
8710 currentText = (!navigationAsDateFormat ? currentText :
8711 this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
8712 var 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">' +
8713 this._get(inst, 'closeText') + '</button>' : '');
8714 var buttonPanel = (showButtonPanel) ? '<div class="ui-datepicker-buttonpane ui-widget-content">' + (isRTL ? controls : '') +
8715 (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"' +
8716 '>' + currentText + '</button>' : '') + (isRTL ? '' : controls) + '</div>' : '';
8717 var firstDay = parseInt(this._get(inst, 'firstDay'),10);
8718 firstDay = (isNaN(firstDay) ? 0 : firstDay);
8719 var showWeek = this._get(inst, 'showWeek');
8720 var dayNames = this._get(inst, 'dayNames');
8721 var dayNamesShort = this._get(inst, 'dayNamesShort');
8722 var dayNamesMin = this._get(inst, 'dayNamesMin');
8723 var monthNames = this._get(inst, 'monthNames');
8724 var monthNamesShort = this._get(inst, 'monthNamesShort');
8725 var beforeShowDay = this._get(inst, 'beforeShowDay');
8726 var showOtherMonths = this._get(inst, 'showOtherMonths');
8727 var selectOtherMonths = this._get(inst, 'selectOtherMonths');
8728 var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week;
8729 var defaultDate = this._getDefaultDate(inst);
8730 var html = '';
8731 for (var row = 0; row < numMonths[0]; row++) {
8732 var group = '';
8733 this.maxRows = 4;
8734 for (var col = 0; col < numMonths[1]; col++) {
8735 var selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
8736 var cornerClass = ' ui-corner-all';
8737 var calender = '';
8738 if (isMultiMonth) {
8739 calender += '<div class="ui-datepicker-group';
8740 if (numMonths[1] > 1)
8741 switch (col) {
8742 case 0: calender += ' ui-datepicker-group-first';
8743 cornerClass = ' ui-corner-' + (isRTL ? 'right' : 'left'); break;
8744 case numMonths[1]-1: calender += ' ui-datepicker-group-last';
8745 cornerClass = ' ui-corner-' + (isRTL ? 'left' : 'right'); break;
8746 default: calender += ' ui-datepicker-group-middle'; cornerClass = ''; break;
8747 }
8748 calender += '">';
8749 }
8750 calender += '<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix' + cornerClass + '">' +
8751 (/all|left/.test(cornerClass) && row == 0 ? (isRTL ? next : prev) : '') +
8752 (/all|right/.test(cornerClass) && row == 0 ? (isRTL ? prev : next) : '') +
8753 this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
8754 row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
8755 '</div><table class="ui-datepicker-calendar"><thead>' +
8756 '<tr>';
8757 var thead = (showWeek ? '<th class="ui-datepicker-week-col">' + this._get(inst, 'weekHeader') + '</th>' : '');
8758 for (var dow = 0; dow < 7; dow++) { // days of the week
8759 var day = (dow + firstDay) % 7;
8760 thead += '<th' + ((dow + firstDay + 6) % 7 >= 5 ? ' class="ui-datepicker-week-end"' : '') + '>' +
8761 '<span title="' + dayNames[day] + '">' + dayNamesMin[day] + '</span></th>';
8762 }
8763 calender += thead + '</tr></thead><tbody>';
8764 var daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
8765 if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth)
8766 inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
8767 var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
8768 var curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
8769 var numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
8770 this.maxRows = numRows;
8771 var printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
8772 for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows
8773 calender += '<tr>';
8774 var tbody = (!showWeek ? '' : '<td class="ui-datepicker-week-col">' +
8775 this._get(inst, 'calculateWeek')(printDate) + '</td>');
8776 for (var dow = 0; dow < 7; dow++) { // create date picker days
8777 var daySettings = (beforeShowDay ?
8778 beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']);
8779 var otherMonth = (printDate.getMonth() != drawMonth);
8780 var unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
8781 (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
8782 tbody += '<td class="' +
8783 ((dow + firstDay + 6) % 7 >= 5 ? ' ui-datepicker-week-end' : '') + // highlight weekends
8784 (otherMonth ? ' ui-datepicker-other-month' : '') + // highlight days from other months
8785 ((printDate.getTime() == selectedDate.getTime() && drawMonth == inst.selectedMonth && inst._keyEvent) || // user pressed key
8786 (defaultDate.getTime() == printDate.getTime() && defaultDate.getTime() == selectedDate.getTime()) ?
8787 // or defaultDate is current printedDate and defaultDate is selectedDate
8788 ' ' + this._dayOverClass : '') + // highlight selected day
8789 (unselectable ? ' ' + this._unselectableClass + ' ui-state-disabled': '') + // highlight unselectable days
8790 (otherMonth && !showOtherMonths ? '' : ' ' + daySettings[1] + // highlight custom dates
8791 (printDate.getTime() == currentDate.getTime() ? ' ' + this._currentClass : '') + // highlight selected day
8792 (printDate.getTime() == today.getTime() ? ' ui-datepicker-today' : '')) + '"' + // highlight today (if different)
8793 ((!otherMonth || showOtherMonths) && daySettings[2] ? ' title="' + daySettings[2] + '"' : '') + // cell title
8794 (unselectable ? '' : ' data-handler="selectDay" data-event="click" data-month="' + printDate.getMonth() + '" data-year="' + printDate.getFullYear() + '"') + '>' + // actions
8795 (otherMonth && !showOtherMonths ? '&#xa0;' : // display for other months
8796 (unselectable ? '<span class="ui-state-default">' + printDate.getDate() + '</span>' : '<a class="ui-state-default' +
8797 (printDate.getTime() == today.getTime() ? ' ui-state-highlight' : '') +
8798 (printDate.getTime() == currentDate.getTime() ? ' ui-state-active' : '') + // highlight selected day
8799 (otherMonth ? ' ui-priority-secondary' : '') + // distinguish dates from other months
8800 '" href="#">' + printDate.getDate() + '</a>')) + '</td>'; // display selectable date
8801 printDate.setDate(printDate.getDate() + 1);
8802 printDate = this._daylightSavingAdjust(printDate);
8803 }
8804 calender += tbody + '</tr>';
8805 }
8806 drawMonth++;
8807 if (drawMonth > 11) {
8808 drawMonth = 0;
8809 drawYear++;
8810 }
8811 calender += '</tbody></table>' + (isMultiMonth ? '</div>' +
8812 ((numMonths[0] > 0 && col == numMonths[1]-1) ? '<div class="ui-datepicker-row-break"></div>' : '') : '');
8813 group += calender;
8814 }
8815 html += group;
8816 }
8817 html += buttonPanel + ($.ui.ie6 && !inst.inline ?
8818 '<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>' : '');
8819 inst._keyEvent = false;
8820 return html;
8821 },
8822
8823 /* Generate the month and year header. */
8824 _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
8825 secondary, monthNames, monthNamesShort) {
8826 var changeMonth = this._get(inst, 'changeMonth');
8827 var changeYear = this._get(inst, 'changeYear');
8828 var showMonthAfterYear = this._get(inst, 'showMonthAfterYear');
8829 var html = '<div class="ui-datepicker-title">';
8830 var monthHtml = '';
8831 // month selection
8832 if (secondary || !changeMonth)
8833 monthHtml += '<span class="ui-datepicker-month">' + monthNames[drawMonth] + '</span>';
8834 else {
8835 var inMinYear = (minDate && minDate.getFullYear() == drawYear);
8836 var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear);
8837 monthHtml += '<select class="ui-datepicker-month" data-handler="selectMonth" data-event="change">';
8838 for (var month = 0; month < 12; month++) {
8839 if ((!inMinYear || month >= minDate.getMonth()) &&
8840 (!inMaxYear || month <= maxDate.getMonth()))
8841 monthHtml += '<option value="' + month + '"' +
8842 (month == drawMonth ? ' selected="selected"' : '') +
8843 '>' + monthNamesShort[month] + '</option>';
8844 }
8845 monthHtml += '</select>';
8846 }
8847 if (!showMonthAfterYear)
8848 html += monthHtml + (secondary || !(changeMonth && changeYear) ? '&#xa0;' : '');
8849 // year selection
8850 if ( !inst.yearshtml ) {
8851 inst.yearshtml = '';
8852 if (secondary || !changeYear)
8853 html += '<span class="ui-datepicker-year">' + drawYear + '</span>';
8854 else {
8855 // determine range of years to display
8856 var years = this._get(inst, 'yearRange').split(':');
8857 var thisYear = new Date().getFullYear();
8858 var determineYear = function(value) {
8859 var year = (value.match(/c[+-].*/) ? drawYear + parseInt(value.substring(1), 10) :
8860 (value.match(/[+-].*/) ? thisYear + parseInt(value, 10) :
8861 parseInt(value, 10)));
8862 return (isNaN(year) ? thisYear : year);
8863 };
8864 var year = determineYear(years[0]);
8865 var endYear = Math.max(year, determineYear(years[1] || ''));
8866 year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
8867 endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
8868 inst.yearshtml += '<select class="ui-datepicker-year" data-handler="selectYear" data-event="change">';
8869 for (; year <= endYear; year++) {
8870 inst.yearshtml += '<option value="' + year + '"' +
8871 (year == drawYear ? ' selected="selected"' : '') +
8872 '>' + year + '</option>';
8873 }
8874 inst.yearshtml += '</select>';
8875
8876 html += inst.yearshtml;
8877 inst.yearshtml = null;
8878 }
8879 }
8880 html += this._get(inst, 'yearSuffix');
8881 if (showMonthAfterYear)
8882 html += (secondary || !(changeMonth && changeYear) ? '&#xa0;' : '') + monthHtml;
8883 html += '</div>'; // Close datepicker_header
8884 return html;
8885 },
8886
8887 /* Adjust one of the date sub-fields. */
8888 _adjustInstDate: function(inst, offset, period) {
8889 var year = inst.drawYear + (period == 'Y' ? offset : 0);
8890 var month = inst.drawMonth + (period == 'M' ? offset : 0);
8891 var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) +
8892 (period == 'D' ? offset : 0);
8893 var date = this._restrictMinMax(inst,
8894 this._daylightSavingAdjust(new Date(year, month, day)));
8895 inst.selectedDay = date.getDate();
8896 inst.drawMonth = inst.selectedMonth = date.getMonth();
8897 inst.drawYear = inst.selectedYear = date.getFullYear();
8898 if (period == 'M' || period == 'Y')
8899 this._notifyChange(inst);
8900 },
8901
8902 /* Ensure a date is within any min/max bounds. */
8903 _restrictMinMax: function(inst, date) {
8904 var minDate = this._getMinMaxDate(inst, 'min');
8905 var maxDate = this._getMinMaxDate(inst, 'max');
8906 var newDate = (minDate && date < minDate ? minDate : date);
8907 newDate = (maxDate && newDate > maxDate ? maxDate : newDate);
8908 return newDate;
8909 },
8910
8911 /* Notify change of month/year. */
8912 _notifyChange: function(inst) {
8913 var onChange = this._get(inst, 'onChangeMonthYear');
8914 if (onChange)
8915 onChange.apply((inst.input ? inst.input[0] : null),
8916 [inst.selectedYear, inst.selectedMonth + 1, inst]);
8917 },
8918
8919 /* Determine the number of months to show. */
8920 _getNumberOfMonths: function(inst) {
8921 var numMonths = this._get(inst, 'numberOfMonths');
8922 return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths));
8923 },
8924
8925 /* Determine the current maximum date - ensure no time components are set. */
8926 _getMinMaxDate: function(inst, minMax) {
8927 return this._determineDate(inst, this._get(inst, minMax + 'Date'), null);
8928 },
8929
8930 /* Find the number of days in a given month. */
8931 _getDaysInMonth: function(year, month) {
8932 return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
8933 },
8934
8935 /* Find the day of the week of the first of a month. */
8936 _getFirstDayOfMonth: function(year, month) {
8937 return new Date(year, month, 1).getDay();
8938 },
8939
8940 /* Determines if we should allow a "next/prev" month display change. */
8941 _canAdjustMonth: function(inst, offset, curYear, curMonth) {
8942 var numMonths = this._getNumberOfMonths(inst);
8943 var date = this._daylightSavingAdjust(new Date(curYear,
8944 curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
8945 if (offset < 0)
8946 date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
8947 return this._isInRange(inst, date);
8948 },
8949
8950 /* Is the given date in the accepted range? */
8951 _isInRange: function(inst, date) {
8952 var minDate = this._getMinMaxDate(inst, 'min');
8953 var maxDate = this._getMinMaxDate(inst, 'max');
8954 return ((!minDate || date.getTime() >= minDate.getTime()) &&
8955 (!maxDate || date.getTime() <= maxDate.getTime()));
8956 },
8957
8958 /* Provide the configuration settings for formatting/parsing. */
8959 _getFormatConfig: function(inst) {
8960 var shortYearCutoff = this._get(inst, 'shortYearCutoff');
8961 shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff :
8962 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
8963 return {shortYearCutoff: shortYearCutoff,
8964 dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'),
8965 monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')};
8966 },
8967
8968 /* Format the given date for display. */
8969 _formatDate: function(inst, day, month, year) {
8970 if (!day) {
8971 inst.currentDay = inst.selectedDay;
8972 inst.currentMonth = inst.selectedMonth;
8973 inst.currentYear = inst.selectedYear;
8974 }
8975 var date = (day ? (typeof day == 'object' ? day :
8976 this._daylightSavingAdjust(new Date(year, month, day))) :
8977 this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
8978 return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst));
8979 }
8980});
8981
8982/*
8983 * Bind hover events for datepicker elements.
8984 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
8985 * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
8986 */
8987function bindHover(dpDiv) {
8988 var selector = 'button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a';
8989 return dpDiv.delegate(selector, 'mouseout', function() {
8990 $(this).removeClass('ui-state-hover');
8991 if (this.className.indexOf('ui-datepicker-prev') != -1) $(this).removeClass('ui-datepicker-prev-hover');
8992 if (this.className.indexOf('ui-datepicker-next') != -1) $(this).removeClass('ui-datepicker-next-hover');
8993 })
8994 .delegate(selector, 'mouseover', function(){
8995 if (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) {
8996 $(this).parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover');
8997 $(this).addClass('ui-state-hover');
8998 if (this.className.indexOf('ui-datepicker-prev') != -1) $(this).addClass('ui-datepicker-prev-hover');
8999 if (this.className.indexOf('ui-datepicker-next') != -1) $(this).addClass('ui-datepicker-next-hover');
9000 }
9001 });
9002}
9003
9004/* jQuery extend now ignores nulls! */
9005function extendRemove(target, props) {
9006 $.extend(target, props);
9007 for (var name in props)
9008 if (props[name] == null || props[name] == undefined)
9009 target[name] = props[name];
9010 return target;
9011};
9012
9013/* Invoke the datepicker functionality.
9014 @param options string - a command, optionally followed by additional parameters or
9015 Object - settings for attaching new datepicker functionality
9016 @return jQuery object */
9017$.fn.datepicker = function(options){
9018
9019 /* Verify an empty collection wasn't passed - Fixes #6976 */
9020 if ( !this.length ) {
9021 return this;
9022 }
9023
9024 /* Initialise the date picker. */
9025 if (!$.datepicker.initialized) {
9026 $(document).mousedown($.datepicker._checkExternalClick).
9027 find(document.body).append($.datepicker.dpDiv);
9028 $.datepicker.initialized = true;
9029 }
9030
9031 var otherArgs = Array.prototype.slice.call(arguments, 1);
9032 if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate' || options == 'widget'))
9033 return $.datepicker['_' + options + 'Datepicker'].
9034 apply($.datepicker, [this[0]].concat(otherArgs));
9035 if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string')
9036 return $.datepicker['_' + options + 'Datepicker'].
9037 apply($.datepicker, [this[0]].concat(otherArgs));
9038 return this.each(function() {
9039 typeof options == 'string' ?
9040 $.datepicker['_' + options + 'Datepicker'].
9041 apply($.datepicker, [this].concat(otherArgs)) :
9042 $.datepicker._attachDatepicker(this, options);
9043 });
9044};
9045
9046$.datepicker = new Datepicker(); // singleton instance
9047$.datepicker.initialized = false;
9048$.datepicker.uuid = new Date().getTime();
9049$.datepicker.version = "1.9.2";
9050
9051// Workaround for #4055
9052// Add another global to avoid noConflict issues with inline event handlers
9053window['DP_jQuery_' + dpuuid] = $;
9054
9055})(jQuery);
9056
9057(function( $, undefined ) {
9058
9059var uiDialogClasses = "ui-dialog ui-widget ui-widget-content ui-corner-all ",
9060 sizeRelatedOptions = {
9061 buttons: true,
9062 height: true,
9063 maxHeight: true,
9064 maxWidth: true,
9065 minHeight: true,
9066 minWidth: true,
9067 width: true
9068 },
9069 resizableRelatedOptions = {
9070 maxHeight: true,
9071 maxWidth: true,
9072 minHeight: true,
9073 minWidth: true
9074 };
9075
9076$.widget("ui.dialog", {
9077 version: "1.9.2",
9078 options: {
9079 autoOpen: true,
9080 buttons: {},
9081 closeOnEscape: true,
9082 closeText: "close",
9083 dialogClass: "",
9084 draggable: true,
9085 hide: null,
9086 height: "auto",
9087 maxHeight: false,
9088 maxWidth: false,
9089 minHeight: 150,
9090 minWidth: 150,
9091 modal: false,
9092 position: {
9093 my: "center",
9094 at: "center",
9095 of: window,
9096 collision: "fit",
9097 // ensure that the titlebar is never outside the document
9098 using: function( pos ) {
9099 var topOffset = $( this ).css( pos ).offset().top;
9100 if ( topOffset < 0 ) {
9101 $( this ).css( "top", pos.top - topOffset );
9102 }
9103 }
9104 },
9105 resizable: true,
9106 show: null,
9107 stack: true,
9108 title: "",
9109 width: 300,
9110 zIndex: 1000
9111 },
9112
9113 _create: function() {
9114 this.originalTitle = this.element.attr( "title" );
9115 // #5742 - .attr() might return a DOMElement
9116 if ( typeof this.originalTitle !== "string" ) {
9117 this.originalTitle = "";
9118 }
9119 this.oldPosition = {
9120 parent: this.element.parent(),
9121 index: this.element.parent().children().index( this.element )
9122 };
9123 this.options.title = this.options.title || this.originalTitle;
9124 var that = this,
9125 options = this.options,
9126
9127 title = options.title || "&#160;",
9128 uiDialog,
9129 uiDialogTitlebar,
9130 uiDialogTitlebarClose,
9131 uiDialogTitle,
9132 uiDialogButtonPane;
9133
9134 uiDialog = ( this.uiDialog = $( "<div>" ) )
9135 .addClass( uiDialogClasses + options.dialogClass )
9136 .css({
9137 display: "none",
9138 outline: 0, // TODO: move to stylesheet
9139 zIndex: options.zIndex
9140 })
9141 // setting tabIndex makes the div focusable
9142 .attr( "tabIndex", -1)
9143 .keydown(function( event ) {
9144 if ( options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
9145 event.keyCode === $.ui.keyCode.ESCAPE ) {
9146 that.close( event );
9147 event.preventDefault();
9148 }
9149 })
9150 .mousedown(function( event ) {
9151 that.moveToTop( false, event );
9152 })
9153 .appendTo( "body" );
9154
9155 this.element
9156 .show()
9157 .removeAttr( "title" )
9158 .addClass( "ui-dialog-content ui-widget-content" )
9159 .appendTo( uiDialog );
9160
9161 uiDialogTitlebar = ( this.uiDialogTitlebar = $( "<div>" ) )
9162 .addClass( "ui-dialog-titlebar ui-widget-header " +
9163 "ui-corner-all ui-helper-clearfix" )
9164 .bind( "mousedown", function() {
9165 // Dialog isn't getting focus when dragging (#8063)
9166 uiDialog.focus();
9167 })
9168 .prependTo( uiDialog );
9169
9170 uiDialogTitlebarClose = $( "<a href='#'></a>" )
9171 .addClass( "ui-dialog-titlebar-close ui-corner-all" )
9172 .attr( "role", "button" )
9173 .click(function( event ) {
9174 event.preventDefault();
9175 that.close( event );
9176 })
9177 .appendTo( uiDialogTitlebar );
9178
9179 ( this.uiDialogTitlebarCloseText = $( "<span>" ) )
9180 .addClass( "ui-icon ui-icon-closethick" )
9181 .text( options.closeText )
9182 .appendTo( uiDialogTitlebarClose );
9183
9184 uiDialogTitle = $( "<span>" )
9185 .uniqueId()
9186 .addClass( "ui-dialog-title" )
9187 .html( title )
9188 .prependTo( uiDialogTitlebar );
9189
9190 uiDialogButtonPane = ( this.uiDialogButtonPane = $( "<div>" ) )
9191 .addClass( "ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" );
9192
9193 ( this.uiButtonSet = $( "<div>" ) )
9194 .addClass( "ui-dialog-buttonset" )
9195 .appendTo( uiDialogButtonPane );
9196
9197 uiDialog.attr({
9198 role: "dialog",
9199 "aria-labelledby": uiDialogTitle.attr( "id" )
9200 });
9201
9202 uiDialogTitlebar.find( "*" ).add( uiDialogTitlebar ).disableSelection();
9203 this._hoverable( uiDialogTitlebarClose );
9204 this._focusable( uiDialogTitlebarClose );
9205
9206 if ( options.draggable && $.fn.draggable ) {
9207 this._makeDraggable();
9208 }
9209 if ( options.resizable && $.fn.resizable ) {
9210 this._makeResizable();
9211 }
9212
9213 this._createButtons( options.buttons );
9214 this._isOpen = false;
9215
9216 if ( $.fn.bgiframe ) {
9217 uiDialog.bgiframe();
9218 }
9219
9220 // prevent tabbing out of modal dialogs
9221 this._on( uiDialog, { keydown: function( event ) {
9222 if ( !options.modal || event.keyCode !== $.ui.keyCode.TAB ) {
9223 return;
9224 }
9225
9226 var tabbables = $( ":tabbable", uiDialog ),
9227 first = tabbables.filter( ":first" ),
9228 last = tabbables.filter( ":last" );
9229
9230 if ( event.target === last[0] && !event.shiftKey ) {
9231 first.focus( 1 );
9232 return false;
9233 } else if ( event.target === first[0] && event.shiftKey ) {
9234 last.focus( 1 );
9235 return false;
9236 }
9237 }});
9238 },
9239
9240 _init: function() {
9241 if ( this.options.autoOpen ) {
9242 this.open();
9243 }
9244 },
9245
9246 _destroy: function() {
9247 var next,
9248 oldPosition = this.oldPosition;
9249
9250 if ( this.overlay ) {
9251 this.overlay.destroy();
9252 }
9253 this.uiDialog.hide();
9254 this.element
9255 .removeClass( "ui-dialog-content ui-widget-content" )
9256 .hide()
9257 .appendTo( "body" );
9258 this.uiDialog.remove();
9259
9260 if ( this.originalTitle ) {
9261 this.element.attr( "title", this.originalTitle );
9262 }
9263
9264 next = oldPosition.parent.children().eq( oldPosition.index );
9265 // Don't try to place the dialog next to itself (#8613)
9266 if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
9267 next.before( this.element );
9268 } else {
9269 oldPosition.parent.append( this.element );
9270 }
9271 },
9272
9273 widget: function() {
9274 return this.uiDialog;
9275 },
9276
9277 close: function( event ) {
9278 var that = this,
9279 maxZ, thisZ;
9280
9281 if ( !this._isOpen ) {
9282 return;
9283 }
9284
9285 if ( false === this._trigger( "beforeClose", event ) ) {
9286 return;
9287 }
9288
9289 this._isOpen = false;
9290
9291 if ( this.overlay ) {
9292 this.overlay.destroy();
9293 }
9294
9295 if ( this.options.hide ) {
9296 this._hide( this.uiDialog, this.options.hide, function() {
9297 that._trigger( "close", event );
9298 });
9299 } else {
9300 this.uiDialog.hide();
9301 this._trigger( "close", event );
9302 }
9303
9304 $.ui.dialog.overlay.resize();
9305
9306 // adjust the maxZ to allow other modal dialogs to continue to work (see #4309)
9307 if ( this.options.modal ) {
9308 maxZ = 0;
9309 $( ".ui-dialog" ).each(function() {
9310 if ( this !== that.uiDialog[0] ) {
9311 thisZ = $( this ).css( "z-index" );
9312 if ( !isNaN( thisZ ) ) {
9313 maxZ = Math.max( maxZ, thisZ );
9314 }
9315 }
9316 });
9317 $.ui.dialog.maxZ = maxZ;
9318 }
9319
9320 return this;
9321 },
9322
9323 isOpen: function() {
9324 return this._isOpen;
9325 },
9326
9327 // the force parameter allows us to move modal dialogs to their correct
9328 // position on open
9329 moveToTop: function( force, event ) {
9330 var options = this.options,
9331 saveScroll;
9332
9333 if ( ( options.modal && !force ) ||
9334 ( !options.stack && !options.modal ) ) {
9335 return this._trigger( "focus", event );
9336 }
9337
9338 if ( options.zIndex > $.ui.dialog.maxZ ) {
9339 $.ui.dialog.maxZ = options.zIndex;
9340 }
9341 if ( this.overlay ) {
9342 $.ui.dialog.maxZ += 1;
9343 $.ui.dialog.overlay.maxZ = $.ui.dialog.maxZ;
9344 this.overlay.$el.css( "z-index", $.ui.dialog.overlay.maxZ );
9345 }
9346
9347 // Save and then restore scroll
9348 // Opera 9.5+ resets when parent z-index is changed.
9349 // http://bugs.jqueryui.com/ticket/3193
9350 saveScroll = {
9351 scrollTop: this.element.scrollTop(),
9352 scrollLeft: this.element.scrollLeft()
9353 };
9354 $.ui.dialog.maxZ += 1;
9355 this.uiDialog.css( "z-index", $.ui.dialog.maxZ );
9356 this.element.attr( saveScroll );
9357 this._trigger( "focus", event );
9358
9359 return this;
9360 },
9361
9362 open: function() {
9363 if ( this._isOpen ) {
9364 return;
9365 }
9366
9367 var hasFocus,
9368 options = this.options,
9369 uiDialog = this.uiDialog;
9370
9371 this._size();
9372 this._position( options.position );
9373 uiDialog.show( options.show );
9374 this.overlay = options.modal ? new $.ui.dialog.overlay( this ) : null;
9375 this.moveToTop( true );
9376
9377 // set focus to the first tabbable element in the content area or the first button
9378 // if there are no tabbable elements, set focus on the dialog itself
9379 hasFocus = this.element.find( ":tabbable" );
9380 if ( !hasFocus.length ) {
9381 hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
9382 if ( !hasFocus.length ) {
9383 hasFocus = uiDialog;
9384 }
9385 }
9386 hasFocus.eq( 0 ).focus();
9387
9388 this._isOpen = true;
9389 this._trigger( "open" );
9390
9391 return this;
9392 },
9393
9394 _createButtons: function( buttons ) {
9395 var that = this,
9396 hasButtons = false;
9397
9398 // if we already have a button pane, remove it
9399 this.uiDialogButtonPane.remove();
9400 this.uiButtonSet.empty();
9401
9402 if ( typeof buttons === "object" && buttons !== null ) {
9403 $.each( buttons, function() {
9404 return !(hasButtons = true);
9405 });
9406 }
9407 if ( hasButtons ) {
9408 $.each( buttons, function( name, props ) {
9409 var button, click;
9410 props = $.isFunction( props ) ?
9411 { click: props, text: name } :
9412 props;
9413 // Default to a non-submitting button
9414 props = $.extend( { type: "button" }, props );
9415 // Change the context for the click callback to be the main element
9416 click = props.click;
9417 props.click = function() {
9418 click.apply( that.element[0], arguments );
9419 };
9420 button = $( "<button></button>", props )
9421 .appendTo( that.uiButtonSet );
9422 if ( $.fn.button ) {
9423 button.button();
9424 }
9425 });
9426 this.uiDialog.addClass( "ui-dialog-buttons" );
9427 this.uiDialogButtonPane.appendTo( this.uiDialog );
9428 } else {
9429 this.uiDialog.removeClass( "ui-dialog-buttons" );
9430 }
9431 },
9432
9433 _makeDraggable: function() {
9434 var that = this,
9435 options = this.options;
9436
9437 function filteredUi( ui ) {
9438 return {
9439 position: ui.position,
9440 offset: ui.offset
9441 };
9442 }
9443
9444 this.uiDialog.draggable({
9445 cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
9446 handle: ".ui-dialog-titlebar",
9447 containment: "document",
9448 start: function( event, ui ) {
9449 $( this )
9450 .addClass( "ui-dialog-dragging" );
9451 that._trigger( "dragStart", event, filteredUi( ui ) );
9452 },
9453 drag: function( event, ui ) {
9454 that._trigger( "drag", event, filteredUi( ui ) );
9455 },
9456 stop: function( event, ui ) {
9457 options.position = [
9458 ui.position.left - that.document.scrollLeft(),
9459 ui.position.top - that.document.scrollTop()
9460 ];
9461 $( this )
9462 .removeClass( "ui-dialog-dragging" );
9463 that._trigger( "dragStop", event, filteredUi( ui ) );
9464 $.ui.dialog.overlay.resize();
9465 }
9466 });
9467 },
9468
9469 _makeResizable: function( handles ) {
9470 handles = (handles === undefined ? this.options.resizable : handles);
9471 var that = this,
9472 options = this.options,
9473 // .ui-resizable has position: relative defined in the stylesheet
9474 // but dialogs have to use absolute or fixed positioning
9475 position = this.uiDialog.css( "position" ),
9476 resizeHandles = typeof handles === 'string' ?
9477 handles :
9478 "n,e,s,w,se,sw,ne,nw";
9479
9480 function filteredUi( ui ) {
9481 return {
9482 originalPosition: ui.originalPosition,
9483 originalSize: ui.originalSize,
9484 position: ui.position,
9485 size: ui.size
9486 };
9487 }
9488
9489 this.uiDialog.resizable({
9490 cancel: ".ui-dialog-content",
9491 containment: "document",
9492 alsoResize: this.element,
9493 maxWidth: options.maxWidth,
9494 maxHeight: options.maxHeight,
9495 minWidth: options.minWidth,
9496 minHeight: this._minHeight(),
9497 handles: resizeHandles,
9498 start: function( event, ui ) {
9499 $( this ).addClass( "ui-dialog-resizing" );
9500 that._trigger( "resizeStart", event, filteredUi( ui ) );
9501 },
9502 resize: function( event, ui ) {
9503 that._trigger( "resize", event, filteredUi( ui ) );
9504 },
9505 stop: function( event, ui ) {
9506 $( this ).removeClass( "ui-dialog-resizing" );
9507 options.height = $( this ).height();
9508 options.width = $( this ).width();
9509 that._trigger( "resizeStop", event, filteredUi( ui ) );
9510 $.ui.dialog.overlay.resize();
9511 }
9512 })
9513 .css( "position", position )
9514 .find( ".ui-resizable-se" )
9515 .addClass( "ui-icon ui-icon-grip-diagonal-se" );
9516 },
9517
9518 _minHeight: function() {
9519 var options = this.options;
9520
9521 if ( options.height === "auto" ) {
9522 return options.minHeight;
9523 } else {
9524 return Math.min( options.minHeight, options.height );
9525 }
9526 },
9527
9528 _position: function( position ) {
9529 var myAt = [],
9530 offset = [ 0, 0 ],
9531 isVisible;
9532
9533 if ( position ) {
9534 // deep extending converts arrays to objects in jQuery <= 1.3.2 :-(
9535 // if (typeof position == 'string' || $.isArray(position)) {
9536 // myAt = $.isArray(position) ? position : position.split(' ');
9537
9538 if ( typeof position === "string" || (typeof position === "object" && "0" in position ) ) {
9539 myAt = position.split ? position.split( " " ) : [ position[ 0 ], position[ 1 ] ];
9540 if ( myAt.length === 1 ) {
9541 myAt[ 1 ] = myAt[ 0 ];
9542 }
9543
9544 $.each( [ "left", "top" ], function( i, offsetPosition ) {
9545 if ( +myAt[ i ] === myAt[ i ] ) {
9546 offset[ i ] = myAt[ i ];
9547 myAt[ i ] = offsetPosition;
9548 }
9549 });
9550
9551 position = {
9552 my: myAt[0] + (offset[0] < 0 ? offset[0] : "+" + offset[0]) + " " +
9553 myAt[1] + (offset[1] < 0 ? offset[1] : "+" + offset[1]),
9554 at: myAt.join( " " )
9555 };
9556 }
9557
9558 position = $.extend( {}, $.ui.dialog.prototype.options.position, position );
9559 } else {
9560 position = $.ui.dialog.prototype.options.position;
9561 }
9562
9563 // need to show the dialog to get the actual offset in the position plugin
9564 isVisible = this.uiDialog.is( ":visible" );
9565 if ( !isVisible ) {
9566 this.uiDialog.show();
9567 }
9568 this.uiDialog.position( position );
9569 if ( !isVisible ) {
9570 this.uiDialog.hide();
9571 }
9572 },
9573
9574 _setOptions: function( options ) {
9575 var that = this,
9576 resizableOptions = {},
9577 resize = false;
9578
9579 $.each( options, function( key, value ) {
9580 that._setOption( key, value );
9581
9582 if ( key in sizeRelatedOptions ) {
9583 resize = true;
9584 }
9585 if ( key in resizableRelatedOptions ) {
9586 resizableOptions[ key ] = value;
9587 }
9588 });
9589
9590 if ( resize ) {
9591 this._size();
9592 }
9593 if ( this.uiDialog.is( ":data(resizable)" ) ) {
9594 this.uiDialog.resizable( "option", resizableOptions );
9595 }
9596 },
9597
9598 _setOption: function( key, value ) {
9599 var isDraggable, isResizable,
9600 uiDialog = this.uiDialog;
9601
9602 switch ( key ) {
9603 case "buttons":
9604 this._createButtons( value );
9605 break;
9606 case "closeText":
9607 // ensure that we always pass a string
9608 this.uiDialogTitlebarCloseText.text( "" + value );
9609 break;
9610 case "dialogClass":
9611 uiDialog
9612 .removeClass( this.options.dialogClass )
9613 .addClass( uiDialogClasses + value );
9614 break;
9615 case "disabled":
9616 if ( value ) {
9617 uiDialog.addClass( "ui-dialog-disabled" );
9618 } else {
9619 uiDialog.removeClass( "ui-dialog-disabled" );
9620 }
9621 break;
9622 case "draggable":
9623 isDraggable = uiDialog.is( ":data(draggable)" );
9624 if ( isDraggable && !value ) {
9625 uiDialog.draggable( "destroy" );
9626 }
9627
9628 if ( !isDraggable && value ) {
9629 this._makeDraggable();
9630 }
9631 break;
9632 case "position":
9633 this._position( value );
9634 break;
9635 case "resizable":
9636 // currently resizable, becoming non-resizable
9637 isResizable = uiDialog.is( ":data(resizable)" );
9638 if ( isResizable && !value ) {
9639 uiDialog.resizable( "destroy" );
9640 }
9641
9642 // currently resizable, changing handles
9643 if ( isResizable && typeof value === "string" ) {
9644 uiDialog.resizable( "option", "handles", value );
9645 }
9646
9647 // currently non-resizable, becoming resizable
9648 if ( !isResizable && value !== false ) {
9649 this._makeResizable( value );
9650 }
9651 break;
9652 case "title":
9653 // convert whatever was passed in o a string, for html() to not throw up
9654 $( ".ui-dialog-title", this.uiDialogTitlebar )
9655 .html( "" + ( value || "&#160;" ) );
9656 break;
9657 }
9658
9659 this._super( key, value );
9660 },
9661
9662 _size: function() {
9663 /* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
9664 * divs will both have width and height set, so we need to reset them
9665 */
9666 var nonContentHeight, minContentHeight, autoHeight,
9667 options = this.options,
9668 isVisible = this.uiDialog.is( ":visible" );
9669
9670 // reset content sizing
9671 this.element.show().css({
9672 width: "auto",
9673 minHeight: 0,
9674 height: 0
9675 });
9676
9677 if ( options.minWidth > options.width ) {
9678 options.width = options.minWidth;
9679 }
9680
9681 // reset wrapper sizing
9682 // determine the height of all the non-content elements
9683 nonContentHeight = this.uiDialog.css({
9684 height: "auto",
9685 width: options.width
9686 })
9687 .outerHeight();
9688 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
9689
9690 if ( options.height === "auto" ) {
9691 // only needed for IE6 support
9692 if ( $.support.minHeight ) {
9693 this.element.css({
9694 minHeight: minContentHeight,
9695 height: "auto"
9696 });
9697 } else {
9698 this.uiDialog.show();
9699 autoHeight = this.element.css( "height", "auto" ).height();
9700 if ( !isVisible ) {
9701 this.uiDialog.hide();
9702 }
9703 this.element.height( Math.max( autoHeight, minContentHeight ) );
9704 }
9705 } else {
9706 this.element.height( Math.max( options.height - nonContentHeight, 0 ) );
9707 }
9708
9709 if (this.uiDialog.is( ":data(resizable)" ) ) {
9710 this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
9711 }
9712 }
9713});
9714
9715$.extend($.ui.dialog, {
9716 uuid: 0,
9717 maxZ: 0,
9718
9719 getTitleId: function($el) {
9720 var id = $el.attr( "id" );
9721 if ( !id ) {
9722 this.uuid += 1;
9723 id = this.uuid;
9724 }
9725 return "ui-dialog-title-" + id;
9726 },
9727
9728 overlay: function( dialog ) {
9729 this.$el = $.ui.dialog.overlay.create( dialog );
9730 }
9731});
9732
9733$.extend( $.ui.dialog.overlay, {
9734 instances: [],
9735 // reuse old instances due to IE memory leak with alpha transparency (see #5185)
9736 oldInstances: [],
9737 maxZ: 0,
9738 events: $.map(
9739 "focus,mousedown,mouseup,keydown,keypress,click".split( "," ),
9740 function( event ) {
9741 return event + ".dialog-overlay";
9742 }
9743 ).join( " " ),
9744 create: function( dialog ) {
9745 if ( this.instances.length === 0 ) {
9746 // prevent use of anchors and inputs
9747 // we use a setTimeout in case the overlay is created from an
9748 // event that we're going to be cancelling (see #2804)
9749 setTimeout(function() {
9750 // handle $(el).dialog().dialog('close') (see #4065)
9751 if ( $.ui.dialog.overlay.instances.length ) {
9752 $( document ).bind( $.ui.dialog.overlay.events, function( event ) {
9753 // stop events if the z-index of the target is < the z-index of the overlay
9754 // we cannot return true when we don't want to cancel the event (#3523)
9755 if ( $( event.target ).zIndex() < $.ui.dialog.overlay.maxZ ) {
9756 return false;
9757 }
9758 });
9759 }
9760 }, 1 );
9761
9762 // handle window resize
9763 $( window ).bind( "resize.dialog-overlay", $.ui.dialog.overlay.resize );
9764 }
9765
9766 var $el = ( this.oldInstances.pop() || $( "<div>" ).addClass( "ui-widget-overlay" ) );
9767
9768 // allow closing by pressing the escape key
9769 $( document ).bind( "keydown.dialog-overlay", function( event ) {
9770 var instances = $.ui.dialog.overlay.instances;
9771 // only react to the event if we're the top overlay
9772 if ( instances.length !== 0 && instances[ instances.length - 1 ] === $el &&
9773 dialog.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
9774 event.keyCode === $.ui.keyCode.ESCAPE ) {
9775
9776 dialog.close( event );
9777 event.preventDefault();
9778 }
9779 });
9780
9781 $el.appendTo( document.body ).css({
9782 width: this.width(),
9783 height: this.height()
9784 });
9785
9786 if ( $.fn.bgiframe ) {
9787 $el.bgiframe();
9788 }
9789
9790 this.instances.push( $el );
9791 return $el;
9792 },
9793
9794 destroy: function( $el ) {
9795 var indexOf = $.inArray( $el, this.instances ),
9796 maxZ = 0;
9797
9798 if ( indexOf !== -1 ) {
9799 this.oldInstances.push( this.instances.splice( indexOf, 1 )[ 0 ] );
9800 }
9801
9802 if ( this.instances.length === 0 ) {
9803 $( [ document, window ] ).unbind( ".dialog-overlay" );
9804 }
9805
9806 $el.height( 0 ).width( 0 ).remove();
9807
9808 // adjust the maxZ to allow other modal dialogs to continue to work (see #4309)
9809 $.each( this.instances, function() {
9810 maxZ = Math.max( maxZ, this.css( "z-index" ) );
9811 });
9812 this.maxZ = maxZ;
9813 },
9814
9815 height: function() {
9816 var scrollHeight,
9817 offsetHeight;
9818 // handle IE
9819 if ( $.ui.ie ) {
9820 scrollHeight = Math.max(
9821 document.documentElement.scrollHeight,
9822 document.body.scrollHeight
9823 );
9824 offsetHeight = Math.max(
9825 document.documentElement.offsetHeight,
9826 document.body.offsetHeight
9827 );
9828
9829 if ( scrollHeight < offsetHeight ) {
9830 return $( window ).height() + "px";
9831 } else {
9832 return scrollHeight + "px";
9833 }
9834 // handle "good" browsers
9835 } else {
9836 return $( document ).height() + "px";
9837 }
9838 },
9839
9840 width: function() {
9841 var scrollWidth,
9842 offsetWidth;
9843 // handle IE
9844 if ( $.ui.ie ) {
9845 scrollWidth = Math.max(
9846 document.documentElement.scrollWidth,
9847 document.body.scrollWidth
9848 );
9849 offsetWidth = Math.max(
9850 document.documentElement.offsetWidth,
9851 document.body.offsetWidth
9852 );
9853
9854 if ( scrollWidth < offsetWidth ) {
9855 return $( window ).width() + "px";
9856 } else {
9857 return scrollWidth + "px";
9858 }
9859 // handle "good" browsers
9860 } else {
9861 return $( document ).width() + "px";
9862 }
9863 },
9864
9865 resize: function() {
9866 /* If the dialog is draggable and the user drags it past the
9867 * right edge of the window, the document becomes wider so we
9868 * need to stretch the overlay. If the user then drags the
9869 * dialog back to the left, the document will become narrower,
9870 * so we need to shrink the overlay to the appropriate size.
9871 * This is handled by shrinking the overlay before setting it
9872 * to the full document size.
9873 */
9874 var $overlays = $( [] );
9875 $.each( $.ui.dialog.overlay.instances, function() {
9876 $overlays = $overlays.add( this );
9877 });
9878
9879 $overlays.css({
9880 width: 0,
9881 height: 0
9882 }).css({
9883 width: $.ui.dialog.overlay.width(),
9884 height: $.ui.dialog.overlay.height()
9885 });
9886 }
9887});
9888
9889$.extend( $.ui.dialog.overlay.prototype, {
9890 destroy: function() {
9891 $.ui.dialog.overlay.destroy( this.$el );
9892 }
9893});
9894
9895}( jQuery ) );
9896
9897(function( $, undefined ) {
9898
9899var rvertical = /up|down|vertical/,
9900 rpositivemotion = /up|left|vertical|horizontal/;
9901
9902$.effects.effect.blind = function( o, done ) {
9903 // Create element
9904 var el = $( this ),
9905 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
9906 mode = $.effects.setMode( el, o.mode || "hide" ),
9907 direction = o.direction || "up",
9908 vertical = rvertical.test( direction ),
9909 ref = vertical ? "height" : "width",
9910 ref2 = vertical ? "top" : "left",
9911 motion = rpositivemotion.test( direction ),
9912 animation = {},
9913 show = mode === "show",
9914 wrapper, distance, margin;
9915
9916 // if already wrapped, the wrapper's properties are my property. #6245
9917 if ( el.parent().is( ".ui-effects-wrapper" ) ) {
9918 $.effects.save( el.parent(), props );
9919 } else {
9920 $.effects.save( el, props );
9921 }
9922 el.show();
9923 wrapper = $.effects.createWrapper( el ).css({
9924 overflow: "hidden"
9925 });
9926
9927 distance = wrapper[ ref ]();
9928 margin = parseFloat( wrapper.css( ref2 ) ) || 0;
9929
9930 animation[ ref ] = show ? distance : 0;
9931 if ( !motion ) {
9932 el
9933 .css( vertical ? "bottom" : "right", 0 )
9934 .css( vertical ? "top" : "left", "auto" )
9935 .css({ position: "absolute" });
9936
9937 animation[ ref2 ] = show ? margin : distance + margin;
9938 }
9939
9940 // start at 0 if we are showing
9941 if ( show ) {
9942 wrapper.css( ref, 0 );
9943 if ( ! motion ) {
9944 wrapper.css( ref2, margin + distance );
9945 }
9946 }
9947
9948 // Animate
9949 wrapper.animate( animation, {
9950 duration: o.duration,
9951 easing: o.easing,
9952 queue: false,
9953 complete: function() {
9954 if ( mode === "hide" ) {
9955 el.hide();
9956 }
9957 $.effects.restore( el, props );
9958 $.effects.removeWrapper( el );
9959 done();
9960 }
9961 });
9962
9963};
9964
9965})(jQuery);
9966
9967(function( $, undefined ) {
9968
9969$.effects.effect.bounce = function( o, done ) {
9970 var el = $( this ),
9971 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
9972
9973 // defaults:
9974 mode = $.effects.setMode( el, o.mode || "effect" ),
9975 hide = mode === "hide",
9976 show = mode === "show",
9977 direction = o.direction || "up",
9978 distance = o.distance,
9979 times = o.times || 5,
9980
9981 // number of internal animations
9982 anims = times * 2 + ( show || hide ? 1 : 0 ),
9983 speed = o.duration / anims,
9984 easing = o.easing,
9985
9986 // utility:
9987 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
9988 motion = ( direction === "up" || direction === "left" ),
9989 i,
9990 upAnim,
9991 downAnim,
9992
9993 // we will need to re-assemble the queue to stack our animations in place
9994 queue = el.queue(),
9995 queuelen = queue.length;
9996
9997 // Avoid touching opacity to prevent clearType and PNG issues in IE
9998 if ( show || hide ) {
9999 props.push( "opacity" );
10000 }
10001
10002 $.effects.save( el, props );
10003 el.show();
10004 $.effects.createWrapper( el ); // Create Wrapper
10005
10006 // default distance for the BIGGEST bounce is the outer Distance / 3
10007 if ( !distance ) {
10008 distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
10009 }
10010
10011 if ( show ) {
10012 downAnim = { opacity: 1 };
10013 downAnim[ ref ] = 0;
10014
10015 // if we are showing, force opacity 0 and set the initial position
10016 // then do the "first" animation
10017 el.css( "opacity", 0 )
10018 .css( ref, motion ? -distance * 2 : distance * 2 )
10019 .animate( downAnim, speed, easing );
10020 }
10021
10022 // start at the smallest distance if we are hiding
10023 if ( hide ) {
10024 distance = distance / Math.pow( 2, times - 1 );
10025 }
10026
10027 downAnim = {};
10028 downAnim[ ref ] = 0;
10029 // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
10030 for ( i = 0; i < times; i++ ) {
10031 upAnim = {};
10032 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
10033
10034 el.animate( upAnim, speed, easing )
10035 .animate( downAnim, speed, easing );
10036
10037 distance = hide ? distance * 2 : distance / 2;
10038 }
10039
10040 // Last Bounce when Hiding
10041 if ( hide ) {
10042 upAnim = { opacity: 0 };
10043 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
10044
10045 el.animate( upAnim, speed, easing );
10046 }
10047
10048 el.queue(function() {
10049 if ( hide ) {
10050 el.hide();
10051 }
10052 $.effects.restore( el, props );
10053 $.effects.removeWrapper( el );
10054 done();
10055 });
10056
10057 // inject all the animations we just queued to be first in line (after "inprogress")
10058 if ( queuelen > 1) {
10059 queue.splice.apply( queue,
10060 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
10061 }
10062 el.dequeue();
10063
10064};
10065
10066})(jQuery);
10067
10068(function( $, undefined ) {
10069
10070$.effects.effect.clip = function( o, done ) {
10071 // Create element
10072 var el = $( this ),
10073 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10074 mode = $.effects.setMode( el, o.mode || "hide" ),
10075 show = mode === "show",
10076 direction = o.direction || "vertical",
10077 vert = direction === "vertical",
10078 size = vert ? "height" : "width",
10079 position = vert ? "top" : "left",
10080 animation = {},
10081 wrapper, animate, distance;
10082
10083 // Save & Show
10084 $.effects.save( el, props );
10085 el.show();
10086
10087 // Create Wrapper
10088 wrapper = $.effects.createWrapper( el ).css({
10089 overflow: "hidden"
10090 });
10091 animate = ( el[0].tagName === "IMG" ) ? wrapper : el;
10092 distance = animate[ size ]();
10093
10094 // Shift
10095 if ( show ) {
10096 animate.css( size, 0 );
10097 animate.css( position, distance / 2 );
10098 }
10099
10100 // Create Animation Object:
10101 animation[ size ] = show ? distance : 0;
10102 animation[ position ] = show ? 0 : distance / 2;
10103
10104 // Animate
10105 animate.animate( animation, {
10106 queue: false,
10107 duration: o.duration,
10108 easing: o.easing,
10109 complete: function() {
10110 if ( !show ) {
10111 el.hide();
10112 }
10113 $.effects.restore( el, props );
10114 $.effects.removeWrapper( el );
10115 done();
10116 }
10117 });
10118
10119};
10120
10121})(jQuery);
10122
10123(function( $, undefined ) {
10124
10125$.effects.effect.drop = function( o, done ) {
10126
10127 var el = $( this ),
10128 props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
10129 mode = $.effects.setMode( el, o.mode || "hide" ),
10130 show = mode === "show",
10131 direction = o.direction || "left",
10132 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
10133 motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
10134 animation = {
10135 opacity: show ? 1 : 0
10136 },
10137 distance;
10138
10139 // Adjust
10140 $.effects.save( el, props );
10141 el.show();
10142 $.effects.createWrapper( el );
10143
10144 distance = o.distance || el[ ref === "top" ? "outerHeight": "outerWidth" ]( true ) / 2;
10145
10146 if ( show ) {
10147 el
10148 .css( "opacity", 0 )
10149 .css( ref, motion === "pos" ? -distance : distance );
10150 }
10151
10152 // Animation
10153 animation[ ref ] = ( show ?
10154 ( motion === "pos" ? "+=" : "-=" ) :
10155 ( motion === "pos" ? "-=" : "+=" ) ) +
10156 distance;
10157
10158 // Animate
10159 el.animate( animation, {
10160 queue: false,
10161 duration: o.duration,
10162 easing: o.easing,
10163 complete: function() {
10164 if ( mode === "hide" ) {
10165 el.hide();
10166 }
10167 $.effects.restore( el, props );
10168 $.effects.removeWrapper( el );
10169 done();
10170 }
10171 });
10172};
10173
10174})(jQuery);
10175
10176(function( $, undefined ) {
10177
10178$.effects.effect.explode = function( o, done ) {
10179
10180 var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3,
10181 cells = rows,
10182 el = $( this ),
10183 mode = $.effects.setMode( el, o.mode || "hide" ),
10184 show = mode === "show",
10185
10186 // show and then visibility:hidden the element before calculating offset
10187 offset = el.show().css( "visibility", "hidden" ).offset(),
10188
10189 // width and height of a piece
10190 width = Math.ceil( el.outerWidth() / cells ),
10191 height = Math.ceil( el.outerHeight() / rows ),
10192 pieces = [],
10193
10194 // loop
10195 i, j, left, top, mx, my;
10196
10197 // children animate complete:
10198 function childComplete() {
10199 pieces.push( this );
10200 if ( pieces.length === rows * cells ) {
10201 animComplete();
10202 }
10203 }
10204
10205 // clone the element for each row and cell.
10206 for( i = 0; i < rows ; i++ ) { // ===>
10207 top = offset.top + i * height;
10208 my = i - ( rows - 1 ) / 2 ;
10209
10210 for( j = 0; j < cells ; j++ ) { // |||
10211 left = offset.left + j * width;
10212 mx = j - ( cells - 1 ) / 2 ;
10213
10214 // Create a clone of the now hidden main element that will be absolute positioned
10215 // within a wrapper div off the -left and -top equal to size of our pieces
10216 el
10217 .clone()
10218 .appendTo( "body" )
10219 .wrap( "<div></div>" )
10220 .css({
10221 position: "absolute",
10222 visibility: "visible",
10223 left: -j * width,
10224 top: -i * height
10225 })
10226
10227 // select the wrapper - make it overflow: hidden and absolute positioned based on
10228 // where the original was located +left and +top equal to the size of pieces
10229 .parent()
10230 .addClass( "ui-effects-explode" )
10231 .css({
10232 position: "absolute",
10233 overflow: "hidden",
10234 width: width,
10235 height: height,
10236 left: left + ( show ? mx * width : 0 ),
10237 top: top + ( show ? my * height : 0 ),
10238 opacity: show ? 0 : 1
10239 }).animate({
10240 left: left + ( show ? 0 : mx * width ),
10241 top: top + ( show ? 0 : my * height ),
10242 opacity: show ? 1 : 0
10243 }, o.duration || 500, o.easing, childComplete );
10244 }
10245 }
10246
10247 function animComplete() {
10248 el.css({
10249 visibility: "visible"
10250 });
10251 $( pieces ).remove();
10252 if ( !show ) {
10253 el.hide();
10254 }
10255 done();
10256 }
10257};
10258
10259})(jQuery);
10260
10261(function( $, undefined ) {
10262
10263$.effects.effect.fade = function( o, done ) {
10264 var el = $( this ),
10265 mode = $.effects.setMode( el, o.mode || "toggle" );
10266
10267 el.animate({
10268 opacity: mode
10269 }, {
10270 queue: false,
10271 duration: o.duration,
10272 easing: o.easing,
10273 complete: done
10274 });
10275};
10276
10277})( jQuery );
10278
10279(function( $, undefined ) {
10280
10281$.effects.effect.fold = function( o, done ) {
10282
10283 // Create element
10284 var el = $( this ),
10285 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10286 mode = $.effects.setMode( el, o.mode || "hide" ),
10287 show = mode === "show",
10288 hide = mode === "hide",
10289 size = o.size || 15,
10290 percent = /([0-9]+)%/.exec( size ),
10291 horizFirst = !!o.horizFirst,
10292 widthFirst = show !== horizFirst,
10293 ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ],
10294 duration = o.duration / 2,
10295 wrapper, distance,
10296 animation1 = {},
10297 animation2 = {};
10298
10299 $.effects.save( el, props );
10300 el.show();
10301
10302 // Create Wrapper
10303 wrapper = $.effects.createWrapper( el ).css({
10304 overflow: "hidden"
10305 });
10306 distance = widthFirst ?
10307 [ wrapper.width(), wrapper.height() ] :
10308 [ wrapper.height(), wrapper.width() ];
10309
10310 if ( percent ) {
10311 size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
10312 }
10313 if ( show ) {
10314 wrapper.css( horizFirst ? {
10315 height: 0,
10316 width: size
10317 } : {
10318 height: size,
10319 width: 0
10320 });
10321 }
10322
10323 // Animation
10324 animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size;
10325 animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0;
10326
10327 // Animate
10328 wrapper
10329 .animate( animation1, duration, o.easing )
10330 .animate( animation2, duration, o.easing, function() {
10331 if ( hide ) {
10332 el.hide();
10333 }
10334 $.effects.restore( el, props );
10335 $.effects.removeWrapper( el );
10336 done();
10337 });
10338
10339};
10340
10341})(jQuery);
10342
10343(function( $, undefined ) {
10344
10345$.effects.effect.highlight = function( o, done ) {
10346 var elem = $( this ),
10347 props = [ "backgroundImage", "backgroundColor", "opacity" ],
10348 mode = $.effects.setMode( elem, o.mode || "show" ),
10349 animation = {
10350 backgroundColor: elem.css( "backgroundColor" )
10351 };
10352
10353 if (mode === "hide") {
10354 animation.opacity = 0;
10355 }
10356
10357 $.effects.save( elem, props );
10358
10359 elem
10360 .show()
10361 .css({
10362 backgroundImage: "none",
10363 backgroundColor: o.color || "#ffff99"
10364 })
10365 .animate( animation, {
10366 queue: false,
10367 duration: o.duration,
10368 easing: o.easing,
10369 complete: function() {
10370 if ( mode === "hide" ) {
10371 elem.hide();
10372 }
10373 $.effects.restore( elem, props );
10374 done();
10375 }
10376 });
10377};
10378
10379})(jQuery);
10380
10381(function( $, undefined ) {
10382
10383$.effects.effect.pulsate = function( o, done ) {
10384 var elem = $( this ),
10385 mode = $.effects.setMode( elem, o.mode || "show" ),
10386 show = mode === "show",
10387 hide = mode === "hide",
10388 showhide = ( show || mode === "hide" ),
10389
10390 // showing or hiding leaves of the "last" animation
10391 anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
10392 duration = o.duration / anims,
10393 animateTo = 0,
10394 queue = elem.queue(),
10395 queuelen = queue.length,
10396 i;
10397
10398 if ( show || !elem.is(":visible")) {
10399 elem.css( "opacity", 0 ).show();
10400 animateTo = 1;
10401 }
10402
10403 // anims - 1 opacity "toggles"
10404 for ( i = 1; i < anims; i++ ) {
10405 elem.animate({
10406 opacity: animateTo
10407 }, duration, o.easing );
10408 animateTo = 1 - animateTo;
10409 }
10410
10411 elem.animate({
10412 opacity: animateTo
10413 }, duration, o.easing);
10414
10415 elem.queue(function() {
10416 if ( hide ) {
10417 elem.hide();
10418 }
10419 done();
10420 });
10421
10422 // We just queued up "anims" animations, we need to put them next in the queue
10423 if ( queuelen > 1 ) {
10424 queue.splice.apply( queue,
10425 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
10426 }
10427 elem.dequeue();
10428};
10429
10430})(jQuery);
10431
10432(function( $, undefined ) {
10433
10434$.effects.effect.puff = function( o, done ) {
10435 var elem = $( this ),
10436 mode = $.effects.setMode( elem, o.mode || "hide" ),
10437 hide = mode === "hide",
10438 percent = parseInt( o.percent, 10 ) || 150,
10439 factor = percent / 100,
10440 original = {
10441 height: elem.height(),
10442 width: elem.width(),
10443 outerHeight: elem.outerHeight(),
10444 outerWidth: elem.outerWidth()
10445 };
10446
10447 $.extend( o, {
10448 effect: "scale",
10449 queue: false,
10450 fade: true,
10451 mode: mode,
10452 complete: done,
10453 percent: hide ? percent : 100,
10454 from: hide ?
10455 original :
10456 {
10457 height: original.height * factor,
10458 width: original.width * factor,
10459 outerHeight: original.outerHeight * factor,
10460 outerWidth: original.outerWidth * factor
10461 }
10462 });
10463
10464 elem.effect( o );
10465};
10466
10467$.effects.effect.scale = function( o, done ) {
10468
10469 // Create element
10470 var el = $( this ),
10471 options = $.extend( true, {}, o ),
10472 mode = $.effects.setMode( el, o.mode || "effect" ),
10473 percent = parseInt( o.percent, 10 ) ||
10474 ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ),
10475 direction = o.direction || "both",
10476 origin = o.origin,
10477 original = {
10478 height: el.height(),
10479 width: el.width(),
10480 outerHeight: el.outerHeight(),
10481 outerWidth: el.outerWidth()
10482 },
10483 factor = {
10484 y: direction !== "horizontal" ? (percent / 100) : 1,
10485 x: direction !== "vertical" ? (percent / 100) : 1
10486 };
10487
10488 // We are going to pass this effect to the size effect:
10489 options.effect = "size";
10490 options.queue = false;
10491 options.complete = done;
10492
10493 // Set default origin and restore for show/hide
10494 if ( mode !== "effect" ) {
10495 options.origin = origin || ["middle","center"];
10496 options.restore = true;
10497 }
10498
10499 options.from = o.from || ( mode === "show" ? {
10500 height: 0,
10501 width: 0,
10502 outerHeight: 0,
10503 outerWidth: 0
10504 } : original );
10505 options.to = {
10506 height: original.height * factor.y,
10507 width: original.width * factor.x,
10508 outerHeight: original.outerHeight * factor.y,
10509 outerWidth: original.outerWidth * factor.x
10510 };
10511
10512 // Fade option to support puff
10513 if ( options.fade ) {
10514 if ( mode === "show" ) {
10515 options.from.opacity = 0;
10516 options.to.opacity = 1;
10517 }
10518 if ( mode === "hide" ) {
10519 options.from.opacity = 1;
10520 options.to.opacity = 0;
10521 }
10522 }
10523
10524 // Animate
10525 el.effect( options );
10526
10527};
10528
10529$.effects.effect.size = function( o, done ) {
10530
10531 // Create element
10532 var original, baseline, factor,
10533 el = $( this ),
10534 props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ],
10535
10536 // Always restore
10537 props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ],
10538
10539 // Copy for children
10540 props2 = [ "width", "height", "overflow" ],
10541 cProps = [ "fontSize" ],
10542 vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
10543 hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
10544
10545 // Set options
10546 mode = $.effects.setMode( el, o.mode || "effect" ),
10547 restore = o.restore || mode !== "effect",
10548 scale = o.scale || "both",
10549 origin = o.origin || [ "middle", "center" ],
10550 position = el.css( "position" ),
10551 props = restore ? props0 : props1,
10552 zero = {
10553 height: 0,
10554 width: 0,
10555 outerHeight: 0,
10556 outerWidth: 0
10557 };
10558
10559 if ( mode === "show" ) {
10560 el.show();
10561 }
10562 original = {
10563 height: el.height(),
10564 width: el.width(),
10565 outerHeight: el.outerHeight(),
10566 outerWidth: el.outerWidth()
10567 };
10568
10569 if ( o.mode === "toggle" && mode === "show" ) {
10570 el.from = o.to || zero;
10571 el.to = o.from || original;
10572 } else {
10573 el.from = o.from || ( mode === "show" ? zero : original );
10574 el.to = o.to || ( mode === "hide" ? zero : original );
10575 }
10576
10577 // Set scaling factor
10578 factor = {
10579 from: {
10580 y: el.from.height / original.height,
10581 x: el.from.width / original.width
10582 },
10583 to: {
10584 y: el.to.height / original.height,
10585 x: el.to.width / original.width
10586 }
10587 };
10588
10589 // Scale the css box
10590 if ( scale === "box" || scale === "both" ) {
10591
10592 // Vertical props scaling
10593 if ( factor.from.y !== factor.to.y ) {
10594 props = props.concat( vProps );
10595 el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
10596 el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
10597 }
10598
10599 // Horizontal props scaling
10600 if ( factor.from.x !== factor.to.x ) {
10601 props = props.concat( hProps );
10602 el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
10603 el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
10604 }
10605 }
10606
10607 // Scale the content
10608 if ( scale === "content" || scale === "both" ) {
10609
10610 // Vertical props scaling
10611 if ( factor.from.y !== factor.to.y ) {
10612 props = props.concat( cProps ).concat( props2 );
10613 el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
10614 el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
10615 }
10616 }
10617
10618 $.effects.save( el, props );
10619 el.show();
10620 $.effects.createWrapper( el );
10621 el.css( "overflow", "hidden" ).css( el.from );
10622
10623 // Adjust
10624 if (origin) { // Calculate baseline shifts
10625 baseline = $.effects.getBaseline( origin, original );
10626 el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
10627 el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
10628 el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
10629 el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
10630 }
10631 el.css( el.from ); // set top & left
10632
10633 // Animate
10634 if ( scale === "content" || scale === "both" ) { // Scale the children
10635
10636 // Add margins/font-size
10637 vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps);
10638 hProps = hProps.concat([ "marginLeft", "marginRight" ]);
10639 props2 = props0.concat(vProps).concat(hProps);
10640
10641 el.find( "*[width]" ).each( function(){
10642 var child = $( this ),
10643 c_original = {
10644 height: child.height(),
10645 width: child.width(),
10646 outerHeight: child.outerHeight(),
10647 outerWidth: child.outerWidth()
10648 };
10649 if (restore) {
10650 $.effects.save(child, props2);
10651 }
10652
10653 child.from = {
10654 height: c_original.height * factor.from.y,
10655 width: c_original.width * factor.from.x,
10656 outerHeight: c_original.outerHeight * factor.from.y,
10657 outerWidth: c_original.outerWidth * factor.from.x
10658 };
10659 child.to = {
10660 height: c_original.height * factor.to.y,
10661 width: c_original.width * factor.to.x,
10662 outerHeight: c_original.height * factor.to.y,
10663 outerWidth: c_original.width * factor.to.x
10664 };
10665
10666 // Vertical props scaling
10667 if ( factor.from.y !== factor.to.y ) {
10668 child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
10669 child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
10670 }
10671
10672 // Horizontal props scaling
10673 if ( factor.from.x !== factor.to.x ) {
10674 child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
10675 child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
10676 }
10677
10678 // Animate children
10679 child.css( child.from );
10680 child.animate( child.to, o.duration, o.easing, function() {
10681
10682 // Restore children
10683 if ( restore ) {
10684 $.effects.restore( child, props2 );
10685 }
10686 });
10687 });
10688 }
10689
10690 // Animate
10691 el.animate( el.to, {
10692 queue: false,
10693 duration: o.duration,
10694 easing: o.easing,
10695 complete: function() {
10696 if ( el.to.opacity === 0 ) {
10697 el.css( "opacity", el.from.opacity );
10698 }
10699 if( mode === "hide" ) {
10700 el.hide();
10701 }
10702 $.effects.restore( el, props );
10703 if ( !restore ) {
10704
10705 // we need to calculate our new positioning based on the scaling
10706 if ( position === "static" ) {
10707 el.css({
10708 position: "relative",
10709 top: el.to.top,
10710 left: el.to.left
10711 });
10712 } else {
10713 $.each([ "top", "left" ], function( idx, pos ) {
10714 el.css( pos, function( _, str ) {
10715 var val = parseInt( str, 10 ),
10716 toRef = idx ? el.to.left : el.to.top;
10717
10718 // if original was "auto", recalculate the new value from wrapper
10719 if ( str === "auto" ) {
10720 return toRef + "px";
10721 }
10722
10723 return val + toRef + "px";
10724 });
10725 });
10726 }
10727 }
10728
10729 $.effects.removeWrapper( el );
10730 done();
10731 }
10732 });
10733
10734};
10735
10736})(jQuery);
10737
10738(function( $, undefined ) {
10739
10740$.effects.effect.shake = function( o, done ) {
10741
10742 var el = $( this ),
10743 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10744 mode = $.effects.setMode( el, o.mode || "effect" ),
10745 direction = o.direction || "left",
10746 distance = o.distance || 20,
10747 times = o.times || 3,
10748 anims = times * 2 + 1,
10749 speed = Math.round(o.duration/anims),
10750 ref = (direction === "up" || direction === "down") ? "top" : "left",
10751 positiveMotion = (direction === "up" || direction === "left"),
10752 animation = {},
10753 animation1 = {},
10754 animation2 = {},
10755 i,
10756
10757 // we will need to re-assemble the queue to stack our animations in place
10758 queue = el.queue(),
10759 queuelen = queue.length;
10760
10761 $.effects.save( el, props );
10762 el.show();
10763 $.effects.createWrapper( el );
10764
10765 // Animation
10766 animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
10767 animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
10768 animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
10769
10770 // Animate
10771 el.animate( animation, speed, o.easing );
10772
10773 // Shakes
10774 for ( i = 1; i < times; i++ ) {
10775 el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing );
10776 }
10777 el
10778 .animate( animation1, speed, o.easing )
10779 .animate( animation, speed / 2, o.easing )
10780 .queue(function() {
10781 if ( mode === "hide" ) {
10782 el.hide();
10783 }
10784 $.effects.restore( el, props );
10785 $.effects.removeWrapper( el );
10786 done();
10787 });
10788
10789 // inject all the animations we just queued to be first in line (after "inprogress")
10790 if ( queuelen > 1) {
10791 queue.splice.apply( queue,
10792 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
10793 }
10794 el.dequeue();
10795
10796};
10797
10798})(jQuery);
10799
10800(function( $, undefined ) {
10801
10802$.effects.effect.slide = function( o, done ) {
10803
10804 // Create element
10805 var el = $( this ),
10806 props = [ "position", "top", "bottom", "left", "right", "width", "height" ],
10807 mode = $.effects.setMode( el, o.mode || "show" ),
10808 show = mode === "show",
10809 direction = o.direction || "left",
10810 ref = (direction === "up" || direction === "down") ? "top" : "left",
10811 positiveMotion = (direction === "up" || direction === "left"),
10812 distance,
10813 animation = {};
10814
10815 // Adjust
10816 $.effects.save( el, props );
10817 el.show();
10818 distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true );
10819
10820 $.effects.createWrapper( el ).css({
10821 overflow: "hidden"
10822 });
10823
10824 if ( show ) {
10825 el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance );
10826 }
10827
10828 // Animation
10829 animation[ ref ] = ( show ?
10830 ( positiveMotion ? "+=" : "-=") :
10831 ( positiveMotion ? "-=" : "+=")) +
10832 distance;
10833
10834 // Animate
10835 el.animate( animation, {
10836 queue: false,
10837 duration: o.duration,
10838 easing: o.easing,
10839 complete: function() {
10840 if ( mode === "hide" ) {
10841 el.hide();
10842 }
10843 $.effects.restore( el, props );
10844 $.effects.removeWrapper( el );
10845 done();
10846 }
10847 });
10848};
10849
10850})(jQuery);
10851
10852(function( $, undefined ) {
10853
10854$.effects.effect.transfer = function( o, done ) {
10855 var elem = $( this ),
10856 target = $( o.to ),
10857 targetFixed = target.css( "position" ) === "fixed",
10858 body = $("body"),
10859 fixTop = targetFixed ? body.scrollTop() : 0,
10860 fixLeft = targetFixed ? body.scrollLeft() : 0,
10861 endPosition = target.offset(),
10862 animation = {
10863 top: endPosition.top - fixTop ,
10864 left: endPosition.left - fixLeft ,
10865 height: target.innerHeight(),
10866 width: target.innerWidth()
10867 },
10868 startPosition = elem.offset(),
10869 transfer = $( '<div class="ui-effects-transfer"></div>' )
10870 .appendTo( document.body )
10871 .addClass( o.className )
10872 .css({
10873 top: startPosition.top - fixTop ,
10874 left: startPosition.left - fixLeft ,
10875 height: elem.innerHeight(),
10876 width: elem.innerWidth(),
10877 position: targetFixed ? "fixed" : "absolute"
10878 })
10879 .animate( animation, o.duration, o.easing, function() {
10880 transfer.remove();
10881 done();
10882 });
10883};
10884
10885})(jQuery);
10886
10887(function( $, undefined ) {
10888
10889var mouseHandled = false;
10890
10891$.widget( "ui.menu", {
10892 version: "1.9.2",
10893 defaultElement: "<ul>",
10894 delay: 300,
10895 options: {
10896 icons: {
10897 submenu: "ui-icon-carat-1-e"
10898 },
10899 menus: "ul",
10900 position: {
10901 my: "left top",
10902 at: "right top"
10903 },
10904 role: "menu",
10905
10906 // callbacks
10907 blur: null,
10908 focus: null,
10909 select: null
10910 },
10911
10912 _create: function() {
10913 this.activeMenu = this.element;
10914 this.element
10915 .uniqueId()
10916 .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
10917 .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
10918 .attr({
10919 role: this.options.role,
10920 tabIndex: 0
10921 })
10922 // need to catch all clicks on disabled menu
10923 // not possible through _on
10924 .bind( "click" + this.eventNamespace, $.proxy(function( event ) {
10925 if ( this.options.disabled ) {
10926 event.preventDefault();
10927 }
10928 }, this ));
10929
10930 if ( this.options.disabled ) {
10931 this.element
10932 .addClass( "ui-state-disabled" )
10933 .attr( "aria-disabled", "true" );
10934 }
10935
10936 this._on({
10937 // Prevent focus from sticking to links inside menu after clicking
10938 // them (focus should always stay on UL during navigation).
10939 "mousedown .ui-menu-item > a": function( event ) {
10940 event.preventDefault();
10941 },
10942 "click .ui-state-disabled > a": function( event ) {
10943 event.preventDefault();
10944 },
10945 "click .ui-menu-item:has(a)": function( event ) {
10946 var target = $( event.target ).closest( ".ui-menu-item" );
10947 if ( !mouseHandled && target.not( ".ui-state-disabled" ).length ) {
10948 mouseHandled = true;
10949
10950 this.select( event );
10951 // Open submenu on click
10952 if ( target.has( ".ui-menu" ).length ) {
10953 this.expand( event );
10954 } else if ( !this.element.is( ":focus" ) ) {
10955 // Redirect focus to the menu
10956 this.element.trigger( "focus", [ true ] );
10957
10958 // If the active item is on the top level, let it stay active.
10959 // Otherwise, blur the active item since it is no longer visible.
10960 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
10961 clearTimeout( this.timer );
10962 }
10963 }
10964 }
10965 },
10966 "mouseenter .ui-menu-item": function( event ) {
10967 var target = $( event.currentTarget );
10968 // Remove ui-state-active class from siblings of the newly focused menu item
10969 // to avoid a jump caused by adjacent elements both having a class with a border
10970 target.siblings().children( ".ui-state-active" ).removeClass( "ui-state-active" );
10971 this.focus( event, target );
10972 },
10973 mouseleave: "collapseAll",
10974 "mouseleave .ui-menu": "collapseAll",
10975 focus: function( event, keepActiveItem ) {
10976 // If there's already an active item, keep it active
10977 // If not, activate the first item
10978 var item = this.active || this.element.children( ".ui-menu-item" ).eq( 0 );
10979
10980 if ( !keepActiveItem ) {
10981 this.focus( event, item );
10982 }
10983 },
10984 blur: function( event ) {
10985 this._delay(function() {
10986 if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
10987 this.collapseAll( event );
10988 }
10989 });
10990 },
10991 keydown: "_keydown"
10992 });
10993
10994 this.refresh();
10995
10996 // Clicks outside of a menu collapse any open menus
10997 this._on( this.document, {
10998 click: function( event ) {
10999 if ( !$( event.target ).closest( ".ui-menu" ).length ) {
11000 this.collapseAll( event );
11001 }
11002
11003 // Reset the mouseHandled flag
11004 mouseHandled = false;
11005 }
11006 });
11007 },
11008
11009 _destroy: function() {
11010 // Destroy (sub)menus
11011 this.element
11012 .removeAttr( "aria-activedescendant" )
11013 .find( ".ui-menu" ).andSelf()
11014 .removeClass( "ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons" )
11015 .removeAttr( "role" )
11016 .removeAttr( "tabIndex" )
11017 .removeAttr( "aria-labelledby" )
11018 .removeAttr( "aria-expanded" )
11019 .removeAttr( "aria-hidden" )
11020 .removeAttr( "aria-disabled" )
11021 .removeUniqueId()
11022 .show();
11023
11024 // Destroy menu items
11025 this.element.find( ".ui-menu-item" )
11026 .removeClass( "ui-menu-item" )
11027 .removeAttr( "role" )
11028 .removeAttr( "aria-disabled" )
11029 .children( "a" )
11030 .removeUniqueId()
11031 .removeClass( "ui-corner-all ui-state-hover" )
11032 .removeAttr( "tabIndex" )
11033 .removeAttr( "role" )
11034 .removeAttr( "aria-haspopup" )
11035 .children().each( function() {
11036 var elem = $( this );
11037 if ( elem.data( "ui-menu-submenu-carat" ) ) {
11038 elem.remove();
11039 }
11040 });
11041
11042 // Destroy menu dividers
11043 this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
11044 },
11045
11046 _keydown: function( event ) {
11047 var match, prev, character, skip, regex,
11048 preventDefault = true;
11049
11050 function escape( value ) {
11051 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
11052 }
11053
11054 switch ( event.keyCode ) {
11055 case $.ui.keyCode.PAGE_UP:
11056 this.previousPage( event );
11057 break;
11058 case $.ui.keyCode.PAGE_DOWN:
11059 this.nextPage( event );
11060 break;
11061 case $.ui.keyCode.HOME:
11062 this._move( "first", "first", event );
11063 break;
11064 case $.ui.keyCode.END:
11065 this._move( "last", "last", event );
11066 break;
11067 case $.ui.keyCode.UP:
11068 this.previous( event );
11069 break;
11070 case $.ui.keyCode.DOWN:
11071 this.next( event );
11072 break;
11073 case $.ui.keyCode.LEFT:
11074 this.collapse( event );
11075 break;
11076 case $.ui.keyCode.RIGHT:
11077 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
11078 this.expand( event );
11079 }
11080 break;
11081 case $.ui.keyCode.ENTER:
11082 case $.ui.keyCode.SPACE:
11083 this._activate( event );
11084 break;
11085 case $.ui.keyCode.ESCAPE:
11086 this.collapse( event );
11087 break;
11088 default:
11089 preventDefault = false;
11090 prev = this.previousFilter || "";
11091 character = String.fromCharCode( event.keyCode );
11092 skip = false;
11093
11094 clearTimeout( this.filterTimer );
11095
11096 if ( character === prev ) {
11097 skip = true;
11098 } else {
11099 character = prev + character;
11100 }
11101
11102 regex = new RegExp( "^" + escape( character ), "i" );
11103 match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
11104 return regex.test( $( this ).children( "a" ).text() );
11105 });
11106 match = skip && match.index( this.active.next() ) !== -1 ?
11107 this.active.nextAll( ".ui-menu-item" ) :
11108 match;
11109
11110 // If no matches on the current filter, reset to the last character pressed
11111 // to move down the menu to the first item that starts with that character
11112 if ( !match.length ) {
11113 character = String.fromCharCode( event.keyCode );
11114 regex = new RegExp( "^" + escape( character ), "i" );
11115 match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
11116 return regex.test( $( this ).children( "a" ).text() );
11117 });
11118 }
11119
11120 if ( match.length ) {
11121 this.focus( event, match );
11122 if ( match.length > 1 ) {
11123 this.previousFilter = character;
11124 this.filterTimer = this._delay(function() {
11125 delete this.previousFilter;
11126 }, 1000 );
11127 } else {
11128 delete this.previousFilter;
11129 }
11130 } else {
11131 delete this.previousFilter;
11132 }
11133 }
11134
11135 if ( preventDefault ) {
11136 event.preventDefault();
11137 }
11138 },
11139
11140 _activate: function( event ) {
11141 if ( !this.active.is( ".ui-state-disabled" ) ) {
11142 if ( this.active.children( "a[aria-haspopup='true']" ).length ) {
11143 this.expand( event );
11144 } else {
11145 this.select( event );
11146 }
11147 }
11148 },
11149
11150 refresh: function() {
11151 var menus,
11152 icon = this.options.icons.submenu,
11153 submenus = this.element.find( this.options.menus );
11154
11155 // Initialize nested menus
11156 submenus.filter( ":not(.ui-menu)" )
11157 .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
11158 .hide()
11159 .attr({
11160 role: this.options.role,
11161 "aria-hidden": "true",
11162 "aria-expanded": "false"
11163 })
11164 .each(function() {
11165 var menu = $( this ),
11166 item = menu.prev( "a" ),
11167 submenuCarat = $( "<span>" )
11168 .addClass( "ui-menu-icon ui-icon " + icon )
11169 .data( "ui-menu-submenu-carat", true );
11170
11171 item
11172 .attr( "aria-haspopup", "true" )
11173 .prepend( submenuCarat );
11174 menu.attr( "aria-labelledby", item.attr( "id" ) );
11175 });
11176
11177 menus = submenus.add( this.element );
11178
11179 // Don't refresh list items that are already adapted
11180 menus.children( ":not(.ui-menu-item):has(a)" )
11181 .addClass( "ui-menu-item" )
11182 .attr( "role", "presentation" )
11183 .children( "a" )
11184 .uniqueId()
11185 .addClass( "ui-corner-all" )
11186 .attr({
11187 tabIndex: -1,
11188 role: this._itemRole()
11189 });
11190
11191 // Initialize unlinked menu-items containing spaces and/or dashes only as dividers
11192 menus.children( ":not(.ui-menu-item)" ).each(function() {
11193 var item = $( this );
11194 // hyphen, em dash, en dash
11195 if ( !/[^\-—–\s]/.test( item.text() ) ) {
11196 item.addClass( "ui-widget-content ui-menu-divider" );
11197 }
11198 });
11199
11200 // Add aria-disabled attribute to any disabled menu item
11201 menus.children( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
11202
11203 // If the active item has been removed, blur the menu
11204 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
11205 this.blur();
11206 }
11207 },
11208
11209 _itemRole: function() {
11210 return {
11211 menu: "menuitem",
11212 listbox: "option"
11213 }[ this.options.role ];
11214 },
11215
11216 focus: function( event, item ) {
11217 var nested, focused;
11218 this.blur( event, event && event.type === "focus" );
11219
11220 this._scrollIntoView( item );
11221
11222 this.active = item.first();
11223 focused = this.active.children( "a" ).addClass( "ui-state-focus" );
11224 // Only update aria-activedescendant if there's a role
11225 // otherwise we assume focus is managed elsewhere
11226 if ( this.options.role ) {
11227 this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
11228 }
11229
11230 // Highlight active parent menu item, if any
11231 this.active
11232 .parent()
11233 .closest( ".ui-menu-item" )
11234 .children( "a:first" )
11235 .addClass( "ui-state-active" );
11236
11237 if ( event && event.type === "keydown" ) {
11238 this._close();
11239 } else {
11240 this.timer = this._delay(function() {
11241 this._close();
11242 }, this.delay );
11243 }
11244
11245 nested = item.children( ".ui-menu" );
11246 if ( nested.length && ( /^mouse/.test( event.type ) ) ) {
11247 this._startOpening(nested);
11248 }
11249 this.activeMenu = item.parent();
11250
11251 this._trigger( "focus", event, { item: item } );
11252 },
11253
11254 _scrollIntoView: function( item ) {
11255 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
11256 if ( this._hasScroll() ) {
11257 borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
11258 paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
11259 offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
11260 scroll = this.activeMenu.scrollTop();
11261 elementHeight = this.activeMenu.height();
11262 itemHeight = item.height();
11263
11264 if ( offset < 0 ) {
11265 this.activeMenu.scrollTop( scroll + offset );
11266 } else if ( offset + itemHeight > elementHeight ) {
11267 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
11268 }
11269 }
11270 },
11271
11272 blur: function( event, fromFocus ) {
11273 if ( !fromFocus ) {
11274 clearTimeout( this.timer );
11275 }
11276
11277 if ( !this.active ) {
11278 return;
11279 }
11280
11281 this.active.children( "a" ).removeClass( "ui-state-focus" );
11282 this.active = null;
11283
11284 this._trigger( "blur", event, { item: this.active } );
11285 },
11286
11287 _startOpening: function( submenu ) {
11288 clearTimeout( this.timer );
11289
11290 // Don't open if already open fixes a Firefox bug that caused a .5 pixel
11291 // shift in the submenu position when mousing over the carat icon
11292 if ( submenu.attr( "aria-hidden" ) !== "true" ) {
11293 return;
11294 }
11295
11296 this.timer = this._delay(function() {
11297 this._close();
11298 this._open( submenu );
11299 }, this.delay );
11300 },
11301
11302 _open: function( submenu ) {
11303 var position = $.extend({
11304 of: this.active
11305 }, this.options.position );
11306
11307 clearTimeout( this.timer );
11308 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
11309 .hide()
11310 .attr( "aria-hidden", "true" );
11311
11312 submenu
11313 .show()
11314 .removeAttr( "aria-hidden" )
11315 .attr( "aria-expanded", "true" )
11316 .position( position );
11317 },
11318
11319 collapseAll: function( event, all ) {
11320 clearTimeout( this.timer );
11321 this.timer = this._delay(function() {
11322 // If we were passed an event, look for the submenu that contains the event
11323 var currentMenu = all ? this.element :
11324 $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
11325
11326 // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
11327 if ( !currentMenu.length ) {
11328 currentMenu = this.element;
11329 }
11330
11331 this._close( currentMenu );
11332
11333 this.blur( event );
11334 this.activeMenu = currentMenu;
11335 }, this.delay );
11336 },
11337
11338 // With no arguments, closes the currently active menu - if nothing is active
11339 // it closes all menus. If passed an argument, it will search for menus BELOW
11340 _close: function( startMenu ) {
11341 if ( !startMenu ) {
11342 startMenu = this.active ? this.active.parent() : this.element;
11343 }
11344
11345 startMenu
11346 .find( ".ui-menu" )
11347 .hide()
11348 .attr( "aria-hidden", "true" )
11349 .attr( "aria-expanded", "false" )
11350 .end()
11351 .find( "a.ui-state-active" )
11352 .removeClass( "ui-state-active" );
11353 },
11354
11355 collapse: function( event ) {
11356 var newItem = this.active &&
11357 this.active.parent().closest( ".ui-menu-item", this.element );
11358 if ( newItem && newItem.length ) {
11359 this._close();
11360 this.focus( event, newItem );
11361 }
11362 },
11363
11364 expand: function( event ) {
11365 var newItem = this.active &&
11366 this.active
11367 .children( ".ui-menu " )
11368 .children( ".ui-menu-item" )
11369 .first();
11370
11371 if ( newItem && newItem.length ) {
11372 this._open( newItem.parent() );
11373
11374 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
11375 this._delay(function() {
11376 this.focus( event, newItem );
11377 });
11378 }
11379 },
11380
11381 next: function( event ) {
11382 this._move( "next", "first", event );
11383 },
11384
11385 previous: function( event ) {
11386 this._move( "prev", "last", event );
11387 },
11388
11389 isFirstItem: function() {
11390 return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
11391 },
11392
11393 isLastItem: function() {
11394 return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
11395 },
11396
11397 _move: function( direction, filter, event ) {
11398 var next;
11399 if ( this.active ) {
11400 if ( direction === "first" || direction === "last" ) {
11401 next = this.active
11402 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
11403 .eq( -1 );
11404 } else {
11405 next = this.active
11406 [ direction + "All" ]( ".ui-menu-item" )
11407 .eq( 0 );
11408 }
11409 }
11410 if ( !next || !next.length || !this.active ) {
11411 next = this.activeMenu.children( ".ui-menu-item" )[ filter ]();
11412 }
11413
11414 this.focus( event, next );
11415 },
11416
11417 nextPage: function( event ) {
11418 var item, base, height;
11419
11420 if ( !this.active ) {
11421 this.next( event );
11422 return;
11423 }
11424 if ( this.isLastItem() ) {
11425 return;
11426 }
11427 if ( this._hasScroll() ) {
11428 base = this.active.offset().top;
11429 height = this.element.height();
11430 this.active.nextAll( ".ui-menu-item" ).each(function() {
11431 item = $( this );
11432 return item.offset().top - base - height < 0;
11433 });
11434
11435 this.focus( event, item );
11436 } else {
11437 this.focus( event, this.activeMenu.children( ".ui-menu-item" )
11438 [ !this.active ? "first" : "last" ]() );
11439 }
11440 },
11441
11442 previousPage: function( event ) {
11443 var item, base, height;
11444 if ( !this.active ) {
11445 this.next( event );
11446 return;
11447 }
11448 if ( this.isFirstItem() ) {
11449 return;
11450 }
11451 if ( this._hasScroll() ) {
11452 base = this.active.offset().top;
11453 height = this.element.height();
11454 this.active.prevAll( ".ui-menu-item" ).each(function() {
11455 item = $( this );
11456 return item.offset().top - base + height > 0;
11457 });
11458
11459 this.focus( event, item );
11460 } else {
11461 this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
11462 }
11463 },
11464
11465 _hasScroll: function() {
11466 return this.element.outerHeight() < this.element.prop( "scrollHeight" );
11467 },
11468
11469 select: function( event ) {
11470 // TODO: It should never be possible to not have an active item at this
11471 // point, but the tests don't trigger mouseenter before click.
11472 this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
11473 var ui = { item: this.active };
11474 if ( !this.active.has( ".ui-menu" ).length ) {
11475 this.collapseAll( event, true );
11476 }
11477 this._trigger( "select", event, ui );
11478 }
11479});
11480
11481}( jQuery ));
11482
11483(function( $, undefined ) {
11484
11485$.ui = $.ui || {};
11486
11487var cachedScrollbarWidth,
11488 max = Math.max,
11489 abs = Math.abs,
11490 round = Math.round,
11491 rhorizontal = /left|center|right/,
11492 rvertical = /top|center|bottom/,
11493 roffset = /[\+\-]\d+%?/,
11494 rposition = /^\w+/,
11495 rpercent = /%$/,
11496 _position = $.fn.position;
11497
11498function getOffsets( offsets, width, height ) {
11499 return [
11500 parseInt( offsets[ 0 ], 10 ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
11501 parseInt( offsets[ 1 ], 10 ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
11502 ];
11503}
11504function parseCss( element, property ) {
11505 return parseInt( $.css( element, property ), 10 ) || 0;
11506}
11507
11508$.position = {
11509 scrollbarWidth: function() {
11510 if ( cachedScrollbarWidth !== undefined ) {
11511 return cachedScrollbarWidth;
11512 }
11513 var w1, w2,
11514 div = $( "<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
11515 innerDiv = div.children()[0];
11516
11517 $( "body" ).append( div );
11518 w1 = innerDiv.offsetWidth;
11519 div.css( "overflow", "scroll" );
11520
11521 w2 = innerDiv.offsetWidth;
11522
11523 if ( w1 === w2 ) {
11524 w2 = div[0].clientWidth;
11525 }
11526
11527 div.remove();
11528
11529 return (cachedScrollbarWidth = w1 - w2);
11530 },
11531 getScrollInfo: function( within ) {
11532 var overflowX = within.isWindow ? "" : within.element.css( "overflow-x" ),
11533 overflowY = within.isWindow ? "" : within.element.css( "overflow-y" ),
11534 hasOverflowX = overflowX === "scroll" ||
11535 ( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
11536 hasOverflowY = overflowY === "scroll" ||
11537 ( overflowY === "auto" && within.height < within.element[0].scrollHeight );
11538 return {
11539 width: hasOverflowX ? $.position.scrollbarWidth() : 0,
11540 height: hasOverflowY ? $.position.scrollbarWidth() : 0
11541 };
11542 },
11543 getWithinInfo: function( element ) {
11544 var withinElement = $( element || window ),
11545 isWindow = $.isWindow( withinElement[0] );
11546 return {
11547 element: withinElement,
11548 isWindow: isWindow,
11549 offset: withinElement.offset() || { left: 0, top: 0 },
11550 scrollLeft: withinElement.scrollLeft(),
11551 scrollTop: withinElement.scrollTop(),
11552 width: isWindow ? withinElement.width() : withinElement.outerWidth(),
11553 height: isWindow ? withinElement.height() : withinElement.outerHeight()
11554 };
11555 }
11556};
11557
11558$.fn.position = function( options ) {
11559 if ( !options || !options.of ) {
11560 return _position.apply( this, arguments );
11561 }
11562
11563 // make a copy, we don't want to modify arguments
11564 options = $.extend( {}, options );
11565
11566 var atOffset, targetWidth, targetHeight, targetOffset, basePosition,
11567 target = $( options.of ),
11568 within = $.position.getWithinInfo( options.within ),
11569 scrollInfo = $.position.getScrollInfo( within ),
11570 targetElem = target[0],
11571 collision = ( options.collision || "flip" ).split( " " ),
11572 offsets = {};
11573
11574 if ( targetElem.nodeType === 9 ) {
11575 targetWidth = target.width();
11576 targetHeight = target.height();
11577 targetOffset = { top: 0, left: 0 };
11578 } else if ( $.isWindow( targetElem ) ) {
11579 targetWidth = target.width();
11580 targetHeight = target.height();
11581 targetOffset = { top: target.scrollTop(), left: target.scrollLeft() };
11582 } else if ( targetElem.preventDefault ) {
11583 // force left top to allow flipping
11584 options.at = "left top";
11585 targetWidth = targetHeight = 0;
11586 targetOffset = { top: targetElem.pageY, left: targetElem.pageX };
11587 } else {
11588 targetWidth = target.outerWidth();
11589 targetHeight = target.outerHeight();
11590 targetOffset = target.offset();
11591 }
11592 // clone to reuse original targetOffset later
11593 basePosition = $.extend( {}, targetOffset );
11594
11595 // force my and at to have valid horizontal and vertical positions
11596 // if a value is missing or invalid, it will be converted to center
11597 $.each( [ "my", "at" ], function() {
11598 var pos = ( options[ this ] || "" ).split( " " ),
11599 horizontalOffset,
11600 verticalOffset;
11601
11602 if ( pos.length === 1) {
11603 pos = rhorizontal.test( pos[ 0 ] ) ?
11604 pos.concat( [ "center" ] ) :
11605 rvertical.test( pos[ 0 ] ) ?
11606 [ "center" ].concat( pos ) :
11607 [ "center", "center" ];
11608 }
11609 pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
11610 pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
11611
11612 // calculate offsets
11613 horizontalOffset = roffset.exec( pos[ 0 ] );
11614 verticalOffset = roffset.exec( pos[ 1 ] );
11615 offsets[ this ] = [
11616 horizontalOffset ? horizontalOffset[ 0 ] : 0,
11617 verticalOffset ? verticalOffset[ 0 ] : 0
11618 ];
11619
11620 // reduce to just the positions without the offsets
11621 options[ this ] = [
11622 rposition.exec( pos[ 0 ] )[ 0 ],
11623 rposition.exec( pos[ 1 ] )[ 0 ]
11624 ];
11625 });
11626
11627 // normalize collision option
11628 if ( collision.length === 1 ) {
11629 collision[ 1 ] = collision[ 0 ];
11630 }
11631
11632 if ( options.at[ 0 ] === "right" ) {
11633 basePosition.left += targetWidth;
11634 } else if ( options.at[ 0 ] === "center" ) {
11635 basePosition.left += targetWidth / 2;
11636 }
11637
11638 if ( options.at[ 1 ] === "bottom" ) {
11639 basePosition.top += targetHeight;
11640 } else if ( options.at[ 1 ] === "center" ) {
11641 basePosition.top += targetHeight / 2;
11642 }
11643
11644 atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
11645 basePosition.left += atOffset[ 0 ];
11646 basePosition.top += atOffset[ 1 ];
11647
11648 return this.each(function() {
11649 var collisionPosition, using,
11650 elem = $( this ),
11651 elemWidth = elem.outerWidth(),
11652 elemHeight = elem.outerHeight(),
11653 marginLeft = parseCss( this, "marginLeft" ),
11654 marginTop = parseCss( this, "marginTop" ),
11655 collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
11656 collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
11657 position = $.extend( {}, basePosition ),
11658 myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
11659
11660 if ( options.my[ 0 ] === "right" ) {
11661 position.left -= elemWidth;
11662 } else if ( options.my[ 0 ] === "center" ) {
11663 position.left -= elemWidth / 2;
11664 }
11665
11666 if ( options.my[ 1 ] === "bottom" ) {
11667 position.top -= elemHeight;
11668 } else if ( options.my[ 1 ] === "center" ) {
11669 position.top -= elemHeight / 2;
11670 }
11671
11672 position.left += myOffset[ 0 ];
11673 position.top += myOffset[ 1 ];
11674
11675 // if the browser doesn't support fractions, then round for consistent results
11676 if ( !$.support.offsetFractions ) {
11677 position.left = round( position.left );
11678 position.top = round( position.top );
11679 }
11680
11681 collisionPosition = {
11682 marginLeft: marginLeft,
11683 marginTop: marginTop
11684 };
11685
11686 $.each( [ "left", "top" ], function( i, dir ) {
11687 if ( $.ui.position[ collision[ i ] ] ) {
11688 $.ui.position[ collision[ i ] ][ dir ]( position, {
11689 targetWidth: targetWidth,
11690 targetHeight: targetHeight,
11691 elemWidth: elemWidth,
11692 elemHeight: elemHeight,
11693 collisionPosition: collisionPosition,
11694 collisionWidth: collisionWidth,
11695 collisionHeight: collisionHeight,
11696 offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
11697 my: options.my,
11698 at: options.at,
11699 within: within,
11700 elem : elem
11701 });
11702 }
11703 });
11704
11705 if ( $.fn.bgiframe ) {
11706 elem.bgiframe();
11707 }
11708
11709 if ( options.using ) {
11710 // adds feedback as second argument to using callback, if present
11711 using = function( props ) {
11712 var left = targetOffset.left - position.left,
11713 right = left + targetWidth - elemWidth,
11714 top = targetOffset.top - position.top,
11715 bottom = top + targetHeight - elemHeight,
11716 feedback = {
11717 target: {
11718 element: target,
11719 left: targetOffset.left,
11720 top: targetOffset.top,
11721 width: targetWidth,
11722 height: targetHeight
11723 },
11724 element: {
11725 element: elem,
11726 left: position.left,
11727 top: position.top,
11728 width: elemWidth,
11729 height: elemHeight
11730 },
11731 horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
11732 vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
11733 };
11734 if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
11735 feedback.horizontal = "center";
11736 }
11737 if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
11738 feedback.vertical = "middle";
11739 }
11740 if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
11741 feedback.important = "horizontal";
11742 } else {
11743 feedback.important = "vertical";
11744 }
11745 options.using.call( this, props, feedback );
11746 };
11747 }
11748
11749 elem.offset( $.extend( position, { using: using } ) );
11750 });
11751};
11752
11753$.ui.position = {
11754 fit: {
11755 left: function( position, data ) {
11756 var within = data.within,
11757 withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
11758 outerWidth = within.width,
11759 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
11760 overLeft = withinOffset - collisionPosLeft,
11761 overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
11762 newOverRight;
11763
11764 // element is wider than within
11765 if ( data.collisionWidth > outerWidth ) {
11766 // element is initially over the left side of within
11767 if ( overLeft > 0 && overRight <= 0 ) {
11768 newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
11769 position.left += overLeft - newOverRight;
11770 // element is initially over right side of within
11771 } else if ( overRight > 0 && overLeft <= 0 ) {
11772 position.left = withinOffset;
11773 // element is initially over both left and right sides of within
11774 } else {
11775 if ( overLeft > overRight ) {
11776 position.left = withinOffset + outerWidth - data.collisionWidth;
11777 } else {
11778 position.left = withinOffset;
11779 }
11780 }
11781 // too far left -> align with left edge
11782 } else if ( overLeft > 0 ) {
11783 position.left += overLeft;
11784 // too far right -> align with right edge
11785 } else if ( overRight > 0 ) {
11786 position.left -= overRight;
11787 // adjust based on position and margin
11788 } else {
11789 position.left = max( position.left - collisionPosLeft, position.left );
11790 }
11791 },
11792 top: function( position, data ) {
11793 var within = data.within,
11794 withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
11795 outerHeight = data.within.height,
11796 collisionPosTop = position.top - data.collisionPosition.marginTop,
11797 overTop = withinOffset - collisionPosTop,
11798 overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
11799 newOverBottom;
11800
11801 // element is taller than within
11802 if ( data.collisionHeight > outerHeight ) {
11803 // element is initially over the top of within
11804 if ( overTop > 0 && overBottom <= 0 ) {
11805 newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
11806 position.top += overTop - newOverBottom;
11807 // element is initially over bottom of within
11808 } else if ( overBottom > 0 && overTop <= 0 ) {
11809 position.top = withinOffset;
11810 // element is initially over both top and bottom of within
11811 } else {
11812 if ( overTop > overBottom ) {
11813 position.top = withinOffset + outerHeight - data.collisionHeight;
11814 } else {
11815 position.top = withinOffset;
11816 }
11817 }
11818 // too far up -> align with top
11819 } else if ( overTop > 0 ) {
11820 position.top += overTop;
11821 // too far down -> align with bottom edge
11822 } else if ( overBottom > 0 ) {
11823 position.top -= overBottom;
11824 // adjust based on position and margin
11825 } else {
11826 position.top = max( position.top - collisionPosTop, position.top );
11827 }
11828 }
11829 },
11830 flip: {
11831 left: function( position, data ) {
11832 var within = data.within,
11833 withinOffset = within.offset.left + within.scrollLeft,
11834 outerWidth = within.width,
11835 offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
11836 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
11837 overLeft = collisionPosLeft - offsetLeft,
11838 overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
11839 myOffset = data.my[ 0 ] === "left" ?
11840 -data.elemWidth :
11841 data.my[ 0 ] === "right" ?
11842 data.elemWidth :
11843 0,
11844 atOffset = data.at[ 0 ] === "left" ?
11845 data.targetWidth :
11846 data.at[ 0 ] === "right" ?
11847 -data.targetWidth :
11848 0,
11849 offset = -2 * data.offset[ 0 ],
11850 newOverRight,
11851 newOverLeft;
11852
11853 if ( overLeft < 0 ) {
11854 newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
11855 if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
11856 position.left += myOffset + atOffset + offset;
11857 }
11858 }
11859 else if ( overRight > 0 ) {
11860 newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
11861 if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
11862 position.left += myOffset + atOffset + offset;
11863 }
11864 }
11865 },
11866 top: function( position, data ) {
11867 var within = data.within,
11868 withinOffset = within.offset.top + within.scrollTop,
11869 outerHeight = within.height,
11870 offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
11871 collisionPosTop = position.top - data.collisionPosition.marginTop,
11872 overTop = collisionPosTop - offsetTop,
11873 overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
11874 top = data.my[ 1 ] === "top",
11875 myOffset = top ?
11876 -data.elemHeight :
11877 data.my[ 1 ] === "bottom" ?
11878 data.elemHeight :
11879 0,
11880 atOffset = data.at[ 1 ] === "top" ?
11881 data.targetHeight :
11882 data.at[ 1 ] === "bottom" ?
11883 -data.targetHeight :
11884 0,
11885 offset = -2 * data.offset[ 1 ],
11886 newOverTop,
11887 newOverBottom;
11888 if ( overTop < 0 ) {
11889 newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
11890 if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) {
11891 position.top += myOffset + atOffset + offset;
11892 }
11893 }
11894 else if ( overBottom > 0 ) {
11895 newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
11896 if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) {
11897 position.top += myOffset + atOffset + offset;
11898 }
11899 }
11900 }
11901 },
11902 flipfit: {
11903 left: function() {
11904 $.ui.position.flip.left.apply( this, arguments );
11905 $.ui.position.fit.left.apply( this, arguments );
11906 },
11907 top: function() {
11908 $.ui.position.flip.top.apply( this, arguments );
11909 $.ui.position.fit.top.apply( this, arguments );
11910 }
11911 }
11912};
11913
11914// fraction support test
11915(function () {
11916 var testElement, testElementParent, testElementStyle, offsetLeft, i,
11917 body = document.getElementsByTagName( "body" )[ 0 ],
11918 div = document.createElement( "div" );
11919
11920 //Create a "fake body" for testing based on method used in jQuery.support
11921 testElement = document.createElement( body ? "div" : "body" );
11922 testElementStyle = {
11923 visibility: "hidden",
11924 width: 0,
11925 height: 0,
11926 border: 0,
11927 margin: 0,
11928 background: "none"
11929 };
11930 if ( body ) {
11931 $.extend( testElementStyle, {
11932 position: "absolute",
11933 left: "-1000px",
11934 top: "-1000px"
11935 });
11936 }
11937 for ( i in testElementStyle ) {
11938 testElement.style[ i ] = testElementStyle[ i ];
11939 }
11940 testElement.appendChild( div );
11941 testElementParent = body || document.documentElement;
11942 testElementParent.insertBefore( testElement, testElementParent.firstChild );
11943
11944 div.style.cssText = "position: absolute; left: 10.7432222px;";
11945
11946 offsetLeft = $( div ).offset().left;
11947 $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11;
11948
11949 testElement.innerHTML = "";
11950 testElementParent.removeChild( testElement );
11951})();
11952
11953// DEPRECATED
11954if ( $.uiBackCompat !== false ) {
11955 // offset option
11956 (function( $ ) {
11957 var _position = $.fn.position;
11958 $.fn.position = function( options ) {
11959 if ( !options || !options.offset ) {
11960 return _position.call( this, options );
11961 }
11962 var offset = options.offset.split( " " ),
11963 at = options.at.split( " " );
11964 if ( offset.length === 1 ) {
11965 offset[ 1 ] = offset[ 0 ];
11966 }
11967 if ( /^\d/.test( offset[ 0 ] ) ) {
11968 offset[ 0 ] = "+" + offset[ 0 ];
11969 }
11970 if ( /^\d/.test( offset[ 1 ] ) ) {
11971 offset[ 1 ] = "+" + offset[ 1 ];
11972 }
11973 if ( at.length === 1 ) {
11974 if ( /left|center|right/.test( at[ 0 ] ) ) {
11975 at[ 1 ] = "center";
11976 } else {
11977 at[ 1 ] = at[ 0 ];
11978 at[ 0 ] = "center";
11979 }
11980 }
11981 return _position.call( this, $.extend( options, {
11982 at: at[ 0 ] + offset[ 0 ] + " " + at[ 1 ] + offset[ 1 ],
11983 offset: undefined
11984 } ) );
11985 };
11986 }( jQuery ) );
11987}
11988
11989}( jQuery ) );
11990
11991(function( $, undefined ) {
11992
11993$.widget( "ui.progressbar", {
11994 version: "1.9.2",
11995 options: {
11996 value: 0,
11997 max: 100
11998 },
11999
12000 min: 0,
12001
12002 _create: function() {
12003 this.element
12004 .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
12005 .attr({
12006 role: "progressbar",
12007 "aria-valuemin": this.min,
12008 "aria-valuemax": this.options.max,
12009 "aria-valuenow": this._value()
12010 });
12011
12012 this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
12013 .appendTo( this.element );
12014
12015 this.oldValue = this._value();
12016 this._refreshValue();
12017 },
12018
12019 _destroy: function() {
12020 this.element
12021 .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
12022 .removeAttr( "role" )
12023 .removeAttr( "aria-valuemin" )
12024 .removeAttr( "aria-valuemax" )
12025 .removeAttr( "aria-valuenow" );
12026
12027 this.valueDiv.remove();
12028 },
12029
12030 value: function( newValue ) {
12031 if ( newValue === undefined ) {
12032 return this._value();
12033 }
12034
12035 this._setOption( "value", newValue );
12036 return this;
12037 },
12038
12039 _setOption: function( key, value ) {
12040 if ( key === "value" ) {
12041 this.options.value = value;
12042 this._refreshValue();
12043 if ( this._value() === this.options.max ) {
12044 this._trigger( "complete" );
12045 }
12046 }
12047
12048 this._super( key, value );
12049 },
12050
12051 _value: function() {
12052 var val = this.options.value;
12053 // normalize invalid value
12054 if ( typeof val !== "number" ) {
12055 val = 0;
12056 }
12057 return Math.min( this.options.max, Math.max( this.min, val ) );
12058 },
12059
12060 _percentage: function() {
12061 return 100 * this._value() / this.options.max;
12062 },
12063
12064 _refreshValue: function() {
12065 var value = this.value(),
12066 percentage = this._percentage();
12067
12068 if ( this.oldValue !== value ) {
12069 this.oldValue = value;
12070 this._trigger( "change" );
12071 }
12072
12073 this.valueDiv
12074 .toggle( value > this.min )
12075 .toggleClass( "ui-corner-right", value === this.options.max )
12076 .width( percentage.toFixed(0) + "%" );
12077 this.element.attr( "aria-valuenow", value );
12078 }
12079});
12080
12081})( jQuery );
12082
12083(function( $, undefined ) {
12084
12085// number of pages in a slider
12086// (how many times can you page up/down to go through the whole range)
12087var numPages = 5;
12088
12089$.widget( "ui.slider", $.ui.mouse, {
12090 version: "1.9.2",
12091 widgetEventPrefix: "slide",
12092
12093 options: {
12094 animate: false,
12095 distance: 0,
12096 max: 100,
12097 min: 0,
12098 orientation: "horizontal",
12099 range: false,
12100 step: 1,
12101 value: 0,
12102 values: null
12103 },
12104
12105 _create: function() {
12106 var i, handleCount,
12107 o = this.options,
12108 existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
12109 handle = "<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",
12110 handles = [];
12111
12112 this._keySliding = false;
12113 this._mouseSliding = false;
12114 this._animateOff = true;
12115 this._handleIndex = null;
12116 this._detectOrientation();
12117 this._mouseInit();
12118
12119 this.element
12120 .addClass( "ui-slider" +
12121 " ui-slider-" + this.orientation +
12122 " ui-widget" +
12123 " ui-widget-content" +
12124 " ui-corner-all" +
12125 ( o.disabled ? " ui-slider-disabled ui-disabled" : "" ) );
12126
12127 this.range = $([]);
12128
12129 if ( o.range ) {
12130 if ( o.range === true ) {
12131 if ( !o.values ) {
12132 o.values = [ this._valueMin(), this._valueMin() ];
12133 }
12134 if ( o.values.length && o.values.length !== 2 ) {
12135 o.values = [ o.values[0], o.values[0] ];
12136 }
12137 }
12138
12139 this.range = $( "<div></div>" )
12140 .appendTo( this.element )
12141 .addClass( "ui-slider-range" +
12142 // note: this isn't the most fittingly semantic framework class for this element,
12143 // but worked best visually with a variety of themes
12144 " ui-widget-header" +
12145 ( ( o.range === "min" || o.range === "max" ) ? " ui-slider-range-" + o.range : "" ) );
12146 }
12147
12148 handleCount = ( o.values && o.values.length ) || 1;
12149
12150 for ( i = existingHandles.length; i < handleCount; i++ ) {
12151 handles.push( handle );
12152 }
12153
12154 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
12155
12156 this.handle = this.handles.eq( 0 );
12157
12158 this.handles.add( this.range ).filter( "a" )
12159 .click(function( event ) {
12160 event.preventDefault();
12161 })
12162 .mouseenter(function() {
12163 if ( !o.disabled ) {
12164 $( this ).addClass( "ui-state-hover" );
12165 }
12166 })
12167 .mouseleave(function() {
12168 $( this ).removeClass( "ui-state-hover" );
12169 })
12170 .focus(function() {
12171 if ( !o.disabled ) {
12172 $( ".ui-slider .ui-state-focus" ).removeClass( "ui-state-focus" );
12173 $( this ).addClass( "ui-state-focus" );
12174 } else {
12175 $( this ).blur();
12176 }
12177 })
12178 .blur(function() {
12179 $( this ).removeClass( "ui-state-focus" );
12180 });
12181
12182 this.handles.each(function( i ) {
12183 $( this ).data( "ui-slider-handle-index", i );
12184 });
12185
12186 this._on( this.handles, {
12187 keydown: function( event ) {
12188 var allowed, curVal, newVal, step,
12189 index = $( event.target ).data( "ui-slider-handle-index" );
12190
12191 switch ( event.keyCode ) {
12192 case $.ui.keyCode.HOME:
12193 case $.ui.keyCode.END:
12194 case $.ui.keyCode.PAGE_UP:
12195 case $.ui.keyCode.PAGE_DOWN:
12196 case $.ui.keyCode.UP:
12197 case $.ui.keyCode.RIGHT:
12198 case $.ui.keyCode.DOWN:
12199 case $.ui.keyCode.LEFT:
12200 event.preventDefault();
12201 if ( !this._keySliding ) {
12202 this._keySliding = true;
12203 $( event.target ).addClass( "ui-state-active" );
12204 allowed = this._start( event, index );
12205 if ( allowed === false ) {
12206 return;
12207 }
12208 }
12209 break;
12210 }
12211
12212 step = this.options.step;
12213 if ( this.options.values && this.options.values.length ) {
12214 curVal = newVal = this.values( index );
12215 } else {
12216 curVal = newVal = this.value();
12217 }
12218
12219 switch ( event.keyCode ) {
12220 case $.ui.keyCode.HOME:
12221 newVal = this._valueMin();
12222 break;
12223 case $.ui.keyCode.END:
12224 newVal = this._valueMax();
12225 break;
12226 case $.ui.keyCode.PAGE_UP:
12227 newVal = this._trimAlignValue( curVal + ( (this._valueMax() - this._valueMin()) / numPages ) );
12228 break;
12229 case $.ui.keyCode.PAGE_DOWN:
12230 newVal = this._trimAlignValue( curVal - ( (this._valueMax() - this._valueMin()) / numPages ) );
12231 break;
12232 case $.ui.keyCode.UP:
12233 case $.ui.keyCode.RIGHT:
12234 if ( curVal === this._valueMax() ) {
12235 return;
12236 }
12237 newVal = this._trimAlignValue( curVal + step );
12238 break;
12239 case $.ui.keyCode.DOWN:
12240 case $.ui.keyCode.LEFT:
12241 if ( curVal === this._valueMin() ) {
12242 return;
12243 }
12244 newVal = this._trimAlignValue( curVal - step );
12245 break;
12246 }
12247
12248 this._slide( event, index, newVal );
12249 },
12250 keyup: function( event ) {
12251 var index = $( event.target ).data( "ui-slider-handle-index" );
12252
12253 if ( this._keySliding ) {
12254 this._keySliding = false;
12255 this._stop( event, index );
12256 this._change( event, index );
12257 $( event.target ).removeClass( "ui-state-active" );
12258 }
12259 }
12260 });
12261
12262 this._refreshValue();
12263
12264 this._animateOff = false;
12265 },
12266
12267 _destroy: function() {
12268 this.handles.remove();
12269 this.range.remove();
12270
12271 this.element
12272 .removeClass( "ui-slider" +
12273 " ui-slider-horizontal" +
12274 " ui-slider-vertical" +
12275 " ui-slider-disabled" +
12276 " ui-widget" +
12277 " ui-widget-content" +
12278 " ui-corner-all" );
12279
12280 this._mouseDestroy();
12281 },
12282
12283 _mouseCapture: function( event ) {
12284 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
12285 that = this,
12286 o = this.options;
12287
12288 if ( o.disabled ) {
12289 return false;
12290 }
12291
12292 this.elementSize = {
12293 width: this.element.outerWidth(),
12294 height: this.element.outerHeight()
12295 };
12296 this.elementOffset = this.element.offset();
12297
12298 position = { x: event.pageX, y: event.pageY };
12299 normValue = this._normValueFromMouse( position );
12300 distance = this._valueMax() - this._valueMin() + 1;
12301 this.handles.each(function( i ) {
12302 var thisDistance = Math.abs( normValue - that.values(i) );
12303 if ( distance > thisDistance ) {
12304 distance = thisDistance;
12305 closestHandle = $( this );
12306 index = i;
12307 }
12308 });
12309
12310 // workaround for bug #3736 (if both handles of a range are at 0,
12311 // the first is always used as the one with least distance,
12312 // and moving it is obviously prevented by preventing negative ranges)
12313 if( o.range === true && this.values(1) === o.min ) {
12314 index += 1;
12315 closestHandle = $( this.handles[index] );
12316 }
12317
12318 allowed = this._start( event, index );
12319 if ( allowed === false ) {
12320 return false;
12321 }
12322 this._mouseSliding = true;
12323
12324 this._handleIndex = index;
12325
12326 closestHandle
12327 .addClass( "ui-state-active" )
12328 .focus();
12329
12330 offset = closestHandle.offset();
12331 mouseOverHandle = !$( event.target ).parents().andSelf().is( ".ui-slider-handle" );
12332 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
12333 left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
12334 top: event.pageY - offset.top -
12335 ( closestHandle.height() / 2 ) -
12336 ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
12337 ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
12338 ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
12339 };
12340
12341 if ( !this.handles.hasClass( "ui-state-hover" ) ) {
12342 this._slide( event, index, normValue );
12343 }
12344 this._animateOff = true;
12345 return true;
12346 },
12347
12348 _mouseStart: function() {
12349 return true;
12350 },
12351
12352 _mouseDrag: function( event ) {
12353 var position = { x: event.pageX, y: event.pageY },
12354 normValue = this._normValueFromMouse( position );
12355
12356 this._slide( event, this._handleIndex, normValue );
12357
12358 return false;
12359 },
12360
12361 _mouseStop: function( event ) {
12362 this.handles.removeClass( "ui-state-active" );
12363 this._mouseSliding = false;
12364
12365 this._stop( event, this._handleIndex );
12366 this._change( event, this._handleIndex );
12367
12368 this._handleIndex = null;
12369 this._clickOffset = null;
12370 this._animateOff = false;
12371
12372 return false;
12373 },
12374
12375 _detectOrientation: function() {
12376 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
12377 },
12378
12379 _normValueFromMouse: function( position ) {
12380 var pixelTotal,
12381 pixelMouse,
12382 percentMouse,
12383 valueTotal,
12384 valueMouse;
12385
12386 if ( this.orientation === "horizontal" ) {
12387 pixelTotal = this.elementSize.width;
12388 pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
12389 } else {
12390 pixelTotal = this.elementSize.height;
12391 pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
12392 }
12393
12394 percentMouse = ( pixelMouse / pixelTotal );
12395 if ( percentMouse > 1 ) {
12396 percentMouse = 1;
12397 }
12398 if ( percentMouse < 0 ) {
12399 percentMouse = 0;
12400 }
12401 if ( this.orientation === "vertical" ) {
12402 percentMouse = 1 - percentMouse;
12403 }
12404
12405 valueTotal = this._valueMax() - this._valueMin();
12406 valueMouse = this._valueMin() + percentMouse * valueTotal;
12407
12408 return this._trimAlignValue( valueMouse );
12409 },
12410
12411 _start: function( event, index ) {
12412 var uiHash = {
12413 handle: this.handles[ index ],
12414 value: this.value()
12415 };
12416 if ( this.options.values && this.options.values.length ) {
12417 uiHash.value = this.values( index );
12418 uiHash.values = this.values();
12419 }
12420 return this._trigger( "start", event, uiHash );
12421 },
12422
12423 _slide: function( event, index, newVal ) {
12424 var otherVal,
12425 newValues,
12426 allowed;
12427
12428 if ( this.options.values && this.options.values.length ) {
12429 otherVal = this.values( index ? 0 : 1 );
12430
12431 if ( ( this.options.values.length === 2 && this.options.range === true ) &&
12432 ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
12433 ) {
12434 newVal = otherVal;
12435 }
12436
12437 if ( newVal !== this.values( index ) ) {
12438 newValues = this.values();
12439 newValues[ index ] = newVal;
12440 // A slide can be canceled by returning false from the slide callback
12441 allowed = this._trigger( "slide", event, {
12442 handle: this.handles[ index ],
12443 value: newVal,
12444 values: newValues
12445 } );
12446 otherVal = this.values( index ? 0 : 1 );
12447 if ( allowed !== false ) {
12448 this.values( index, newVal, true );
12449 }
12450 }
12451 } else {
12452 if ( newVal !== this.value() ) {
12453 // A slide can be canceled by returning false from the slide callback
12454 allowed = this._trigger( "slide", event, {
12455 handle: this.handles[ index ],
12456 value: newVal
12457 } );
12458 if ( allowed !== false ) {
12459 this.value( newVal );
12460 }
12461 }
12462 }
12463 },
12464
12465 _stop: function( event, index ) {
12466 var uiHash = {
12467 handle: this.handles[ index ],
12468 value: this.value()
12469 };
12470 if ( this.options.values && this.options.values.length ) {
12471 uiHash.value = this.values( index );
12472 uiHash.values = this.values();
12473 }
12474
12475 this._trigger( "stop", event, uiHash );
12476 },
12477
12478 _change: function( event, index ) {
12479 if ( !this._keySliding && !this._mouseSliding ) {
12480 var uiHash = {
12481 handle: this.handles[ index ],
12482 value: this.value()
12483 };
12484 if ( this.options.values && this.options.values.length ) {
12485 uiHash.value = this.values( index );
12486 uiHash.values = this.values();
12487 }
12488
12489 this._trigger( "change", event, uiHash );
12490 }
12491 },
12492
12493 value: function( newValue ) {
12494 if ( arguments.length ) {
12495 this.options.value = this._trimAlignValue( newValue );
12496 this._refreshValue();
12497 this._change( null, 0 );
12498 return;
12499 }
12500
12501 return this._value();
12502 },
12503
12504 values: function( index, newValue ) {
12505 var vals,
12506 newValues,
12507 i;
12508
12509 if ( arguments.length > 1 ) {
12510 this.options.values[ index ] = this._trimAlignValue( newValue );
12511 this._refreshValue();
12512 this._change( null, index );
12513 return;
12514 }
12515
12516 if ( arguments.length ) {
12517 if ( $.isArray( arguments[ 0 ] ) ) {
12518 vals = this.options.values;
12519 newValues = arguments[ 0 ];
12520 for ( i = 0; i < vals.length; i += 1 ) {
12521 vals[ i ] = this._trimAlignValue( newValues[ i ] );
12522 this._change( null, i );
12523 }
12524 this._refreshValue();
12525 } else {
12526 if ( this.options.values && this.options.values.length ) {
12527 return this._values( index );
12528 } else {
12529 return this.value();
12530 }
12531 }
12532 } else {
12533 return this._values();
12534 }
12535 },
12536
12537 _setOption: function( key, value ) {
12538 var i,
12539 valsLength = 0;
12540
12541 if ( $.isArray( this.options.values ) ) {
12542 valsLength = this.options.values.length;
12543 }
12544
12545 $.Widget.prototype._setOption.apply( this, arguments );
12546
12547 switch ( key ) {
12548 case "disabled":
12549 if ( value ) {
12550 this.handles.filter( ".ui-state-focus" ).blur();
12551 this.handles.removeClass( "ui-state-hover" );
12552 this.handles.prop( "disabled", true );
12553 this.element.addClass( "ui-disabled" );
12554 } else {
12555 this.handles.prop( "disabled", false );
12556 this.element.removeClass( "ui-disabled" );
12557 }
12558 break;
12559 case "orientation":
12560 this._detectOrientation();
12561 this.element
12562 .removeClass( "ui-slider-horizontal ui-slider-vertical" )
12563 .addClass( "ui-slider-" + this.orientation );
12564 this._refreshValue();
12565 break;
12566 case "value":
12567 this._animateOff = true;
12568 this._refreshValue();
12569 this._change( null, 0 );
12570 this._animateOff = false;
12571 break;
12572 case "values":
12573 this._animateOff = true;
12574 this._refreshValue();
12575 for ( i = 0; i < valsLength; i += 1 ) {
12576 this._change( null, i );
12577 }
12578 this._animateOff = false;
12579 break;
12580 case "min":
12581 case "max":
12582 this._animateOff = true;
12583 this._refreshValue();
12584 this._animateOff = false;
12585 break;
12586 }
12587 },
12588
12589 //internal value getter
12590 // _value() returns value trimmed by min and max, aligned by step
12591 _value: function() {
12592 var val = this.options.value;
12593 val = this._trimAlignValue( val );
12594
12595 return val;
12596 },
12597
12598 //internal values getter
12599 // _values() returns array of values trimmed by min and max, aligned by step
12600 // _values( index ) returns single value trimmed by min and max, aligned by step
12601 _values: function( index ) {
12602 var val,
12603 vals,
12604 i;
12605
12606 if ( arguments.length ) {
12607 val = this.options.values[ index ];
12608 val = this._trimAlignValue( val );
12609
12610 return val;
12611 } else {
12612 // .slice() creates a copy of the array
12613 // this copy gets trimmed by min and max and then returned
12614 vals = this.options.values.slice();
12615 for ( i = 0; i < vals.length; i+= 1) {
12616 vals[ i ] = this._trimAlignValue( vals[ i ] );
12617 }
12618
12619 return vals;
12620 }
12621 },
12622
12623 // returns the step-aligned value that val is closest to, between (inclusive) min and max
12624 _trimAlignValue: function( val ) {
12625 if ( val <= this._valueMin() ) {
12626 return this._valueMin();
12627 }
12628 if ( val >= this._valueMax() ) {
12629 return this._valueMax();
12630 }
12631 var step = ( this.options.step > 0 ) ? this.options.step : 1,
12632 valModStep = (val - this._valueMin()) % step,
12633 alignValue = val - valModStep;
12634
12635 if ( Math.abs(valModStep) * 2 >= step ) {
12636 alignValue += ( valModStep > 0 ) ? step : ( -step );
12637 }
12638
12639 // Since JavaScript has problems with large floats, round
12640 // the final value to 5 digits after the decimal point (see #4124)
12641 return parseFloat( alignValue.toFixed(5) );
12642 },
12643
12644 _valueMin: function() {
12645 return this.options.min;
12646 },
12647
12648 _valueMax: function() {
12649 return this.options.max;
12650 },
12651
12652 _refreshValue: function() {
12653 var lastValPercent, valPercent, value, valueMin, valueMax,
12654 oRange = this.options.range,
12655 o = this.options,
12656 that = this,
12657 animate = ( !this._animateOff ) ? o.animate : false,
12658 _set = {};
12659
12660 if ( this.options.values && this.options.values.length ) {
12661 this.handles.each(function( i ) {
12662 valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
12663 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
12664 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
12665 if ( that.options.range === true ) {
12666 if ( that.orientation === "horizontal" ) {
12667 if ( i === 0 ) {
12668 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
12669 }
12670 if ( i === 1 ) {
12671 that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
12672 }
12673 } else {
12674 if ( i === 0 ) {
12675 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
12676 }
12677 if ( i === 1 ) {
12678 that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
12679 }
12680 }
12681 }
12682 lastValPercent = valPercent;
12683 });
12684 } else {
12685 value = this.value();
12686 valueMin = this._valueMin();
12687 valueMax = this._valueMax();
12688 valPercent = ( valueMax !== valueMin ) ?
12689 ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
12690 0;
12691 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
12692 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
12693
12694 if ( oRange === "min" && this.orientation === "horizontal" ) {
12695 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
12696 }
12697 if ( oRange === "max" && this.orientation === "horizontal" ) {
12698 this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
12699 }
12700 if ( oRange === "min" && this.orientation === "vertical" ) {
12701 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
12702 }
12703 if ( oRange === "max" && this.orientation === "vertical" ) {
12704 this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
12705 }
12706 }
12707 }
12708
12709});
12710
12711}(jQuery));
12712
12713(function( $ ) {
12714
12715function modifier( fn ) {
12716 return function() {
12717 var previous = this.element.val();
12718 fn.apply( this, arguments );
12719 this._refresh();
12720 if ( previous !== this.element.val() ) {
12721 this._trigger( "change" );
12722 }
12723 };
12724}
12725
12726$.widget( "ui.spinner", {
12727 version: "1.9.2",
12728 defaultElement: "<input>",
12729 widgetEventPrefix: "spin",
12730 options: {
12731 culture: null,
12732 icons: {
12733 down: "ui-icon-triangle-1-s",
12734 up: "ui-icon-triangle-1-n"
12735 },
12736 incremental: true,
12737 max: null,
12738 min: null,
12739 numberFormat: null,
12740 page: 10,
12741 step: 1,
12742
12743 change: null,
12744 spin: null,
12745 start: null,
12746 stop: null
12747 },
12748
12749 _create: function() {
12750 // handle string values that need to be parsed
12751 this._setOption( "max", this.options.max );
12752 this._setOption( "min", this.options.min );
12753 this._setOption( "step", this.options.step );
12754
12755 // format the value, but don't constrain
12756 this._value( this.element.val(), true );
12757
12758 this._draw();
12759 this._on( this._events );
12760 this._refresh();
12761
12762 // turning off autocomplete prevents the browser from remembering the
12763 // value when navigating through history, so we re-enable autocomplete
12764 // if the page is unloaded before the widget is destroyed. #7790
12765 this._on( this.window, {
12766 beforeunload: function() {
12767 this.element.removeAttr( "autocomplete" );
12768 }
12769 });
12770 },
12771
12772 _getCreateOptions: function() {
12773 var options = {},
12774 element = this.element;
12775
12776 $.each( [ "min", "max", "step" ], function( i, option ) {
12777 var value = element.attr( option );
12778 if ( value !== undefined && value.length ) {
12779 options[ option ] = value;
12780 }
12781 });
12782
12783 return options;
12784 },
12785
12786 _events: {
12787 keydown: function( event ) {
12788 if ( this._start( event ) && this._keydown( event ) ) {
12789 event.preventDefault();
12790 }
12791 },
12792 keyup: "_stop",
12793 focus: function() {
12794 this.previous = this.element.val();
12795 },
12796 blur: function( event ) {
12797 if ( this.cancelBlur ) {
12798 delete this.cancelBlur;
12799 return;
12800 }
12801
12802 this._refresh();
12803 if ( this.previous !== this.element.val() ) {
12804 this._trigger( "change", event );
12805 }
12806 },
12807 mousewheel: function( event, delta ) {
12808 if ( !delta ) {
12809 return;
12810 }
12811 if ( !this.spinning && !this._start( event ) ) {
12812 return false;
12813 }
12814
12815 this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
12816 clearTimeout( this.mousewheelTimer );
12817 this.mousewheelTimer = this._delay(function() {
12818 if ( this.spinning ) {
12819 this._stop( event );
12820 }
12821 }, 100 );
12822 event.preventDefault();
12823 },
12824 "mousedown .ui-spinner-button": function( event ) {
12825 var previous;
12826
12827 // We never want the buttons to have focus; whenever the user is
12828 // interacting with the spinner, the focus should be on the input.
12829 // If the input is focused then this.previous is properly set from
12830 // when the input first received focus. If the input is not focused
12831 // then we need to set this.previous based on the value before spinning.
12832 previous = this.element[0] === this.document[0].activeElement ?
12833 this.previous : this.element.val();
12834 function checkFocus() {
12835 var isActive = this.element[0] === this.document[0].activeElement;
12836 if ( !isActive ) {
12837 this.element.focus();
12838 this.previous = previous;
12839 // support: IE
12840 // IE sets focus asynchronously, so we need to check if focus
12841 // moved off of the input because the user clicked on the button.
12842 this._delay(function() {
12843 this.previous = previous;
12844 });
12845 }
12846 }
12847
12848 // ensure focus is on (or stays on) the text field
12849 event.preventDefault();
12850 checkFocus.call( this );
12851
12852 // support: IE
12853 // IE doesn't prevent moving focus even with event.preventDefault()
12854 // so we set a flag to know when we should ignore the blur event
12855 // and check (again) if focus moved off of the input.
12856 this.cancelBlur = true;
12857 this._delay(function() {
12858 delete this.cancelBlur;
12859 checkFocus.call( this );
12860 });
12861
12862 if ( this._start( event ) === false ) {
12863 return;
12864 }
12865
12866 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
12867 },
12868 "mouseup .ui-spinner-button": "_stop",
12869 "mouseenter .ui-spinner-button": function( event ) {
12870 // button will add ui-state-active if mouse was down while mouseleave and kept down
12871 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
12872 return;
12873 }
12874
12875 if ( this._start( event ) === false ) {
12876 return false;
12877 }
12878 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
12879 },
12880 // TODO: do we really want to consider this a stop?
12881 // shouldn't we just stop the repeater and wait until mouseup before
12882 // we trigger the stop event?
12883 "mouseleave .ui-spinner-button": "_stop"
12884 },
12885
12886 _draw: function() {
12887 var uiSpinner = this.uiSpinner = this.element
12888 .addClass( "ui-spinner-input" )
12889 .attr( "autocomplete", "off" )
12890 .wrap( this._uiSpinnerHtml() )
12891 .parent()
12892 // add buttons
12893 .append( this._buttonHtml() );
12894
12895 this.element.attr( "role", "spinbutton" );
12896
12897 // button bindings
12898 this.buttons = uiSpinner.find( ".ui-spinner-button" )
12899 .attr( "tabIndex", -1 )
12900 .button()
12901 .removeClass( "ui-corner-all" );
12902
12903 // IE 6 doesn't understand height: 50% for the buttons
12904 // unless the wrapper has an explicit height
12905 if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&
12906 uiSpinner.height() > 0 ) {
12907 uiSpinner.height( uiSpinner.height() );
12908 }
12909
12910 // disable spinner if element was already disabled
12911 if ( this.options.disabled ) {
12912 this.disable();
12913 }
12914 },
12915
12916 _keydown: function( event ) {
12917 var options = this.options,
12918 keyCode = $.ui.keyCode;
12919
12920 switch ( event.keyCode ) {
12921 case keyCode.UP:
12922 this._repeat( null, 1, event );
12923 return true;
12924 case keyCode.DOWN:
12925 this._repeat( null, -1, event );
12926 return true;
12927 case keyCode.PAGE_UP:
12928 this._repeat( null, options.page, event );
12929 return true;
12930 case keyCode.PAGE_DOWN:
12931 this._repeat( null, -options.page, event );
12932 return true;
12933 }
12934
12935 return false;
12936 },
12937
12938 _uiSpinnerHtml: function() {
12939 return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>";
12940 },
12941
12942 _buttonHtml: function() {
12943 return "" +
12944 "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" +
12945 "<span class='ui-icon " + this.options.icons.up + "'>&#9650;</span>" +
12946 "</a>" +
12947 "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" +
12948 "<span class='ui-icon " + this.options.icons.down + "'>&#9660;</span>" +
12949 "</a>";
12950 },
12951
12952 _start: function( event ) {
12953 if ( !this.spinning && this._trigger( "start", event ) === false ) {
12954 return false;
12955 }
12956
12957 if ( !this.counter ) {
12958 this.counter = 1;
12959 }
12960 this.spinning = true;
12961 return true;
12962 },
12963
12964 _repeat: function( i, steps, event ) {
12965 i = i || 500;
12966
12967 clearTimeout( this.timer );
12968 this.timer = this._delay(function() {
12969 this._repeat( 40, steps, event );
12970 }, i );
12971
12972 this._spin( steps * this.options.step, event );
12973 },
12974
12975 _spin: function( step, event ) {
12976 var value = this.value() || 0;
12977
12978 if ( !this.counter ) {
12979 this.counter = 1;
12980 }
12981
12982 value = this._adjustValue( value + step * this._increment( this.counter ) );
12983
12984 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) {
12985 this._value( value );
12986 this.counter++;
12987 }
12988 },
12989
12990 _increment: function( i ) {
12991 var incremental = this.options.incremental;
12992
12993 if ( incremental ) {
12994 return $.isFunction( incremental ) ?
12995 incremental( i ) :
12996 Math.floor( i*i*i/50000 - i*i/500 + 17*i/200 + 1 );
12997 }
12998
12999 return 1;
13000 },
13001
13002 _precision: function() {
13003 var precision = this._precisionOf( this.options.step );
13004 if ( this.options.min !== null ) {
13005 precision = Math.max( precision, this._precisionOf( this.options.min ) );
13006 }
13007 return precision;
13008 },
13009
13010 _precisionOf: function( num ) {
13011 var str = num.toString(),
13012 decimal = str.indexOf( "." );
13013 return decimal === -1 ? 0 : str.length - decimal - 1;
13014 },
13015
13016 _adjustValue: function( value ) {
13017 var base, aboveMin,
13018 options = this.options;
13019
13020 // make sure we're at a valid step
13021 // - find out where we are relative to the base (min or 0)
13022 base = options.min !== null ? options.min : 0;
13023 aboveMin = value - base;
13024 // - round to the nearest step
13025 aboveMin = Math.round(aboveMin / options.step) * options.step;
13026 // - rounding is based on 0, so adjust back to our base
13027 value = base + aboveMin;
13028
13029 // fix precision from bad JS floating point math
13030 value = parseFloat( value.toFixed( this._precision() ) );
13031
13032 // clamp the value
13033 if ( options.max !== null && value > options.max) {
13034 return options.max;
13035 }
13036 if ( options.min !== null && value < options.min ) {
13037 return options.min;
13038 }
13039
13040 return value;
13041 },
13042
13043 _stop: function( event ) {
13044 if ( !this.spinning ) {
13045 return;
13046 }
13047
13048 clearTimeout( this.timer );
13049 clearTimeout( this.mousewheelTimer );
13050 this.counter = 0;
13051 this.spinning = false;
13052 this._trigger( "stop", event );
13053 },
13054
13055 _setOption: function( key, value ) {
13056 if ( key === "culture" || key === "numberFormat" ) {
13057 var prevValue = this._parse( this.element.val() );
13058 this.options[ key ] = value;
13059 this.element.val( this._format( prevValue ) );
13060 return;
13061 }
13062
13063 if ( key === "max" || key === "min" || key === "step" ) {
13064 if ( typeof value === "string" ) {
13065 value = this._parse( value );
13066 }
13067 }
13068
13069 this._super( key, value );
13070
13071 if ( key === "disabled" ) {
13072 if ( value ) {
13073 this.element.prop( "disabled", true );
13074 this.buttons.button( "disable" );
13075 } else {
13076 this.element.prop( "disabled", false );
13077 this.buttons.button( "enable" );
13078 }
13079 }
13080 },
13081
13082 _setOptions: modifier(function( options ) {
13083 this._super( options );
13084 this._value( this.element.val() );
13085 }),
13086
13087 _parse: function( val ) {
13088 if ( typeof val === "string" && val !== "" ) {
13089 val = window.Globalize && this.options.numberFormat ?
13090 Globalize.parseFloat( val, 10, this.options.culture ) : +val;
13091 }
13092 return val === "" || isNaN( val ) ? null : val;
13093 },
13094
13095 _format: function( value ) {
13096 if ( value === "" ) {
13097 return "";
13098 }
13099 return window.Globalize && this.options.numberFormat ?
13100 Globalize.format( value, this.options.numberFormat, this.options.culture ) :
13101 value;
13102 },
13103
13104 _refresh: function() {
13105 this.element.attr({
13106 "aria-valuemin": this.options.min,
13107 "aria-valuemax": this.options.max,
13108 // TODO: what should we do with values that can't be parsed?
13109 "aria-valuenow": this._parse( this.element.val() )
13110 });
13111 },
13112
13113 // update the value without triggering change
13114 _value: function( value, allowAny ) {
13115 var parsed;
13116 if ( value !== "" ) {
13117 parsed = this._parse( value );
13118 if ( parsed !== null ) {
13119 if ( !allowAny ) {
13120 parsed = this._adjustValue( parsed );
13121 }
13122 value = this._format( parsed );
13123 }
13124 }
13125 this.element.val( value );
13126 this._refresh();
13127 },
13128
13129 _destroy: function() {
13130 this.element
13131 .removeClass( "ui-spinner-input" )
13132 .prop( "disabled", false )
13133 .removeAttr( "autocomplete" )
13134 .removeAttr( "role" )
13135 .removeAttr( "aria-valuemin" )
13136 .removeAttr( "aria-valuemax" )
13137 .removeAttr( "aria-valuenow" );
13138 this.uiSpinner.replaceWith( this.element );
13139 },
13140
13141 stepUp: modifier(function( steps ) {
13142 this._stepUp( steps );
13143 }),
13144 _stepUp: function( steps ) {
13145 this._spin( (steps || 1) * this.options.step );
13146 },
13147
13148 stepDown: modifier(function( steps ) {
13149 this._stepDown( steps );
13150 }),
13151 _stepDown: function( steps ) {
13152 this._spin( (steps || 1) * -this.options.step );
13153 },
13154
13155 pageUp: modifier(function( pages ) {
13156 this._stepUp( (pages || 1) * this.options.page );
13157 }),
13158
13159 pageDown: modifier(function( pages ) {
13160 this._stepDown( (pages || 1) * this.options.page );
13161 }),
13162
13163 value: function( newVal ) {
13164 if ( !arguments.length ) {
13165 return this._parse( this.element.val() );
13166 }
13167 modifier( this._value ).call( this, newVal );
13168 },
13169
13170 widget: function() {
13171 return this.uiSpinner;
13172 }
13173});
13174
13175}( jQuery ) );
13176
13177(function( $, undefined ) {
13178
13179var tabId = 0,
13180 rhash = /#.*$/;
13181
13182function getNextTabId() {
13183 return ++tabId;
13184}
13185
13186function isLocal( anchor ) {
13187 return anchor.hash.length > 1 &&
13188 anchor.href.replace( rhash, "" ) ===
13189 location.href.replace( rhash, "" )
13190 // support: Safari 5.1
13191 // Safari 5.1 doesn't encode spaces in window.location
13192 // but it does encode spaces from anchors (#8777)
13193 .replace( /\s/g, "%20" );
13194}
13195
13196$.widget( "ui.tabs", {
13197 version: "1.9.2",
13198 delay: 300,
13199 options: {
13200 active: null,
13201 collapsible: false,
13202 event: "click",
13203 heightStyle: "content",
13204 hide: null,
13205 show: null,
13206
13207 // callbacks
13208 activate: null,
13209 beforeActivate: null,
13210 beforeLoad: null,
13211 load: null
13212 },
13213
13214 _create: function() {
13215 var that = this,
13216 options = this.options,
13217 active = options.active,
13218 locationHash = location.hash.substring( 1 );
13219
13220 this.running = false;
13221
13222 this.element
13223 .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" )
13224 .toggleClass( "ui-tabs-collapsible", options.collapsible )
13225 // Prevent users from focusing disabled tabs via click
13226 .delegate( ".ui-tabs-nav > li", "mousedown" + this.eventNamespace, function( event ) {
13227 if ( $( this ).is( ".ui-state-disabled" ) ) {
13228 event.preventDefault();
13229 }
13230 })
13231 // support: IE <9
13232 // Preventing the default action in mousedown doesn't prevent IE
13233 // from focusing the element, so if the anchor gets focused, blur.
13234 // We don't have to worry about focusing the previously focused
13235 // element since clicking on a non-focusable element should focus
13236 // the body anyway.
13237 .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() {
13238 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
13239 this.blur();
13240 }
13241 });
13242
13243 this._processTabs();
13244
13245 if ( active === null ) {
13246 // check the fragment identifier in the URL
13247 if ( locationHash ) {
13248 this.tabs.each(function( i, tab ) {
13249 if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
13250 active = i;
13251 return false;
13252 }
13253 });
13254 }
13255
13256 // check for a tab marked active via a class
13257 if ( active === null ) {
13258 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
13259 }
13260
13261 // no active tab, set to false
13262 if ( active === null || active === -1 ) {
13263 active = this.tabs.length ? 0 : false;
13264 }
13265 }
13266
13267 // handle numbers: negative, out of range
13268 if ( active !== false ) {
13269 active = this.tabs.index( this.tabs.eq( active ) );
13270 if ( active === -1 ) {
13271 active = options.collapsible ? false : 0;
13272 }
13273 }
13274 options.active = active;
13275
13276 // don't allow collapsible: false and active: false
13277 if ( !options.collapsible && options.active === false && this.anchors.length ) {
13278 options.active = 0;
13279 }
13280
13281 // Take disabling tabs via class attribute from HTML
13282 // into account and update option properly.
13283 if ( $.isArray( options.disabled ) ) {
13284 options.disabled = $.unique( options.disabled.concat(
13285 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
13286 return that.tabs.index( li );
13287 })
13288 ) ).sort();
13289 }
13290
13291 // check for length avoids error when initializing empty list
13292 if ( this.options.active !== false && this.anchors.length ) {
13293 this.active = this._findActive( this.options.active );
13294 } else {
13295 this.active = $();
13296 }
13297
13298 this._refresh();
13299
13300 if ( this.active.length ) {
13301 this.load( options.active );
13302 }
13303 },
13304
13305 _getCreateEventData: function() {
13306 return {
13307 tab: this.active,
13308 panel: !this.active.length ? $() : this._getPanelForTab( this.active )
13309 };
13310 },
13311
13312 _tabKeydown: function( event ) {
13313 var focusedTab = $( this.document[0].activeElement ).closest( "li" ),
13314 selectedIndex = this.tabs.index( focusedTab ),
13315 goingForward = true;
13316
13317 if ( this._handlePageNav( event ) ) {
13318 return;
13319 }
13320
13321 switch ( event.keyCode ) {
13322 case $.ui.keyCode.RIGHT:
13323 case $.ui.keyCode.DOWN:
13324 selectedIndex++;
13325 break;
13326 case $.ui.keyCode.UP:
13327 case $.ui.keyCode.LEFT:
13328 goingForward = false;
13329 selectedIndex--;
13330 break;
13331 case $.ui.keyCode.END:
13332 selectedIndex = this.anchors.length - 1;
13333 break;
13334 case $.ui.keyCode.HOME:
13335 selectedIndex = 0;
13336 break;
13337 case $.ui.keyCode.SPACE:
13338 // Activate only, no collapsing
13339 event.preventDefault();
13340 clearTimeout( this.activating );
13341 this._activate( selectedIndex );
13342 return;
13343 case $.ui.keyCode.ENTER:
13344 // Toggle (cancel delayed activation, allow collapsing)
13345 event.preventDefault();
13346 clearTimeout( this.activating );
13347 // Determine if we should collapse or activate
13348 this._activate( selectedIndex === this.options.active ? false : selectedIndex );
13349 return;
13350 default:
13351 return;
13352 }
13353
13354 // Focus the appropriate tab, based on which key was pressed
13355 event.preventDefault();
13356 clearTimeout( this.activating );
13357 selectedIndex = this._focusNextTab( selectedIndex, goingForward );
13358
13359 // Navigating with control key will prevent automatic activation
13360 if ( !event.ctrlKey ) {
13361 // Update aria-selected immediately so that AT think the tab is already selected.
13362 // Otherwise AT may confuse the user by stating that they need to activate the tab,
13363 // but the tab will already be activated by the time the announcement finishes.
13364 focusedTab.attr( "aria-selected", "false" );
13365 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
13366
13367 this.activating = this._delay(function() {
13368 this.option( "active", selectedIndex );
13369 }, this.delay );
13370 }
13371 },
13372
13373 _panelKeydown: function( event ) {
13374 if ( this._handlePageNav( event ) ) {
13375 return;
13376 }
13377
13378 // Ctrl+up moves focus to the current tab
13379 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
13380 event.preventDefault();
13381 this.active.focus();
13382 }
13383 },
13384
13385 // Alt+page up/down moves focus to the previous/next tab (and activates)
13386 _handlePageNav: function( event ) {
13387 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
13388 this._activate( this._focusNextTab( this.options.active - 1, false ) );
13389 return true;
13390 }
13391 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
13392 this._activate( this._focusNextTab( this.options.active + 1, true ) );
13393 return true;
13394 }
13395 },
13396
13397 _findNextTab: function( index, goingForward ) {
13398 var lastTabIndex = this.tabs.length - 1;
13399
13400 function constrain() {
13401 if ( index > lastTabIndex ) {
13402 index = 0;
13403 }
13404 if ( index < 0 ) {
13405 index = lastTabIndex;
13406 }
13407 return index;
13408 }
13409
13410 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
13411 index = goingForward ? index + 1 : index - 1;
13412 }
13413
13414 return index;
13415 },
13416
13417 _focusNextTab: function( index, goingForward ) {
13418 index = this._findNextTab( index, goingForward );
13419 this.tabs.eq( index ).focus();
13420 return index;
13421 },
13422
13423 _setOption: function( key, value ) {
13424 if ( key === "active" ) {
13425 // _activate() will handle invalid values and update this.options
13426 this._activate( value );
13427 return;
13428 }
13429
13430 if ( key === "disabled" ) {
13431 // don't use the widget factory's disabled handling
13432 this._setupDisabled( value );
13433 return;
13434 }
13435
13436 this._super( key, value);
13437
13438 if ( key === "collapsible" ) {
13439 this.element.toggleClass( "ui-tabs-collapsible", value );
13440 // Setting collapsible: false while collapsed; open first panel
13441 if ( !value && this.options.active === false ) {
13442 this._activate( 0 );
13443 }
13444 }
13445
13446 if ( key === "event" ) {
13447 this._setupEvents( value );
13448 }
13449
13450 if ( key === "heightStyle" ) {
13451 this._setupHeightStyle( value );
13452 }
13453 },
13454
13455 _tabId: function( tab ) {
13456 return tab.attr( "aria-controls" ) || "ui-tabs-" + getNextTabId();
13457 },
13458
13459 _sanitizeSelector: function( hash ) {
13460 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
13461 },
13462
13463 refresh: function() {
13464 var options = this.options,
13465 lis = this.tablist.children( ":has(a[href])" );
13466
13467 // get disabled tabs from class attribute from HTML
13468 // this will get converted to a boolean if needed in _refresh()
13469 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
13470 return lis.index( tab );
13471 });
13472
13473 this._processTabs();
13474
13475 // was collapsed or no tabs
13476 if ( options.active === false || !this.anchors.length ) {
13477 options.active = false;
13478 this.active = $();
13479 // was active, but active tab is gone
13480 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
13481 // all remaining tabs are disabled
13482 if ( this.tabs.length === options.disabled.length ) {
13483 options.active = false;
13484 this.active = $();
13485 // activate previous tab
13486 } else {
13487 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
13488 }
13489 // was active, active tab still exists
13490 } else {
13491 // make sure active index is correct
13492 options.active = this.tabs.index( this.active );
13493 }
13494
13495 this._refresh();
13496 },
13497
13498 _refresh: function() {
13499 this._setupDisabled( this.options.disabled );
13500 this._setupEvents( this.options.event );
13501 this._setupHeightStyle( this.options.heightStyle );
13502
13503 this.tabs.not( this.active ).attr({
13504 "aria-selected": "false",
13505 tabIndex: -1
13506 });
13507 this.panels.not( this._getPanelForTab( this.active ) )
13508 .hide()
13509 .attr({
13510 "aria-expanded": "false",
13511 "aria-hidden": "true"
13512 });
13513
13514 // Make sure one tab is in the tab order
13515 if ( !this.active.length ) {
13516 this.tabs.eq( 0 ).attr( "tabIndex", 0 );
13517 } else {
13518 this.active
13519 .addClass( "ui-tabs-active ui-state-active" )
13520 .attr({
13521 "aria-selected": "true",
13522 tabIndex: 0
13523 });
13524 this._getPanelForTab( this.active )
13525 .show()
13526 .attr({
13527 "aria-expanded": "true",
13528 "aria-hidden": "false"
13529 });
13530 }
13531 },
13532
13533 _processTabs: function() {
13534 var that = this;
13535
13536 this.tablist = this._getList()
13537 .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
13538 .attr( "role", "tablist" );
13539
13540 this.tabs = this.tablist.find( "> li:has(a[href])" )
13541 .addClass( "ui-state-default ui-corner-top" )
13542 .attr({
13543 role: "tab",
13544 tabIndex: -1
13545 });
13546
13547 this.anchors = this.tabs.map(function() {
13548 return $( "a", this )[ 0 ];
13549 })
13550 .addClass( "ui-tabs-anchor" )
13551 .attr({
13552 role: "presentation",
13553 tabIndex: -1
13554 });
13555
13556 this.panels = $();
13557
13558 this.anchors.each(function( i, anchor ) {
13559 var selector, panel, panelId,
13560 anchorId = $( anchor ).uniqueId().attr( "id" ),
13561 tab = $( anchor ).closest( "li" ),
13562 originalAriaControls = tab.attr( "aria-controls" );
13563
13564 // inline tab
13565 if ( isLocal( anchor ) ) {
13566 selector = anchor.hash;
13567 panel = that.element.find( that._sanitizeSelector( selector ) );
13568 // remote tab
13569 } else {
13570 panelId = that._tabId( tab );
13571 selector = "#" + panelId;
13572 panel = that.element.find( selector );
13573 if ( !panel.length ) {
13574 panel = that._createPanel( panelId );
13575 panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
13576 }
13577 panel.attr( "aria-live", "polite" );
13578 }
13579
13580 if ( panel.length) {
13581 that.panels = that.panels.add( panel );
13582 }
13583 if ( originalAriaControls ) {
13584 tab.data( "ui-tabs-aria-controls", originalAriaControls );
13585 }
13586 tab.attr({
13587 "aria-controls": selector.substring( 1 ),
13588 "aria-labelledby": anchorId
13589 });
13590 panel.attr( "aria-labelledby", anchorId );
13591 });
13592
13593 this.panels
13594 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
13595 .attr( "role", "tabpanel" );
13596 },
13597
13598 // allow overriding how to find the list for rare usage scenarios (#7715)
13599 _getList: function() {
13600 return this.element.find( "ol,ul" ).eq( 0 );
13601 },
13602
13603 _createPanel: function( id ) {
13604 return $( "<div>" )
13605 .attr( "id", id )
13606 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
13607 .data( "ui-tabs-destroy", true );
13608 },
13609
13610 _setupDisabled: function( disabled ) {
13611 if ( $.isArray( disabled ) ) {
13612 if ( !disabled.length ) {
13613 disabled = false;
13614 } else if ( disabled.length === this.anchors.length ) {
13615 disabled = true;
13616 }
13617 }
13618
13619 // disable tabs
13620 for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {
13621 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
13622 $( li )
13623 .addClass( "ui-state-disabled" )
13624 .attr( "aria-disabled", "true" );
13625 } else {
13626 $( li )
13627 .removeClass( "ui-state-disabled" )
13628 .removeAttr( "aria-disabled" );
13629 }
13630 }
13631
13632 this.options.disabled = disabled;
13633 },
13634
13635 _setupEvents: function( event ) {
13636 var events = {
13637 click: function( event ) {
13638 event.preventDefault();
13639 }
13640 };
13641 if ( event ) {
13642 $.each( event.split(" "), function( index, eventName ) {
13643 events[ eventName ] = "_eventHandler";
13644 });
13645 }
13646
13647 this._off( this.anchors.add( this.tabs ).add( this.panels ) );
13648 this._on( this.anchors, events );
13649 this._on( this.tabs, { keydown: "_tabKeydown" } );
13650 this._on( this.panels, { keydown: "_panelKeydown" } );
13651
13652 this._focusable( this.tabs );
13653 this._hoverable( this.tabs );
13654 },
13655
13656 _setupHeightStyle: function( heightStyle ) {
13657 var maxHeight, overflow,
13658 parent = this.element.parent();
13659
13660 if ( heightStyle === "fill" ) {
13661 // IE 6 treats height like minHeight, so we need to turn off overflow
13662 // in order to get a reliable height
13663 // we use the minHeight support test because we assume that only
13664 // browsers that don't support minHeight will treat height as minHeight
13665 if ( !$.support.minHeight ) {
13666 overflow = parent.css( "overflow" );
13667 parent.css( "overflow", "hidden");
13668 }
13669 maxHeight = parent.height();
13670 this.element.siblings( ":visible" ).each(function() {
13671 var elem = $( this ),
13672 position = elem.css( "position" );
13673
13674 if ( position === "absolute" || position === "fixed" ) {
13675 return;
13676 }
13677 maxHeight -= elem.outerHeight( true );
13678 });
13679 if ( overflow ) {
13680 parent.css( "overflow", overflow );
13681 }
13682
13683 this.element.children().not( this.panels ).each(function() {
13684 maxHeight -= $( this ).outerHeight( true );
13685 });
13686
13687 this.panels.each(function() {
13688 $( this ).height( Math.max( 0, maxHeight -
13689 $( this ).innerHeight() + $( this ).height() ) );
13690 })
13691 .css( "overflow", "auto" );
13692 } else if ( heightStyle === "auto" ) {
13693 maxHeight = 0;
13694 this.panels.each(function() {
13695 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
13696 }).height( maxHeight );
13697 }
13698 },
13699
13700 _eventHandler: function( event ) {
13701 var options = this.options,
13702 active = this.active,
13703 anchor = $( event.currentTarget ),
13704 tab = anchor.closest( "li" ),
13705 clickedIsActive = tab[ 0 ] === active[ 0 ],
13706 collapsing = clickedIsActive && options.collapsible,
13707 toShow = collapsing ? $() : this._getPanelForTab( tab ),
13708 toHide = !active.length ? $() : this._getPanelForTab( active ),
13709 eventData = {
13710 oldTab: active,
13711 oldPanel: toHide,
13712 newTab: collapsing ? $() : tab,
13713 newPanel: toShow
13714 };
13715
13716 event.preventDefault();
13717
13718 if ( tab.hasClass( "ui-state-disabled" ) ||
13719 // tab is already loading
13720 tab.hasClass( "ui-tabs-loading" ) ||
13721 // can't switch durning an animation
13722 this.running ||
13723 // click on active header, but not collapsible
13724 ( clickedIsActive && !options.collapsible ) ||
13725 // allow canceling activation
13726 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
13727 return;
13728 }
13729
13730 options.active = collapsing ? false : this.tabs.index( tab );
13731
13732 this.active = clickedIsActive ? $() : tab;
13733 if ( this.xhr ) {
13734 this.xhr.abort();
13735 }
13736
13737 if ( !toHide.length && !toShow.length ) {
13738 $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
13739 }
13740
13741 if ( toShow.length ) {
13742 this.load( this.tabs.index( tab ), event );
13743 }
13744 this._toggle( event, eventData );
13745 },
13746
13747 // handles show/hide for selecting tabs
13748 _toggle: function( event, eventData ) {
13749 var that = this,
13750 toShow = eventData.newPanel,
13751 toHide = eventData.oldPanel;
13752
13753 this.running = true;
13754
13755 function complete() {
13756 that.running = false;
13757 that._trigger( "activate", event, eventData );
13758 }
13759
13760 function show() {
13761 eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
13762
13763 if ( toShow.length && that.options.show ) {
13764 that._show( toShow, that.options.show, complete );
13765 } else {
13766 toShow.show();
13767 complete();
13768 }
13769 }
13770
13771 // start out by hiding, then showing, then completing
13772 if ( toHide.length && this.options.hide ) {
13773 this._hide( toHide, this.options.hide, function() {
13774 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
13775 show();
13776 });
13777 } else {
13778 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
13779 toHide.hide();
13780 show();
13781 }
13782
13783 toHide.attr({
13784 "aria-expanded": "false",
13785 "aria-hidden": "true"
13786 });
13787 eventData.oldTab.attr( "aria-selected", "false" );
13788 // If we're switching tabs, remove the old tab from the tab order.
13789 // If we're opening from collapsed state, remove the previous tab from the tab order.
13790 // If we're collapsing, then keep the collapsing tab in the tab order.
13791 if ( toShow.length && toHide.length ) {
13792 eventData.oldTab.attr( "tabIndex", -1 );
13793 } else if ( toShow.length ) {
13794 this.tabs.filter(function() {
13795 return $( this ).attr( "tabIndex" ) === 0;
13796 })
13797 .attr( "tabIndex", -1 );
13798 }
13799
13800 toShow.attr({
13801 "aria-expanded": "true",
13802 "aria-hidden": "false"
13803 });
13804 eventData.newTab.attr({
13805 "aria-selected": "true",
13806 tabIndex: 0
13807 });
13808 },
13809
13810 _activate: function( index ) {
13811 var anchor,
13812 active = this._findActive( index );
13813
13814 // trying to activate the already active panel
13815 if ( active[ 0 ] === this.active[ 0 ] ) {
13816 return;
13817 }
13818
13819 // trying to collapse, simulate a click on the current active header
13820 if ( !active.length ) {
13821 active = this.active;
13822 }
13823
13824 anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
13825 this._eventHandler({
13826 target: anchor,
13827 currentTarget: anchor,
13828 preventDefault: $.noop
13829 });
13830 },
13831
13832 _findActive: function( index ) {
13833 return index === false ? $() : this.tabs.eq( index );
13834 },
13835
13836 _getIndex: function( index ) {
13837 // meta-function to give users option to provide a href string instead of a numerical index.
13838 if ( typeof index === "string" ) {
13839 index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) );
13840 }
13841
13842 return index;
13843 },
13844
13845 _destroy: function() {
13846 if ( this.xhr ) {
13847 this.xhr.abort();
13848 }
13849
13850 this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" );
13851
13852 this.tablist
13853 .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
13854 .removeAttr( "role" );
13855
13856 this.anchors
13857 .removeClass( "ui-tabs-anchor" )
13858 .removeAttr( "role" )
13859 .removeAttr( "tabIndex" )
13860 .removeData( "href.tabs" )
13861 .removeData( "load.tabs" )
13862 .removeUniqueId();
13863
13864 this.tabs.add( this.panels ).each(function() {
13865 if ( $.data( this, "ui-tabs-destroy" ) ) {
13866 $( this ).remove();
13867 } else {
13868 $( this )
13869 .removeClass( "ui-state-default ui-state-active ui-state-disabled " +
13870 "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" )
13871 .removeAttr( "tabIndex" )
13872 .removeAttr( "aria-live" )
13873 .removeAttr( "aria-busy" )
13874 .removeAttr( "aria-selected" )
13875 .removeAttr( "aria-labelledby" )
13876 .removeAttr( "aria-hidden" )
13877 .removeAttr( "aria-expanded" )
13878 .removeAttr( "role" );
13879 }
13880 });
13881
13882 this.tabs.each(function() {
13883 var li = $( this ),
13884 prev = li.data( "ui-tabs-aria-controls" );
13885 if ( prev ) {
13886 li.attr( "aria-controls", prev );
13887 } else {
13888 li.removeAttr( "aria-controls" );
13889 }
13890 });
13891
13892 this.panels.show();
13893
13894 if ( this.options.heightStyle !== "content" ) {
13895 this.panels.css( "height", "" );
13896 }
13897 },
13898
13899 enable: function( index ) {
13900 var disabled = this.options.disabled;
13901 if ( disabled === false ) {
13902 return;
13903 }
13904
13905 if ( index === undefined ) {
13906 disabled = false;
13907 } else {
13908 index = this._getIndex( index );
13909 if ( $.isArray( disabled ) ) {
13910 disabled = $.map( disabled, function( num ) {
13911 return num !== index ? num : null;
13912 });
13913 } else {
13914 disabled = $.map( this.tabs, function( li, num ) {
13915 return num !== index ? num : null;
13916 });
13917 }
13918 }
13919 this._setupDisabled( disabled );
13920 },
13921
13922 disable: function( index ) {
13923 var disabled = this.options.disabled;
13924 if ( disabled === true ) {
13925 return;
13926 }
13927
13928 if ( index === undefined ) {
13929 disabled = true;
13930 } else {
13931 index = this._getIndex( index );
13932 if ( $.inArray( index, disabled ) !== -1 ) {
13933 return;
13934 }
13935 if ( $.isArray( disabled ) ) {
13936 disabled = $.merge( [ index ], disabled ).sort();
13937 } else {
13938 disabled = [ index ];
13939 }
13940 }
13941 this._setupDisabled( disabled );
13942 },
13943
13944 load: function( index, event ) {
13945 index = this._getIndex( index );
13946 var that = this,
13947 tab = this.tabs.eq( index ),
13948 anchor = tab.find( ".ui-tabs-anchor" ),
13949 panel = this._getPanelForTab( tab ),
13950 eventData = {
13951 tab: tab,
13952 panel: panel
13953 };
13954
13955 // not remote
13956 if ( isLocal( anchor[ 0 ] ) ) {
13957 return;
13958 }
13959
13960 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
13961
13962 // support: jQuery <1.8
13963 // jQuery <1.8 returns false if the request is canceled in beforeSend,
13964 // but as of 1.8, $.ajax() always returns a jqXHR object.
13965 if ( this.xhr && this.xhr.statusText !== "canceled" ) {
13966 tab.addClass( "ui-tabs-loading" );
13967 panel.attr( "aria-busy", "true" );
13968
13969 this.xhr
13970 .success(function( response ) {
13971 // support: jQuery <1.8
13972 // http://bugs.jquery.com/ticket/11778
13973 setTimeout(function() {
13974 panel.html( response );
13975 that._trigger( "load", event, eventData );
13976 }, 1 );
13977 })
13978 .complete(function( jqXHR, status ) {
13979 // support: jQuery <1.8
13980 // http://bugs.jquery.com/ticket/11778
13981 setTimeout(function() {
13982 if ( status === "abort" ) {
13983 that.panels.stop( false, true );
13984 }
13985
13986 tab.removeClass( "ui-tabs-loading" );
13987 panel.removeAttr( "aria-busy" );
13988
13989 if ( jqXHR === that.xhr ) {
13990 delete that.xhr;
13991 }
13992 }, 1 );
13993 });
13994 }
13995 },
13996
13997 // TODO: Remove this function in 1.10 when ajaxOptions is removed
13998 _ajaxSettings: function( anchor, event, eventData ) {
13999 var that = this;
14000 return {
14001 url: anchor.attr( "href" ),
14002 beforeSend: function( jqXHR, settings ) {
14003 return that._trigger( "beforeLoad", event,
14004 $.extend( { jqXHR : jqXHR, ajaxSettings: settings }, eventData ) );
14005 }
14006 };
14007 },
14008
14009 _getPanelForTab: function( tab ) {
14010 var id = $( tab ).attr( "aria-controls" );
14011 return this.element.find( this._sanitizeSelector( "#" + id ) );
14012 }
14013});
14014
14015// DEPRECATED
14016if ( $.uiBackCompat !== false ) {
14017
14018 // helper method for a lot of the back compat extensions
14019 $.ui.tabs.prototype._ui = function( tab, panel ) {
14020 return {
14021 tab: tab,
14022 panel: panel,
14023 index: this.anchors.index( tab )
14024 };
14025 };
14026
14027 // url method
14028 $.widget( "ui.tabs", $.ui.tabs, {
14029 url: function( index, url ) {
14030 this.anchors.eq( index ).attr( "href", url );
14031 }
14032 });
14033
14034 // TODO: Remove _ajaxSettings() method when removing this extension
14035 // ajaxOptions and cache options
14036 $.widget( "ui.tabs", $.ui.tabs, {
14037 options: {
14038 ajaxOptions: null,
14039 cache: false
14040 },
14041
14042 _create: function() {
14043 this._super();
14044
14045 var that = this;
14046
14047 this._on({ tabsbeforeload: function( event, ui ) {
14048 // tab is already cached
14049 if ( $.data( ui.tab[ 0 ], "cache.tabs" ) ) {
14050 event.preventDefault();
14051 return;
14052 }
14053
14054 ui.jqXHR.success(function() {
14055 if ( that.options.cache ) {
14056 $.data( ui.tab[ 0 ], "cache.tabs", true );
14057 }
14058 });
14059 }});
14060 },
14061
14062 _ajaxSettings: function( anchor, event, ui ) {
14063 var ajaxOptions = this.options.ajaxOptions;
14064 return $.extend( {}, ajaxOptions, {
14065 error: function( xhr, status ) {
14066 try {
14067 // Passing index avoid a race condition when this method is
14068 // called after the user has selected another tab.
14069 // Pass the anchor that initiated this request allows
14070 // loadError to manipulate the tab content panel via $(a.hash)
14071 ajaxOptions.error(
14072 xhr, status, ui.tab.closest( "li" ).index(), ui.tab[ 0 ] );
14073 }
14074 catch ( error ) {}
14075 }
14076 }, this._superApply( arguments ) );
14077 },
14078
14079 _setOption: function( key, value ) {
14080 // reset cache if switching from cached to not cached
14081 if ( key === "cache" && value === false ) {
14082 this.anchors.removeData( "cache.tabs" );
14083 }
14084 this._super( key, value );
14085 },
14086
14087 _destroy: function() {
14088 this.anchors.removeData( "cache.tabs" );
14089 this._super();
14090 },
14091
14092 url: function( index ){
14093 this.anchors.eq( index ).removeData( "cache.tabs" );
14094 this._superApply( arguments );
14095 }
14096 });
14097
14098 // abort method
14099 $.widget( "ui.tabs", $.ui.tabs, {
14100 abort: function() {
14101 if ( this.xhr ) {
14102 this.xhr.abort();
14103 }
14104 }
14105 });
14106
14107 // spinner
14108 $.widget( "ui.tabs", $.ui.tabs, {
14109 options: {
14110 spinner: "<em>Loading&#8230;</em>"
14111 },
14112 _create: function() {
14113 this._super();
14114 this._on({
14115 tabsbeforeload: function( event, ui ) {
14116 // Don't react to nested tabs or tabs that don't use a spinner
14117 if ( event.target !== this.element[ 0 ] ||
14118 !this.options.spinner ) {
14119 return;
14120 }
14121
14122 var span = ui.tab.find( "span" ),
14123 html = span.html();
14124 span.html( this.options.spinner );
14125 ui.jqXHR.complete(function() {
14126 span.html( html );
14127 });
14128 }
14129 });
14130 }
14131 });
14132
14133 // enable/disable events
14134 $.widget( "ui.tabs", $.ui.tabs, {
14135 options: {
14136 enable: null,
14137 disable: null
14138 },
14139
14140 enable: function( index ) {
14141 var options = this.options,
14142 trigger;
14143
14144 if ( index && options.disabled === true ||
14145 ( $.isArray( options.disabled ) && $.inArray( index, options.disabled ) !== -1 ) ) {
14146 trigger = true;
14147 }
14148
14149 this._superApply( arguments );
14150
14151 if ( trigger ) {
14152 this._trigger( "enable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
14153 }
14154 },
14155
14156 disable: function( index ) {
14157 var options = this.options,
14158 trigger;
14159
14160 if ( index && options.disabled === false ||
14161 ( $.isArray( options.disabled ) && $.inArray( index, options.disabled ) === -1 ) ) {
14162 trigger = true;
14163 }
14164
14165 this._superApply( arguments );
14166
14167 if ( trigger ) {
14168 this._trigger( "disable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
14169 }
14170 }
14171 });
14172
14173 // add/remove methods and events
14174 $.widget( "ui.tabs", $.ui.tabs, {
14175 options: {
14176 add: null,
14177 remove: null,
14178 tabTemplate: "<li><a href='#{href}'><span>#{label}</span></a></li>"
14179 },
14180
14181 add: function( url, label, index ) {
14182 if ( index === undefined ) {
14183 index = this.anchors.length;
14184 }
14185
14186 var doInsertAfter, panel,
14187 options = this.options,
14188 li = $( options.tabTemplate
14189 .replace( /#\{href\}/g, url )
14190 .replace( /#\{label\}/g, label ) ),
14191 id = !url.indexOf( "#" ) ?
14192 url.replace( "#", "" ) :
14193 this._tabId( li );
14194
14195 li.addClass( "ui-state-default ui-corner-top" ).data( "ui-tabs-destroy", true );
14196 li.attr( "aria-controls", id );
14197
14198 doInsertAfter = index >= this.tabs.length;
14199
14200 // try to find an existing element before creating a new one
14201 panel = this.element.find( "#" + id );
14202 if ( !panel.length ) {
14203 panel = this._createPanel( id );
14204 if ( doInsertAfter ) {
14205 if ( index > 0 ) {
14206 panel.insertAfter( this.panels.eq( -1 ) );
14207 } else {
14208 panel.appendTo( this.element );
14209 }
14210 } else {
14211 panel.insertBefore( this.panels[ index ] );
14212 }
14213 }
14214 panel.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ).hide();
14215
14216 if ( doInsertAfter ) {
14217 li.appendTo( this.tablist );
14218 } else {
14219 li.insertBefore( this.tabs[ index ] );
14220 }
14221
14222 options.disabled = $.map( options.disabled, function( n ) {
14223 return n >= index ? ++n : n;
14224 });
14225
14226 this.refresh();
14227 if ( this.tabs.length === 1 && options.active === false ) {
14228 this.option( "active", 0 );
14229 }
14230
14231 this._trigger( "add", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
14232 return this;
14233 },
14234
14235 remove: function( index ) {
14236 index = this._getIndex( index );
14237 var options = this.options,
14238 tab = this.tabs.eq( index ).remove(),
14239 panel = this._getPanelForTab( tab ).remove();
14240
14241 // If selected tab was removed focus tab to the right or
14242 // in case the last tab was removed the tab to the left.
14243 // We check for more than 2 tabs, because if there are only 2,
14244 // then when we remove this tab, there will only be one tab left
14245 // so we don't need to detect which tab to activate.
14246 if ( tab.hasClass( "ui-tabs-active" ) && this.anchors.length > 2 ) {
14247 this._activate( index + ( index + 1 < this.anchors.length ? 1 : -1 ) );
14248 }
14249
14250 options.disabled = $.map(
14251 $.grep( options.disabled, function( n ) {
14252 return n !== index;
14253 }),
14254 function( n ) {
14255 return n >= index ? --n : n;
14256 });
14257
14258 this.refresh();
14259
14260 this._trigger( "remove", null, this._ui( tab.find( "a" )[ 0 ], panel[ 0 ] ) );
14261 return this;
14262 }
14263 });
14264
14265 // length method
14266 $.widget( "ui.tabs", $.ui.tabs, {
14267 length: function() {
14268 return this.anchors.length;
14269 }
14270 });
14271
14272 // panel ids (idPrefix option + title attribute)
14273 $.widget( "ui.tabs", $.ui.tabs, {
14274 options: {
14275 idPrefix: "ui-tabs-"
14276 },
14277
14278 _tabId: function( tab ) {
14279 var a = tab.is( "li" ) ? tab.find( "a[href]" ) : tab;
14280 a = a[0];
14281 return $( a ).closest( "li" ).attr( "aria-controls" ) ||
14282 a.title && a.title.replace( /\s/g, "_" ).replace( /[^\w\u00c0-\uFFFF\-]/g, "" ) ||
14283 this.options.idPrefix + getNextTabId();
14284 }
14285 });
14286
14287 // _createPanel method
14288 $.widget( "ui.tabs", $.ui.tabs, {
14289 options: {
14290 panelTemplate: "<div></div>"
14291 },
14292
14293 _createPanel: function( id ) {
14294 return $( this.options.panelTemplate )
14295 .attr( "id", id )
14296 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
14297 .data( "ui-tabs-destroy", true );
14298 }
14299 });
14300
14301 // selected option
14302 $.widget( "ui.tabs", $.ui.tabs, {
14303 _create: function() {
14304 var options = this.options;
14305 if ( options.active === null && options.selected !== undefined ) {
14306 options.active = options.selected === -1 ? false : options.selected;
14307 }
14308 this._super();
14309 options.selected = options.active;
14310 if ( options.selected === false ) {
14311 options.selected = -1;
14312 }
14313 },
14314
14315 _setOption: function( key, value ) {
14316 if ( key !== "selected" ) {
14317 return this._super( key, value );
14318 }
14319
14320 var options = this.options;
14321 this._super( "active", value === -1 ? false : value );
14322 options.selected = options.active;
14323 if ( options.selected === false ) {
14324 options.selected = -1;
14325 }
14326 },
14327
14328 _eventHandler: function() {
14329 this._superApply( arguments );
14330 this.options.selected = this.options.active;
14331 if ( this.options.selected === false ) {
14332 this.options.selected = -1;
14333 }
14334 }
14335 });
14336
14337 // show and select event
14338 $.widget( "ui.tabs", $.ui.tabs, {
14339 options: {
14340 show: null,
14341 select: null
14342 },
14343 _create: function() {
14344 this._super();
14345 if ( this.options.active !== false ) {
14346 this._trigger( "show", null, this._ui(
14347 this.active.find( ".ui-tabs-anchor" )[ 0 ],
14348 this._getPanelForTab( this.active )[ 0 ] ) );
14349 }
14350 },
14351 _trigger: function( type, event, data ) {
14352 var tab, panel,
14353 ret = this._superApply( arguments );
14354
14355 if ( !ret ) {
14356 return false;
14357 }
14358
14359 if ( type === "beforeActivate" ) {
14360 tab = data.newTab.length ? data.newTab : data.oldTab;
14361 panel = data.newPanel.length ? data.newPanel : data.oldPanel;
14362 ret = this._super( "select", event, {
14363 tab: tab.find( ".ui-tabs-anchor" )[ 0],
14364 panel: panel[ 0 ],
14365 index: tab.closest( "li" ).index()
14366 });
14367 } else if ( type === "activate" && data.newTab.length ) {
14368 ret = this._super( "show", event, {
14369 tab: data.newTab.find( ".ui-tabs-anchor" )[ 0 ],
14370 panel: data.newPanel[ 0 ],
14371 index: data.newTab.closest( "li" ).index()
14372 });
14373 }
14374 return ret;
14375 }
14376 });
14377
14378 // select method
14379 $.widget( "ui.tabs", $.ui.tabs, {
14380 select: function( index ) {
14381 index = this._getIndex( index );
14382 if ( index === -1 ) {
14383 if ( this.options.collapsible && this.options.selected !== -1 ) {
14384 index = this.options.selected;
14385 } else {
14386 return;
14387 }
14388 }
14389 this.anchors.eq( index ).trigger( this.options.event + this.eventNamespace );
14390 }
14391 });
14392
14393 // cookie option
14394 (function() {
14395
14396 var listId = 0;
14397
14398 $.widget( "ui.tabs", $.ui.tabs, {
14399 options: {
14400 cookie: null // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
14401 },
14402 _create: function() {
14403 var options = this.options,
14404 active;
14405 if ( options.active == null && options.cookie ) {
14406 active = parseInt( this._cookie(), 10 );
14407 if ( active === -1 ) {
14408 active = false;
14409 }
14410 options.active = active;
14411 }
14412 this._super();
14413 },
14414 _cookie: function( active ) {
14415 var cookie = [ this.cookie ||
14416 ( this.cookie = this.options.cookie.name || "ui-tabs-" + (++listId) ) ];
14417 if ( arguments.length ) {
14418 cookie.push( active === false ? -1 : active );
14419 cookie.push( this.options.cookie );
14420 }
14421 return $.cookie.apply( null, cookie );
14422 },
14423 _refresh: function() {
14424 this._super();
14425 if ( this.options.cookie ) {
14426 this._cookie( this.options.active, this.options.cookie );
14427 }
14428 },
14429 _eventHandler: function() {
14430 this._superApply( arguments );
14431 if ( this.options.cookie ) {
14432 this._cookie( this.options.active, this.options.cookie );
14433 }
14434 },
14435 _destroy: function() {
14436 this._super();
14437 if ( this.options.cookie ) {
14438 this._cookie( null, this.options.cookie );
14439 }
14440 }
14441 });
14442
14443 })();
14444
14445 // load event
14446 $.widget( "ui.tabs", $.ui.tabs, {
14447 _trigger: function( type, event, data ) {
14448 var _data = $.extend( {}, data );
14449 if ( type === "load" ) {
14450 _data.panel = _data.panel[ 0 ];
14451 _data.tab = _data.tab.find( ".ui-tabs-anchor" )[ 0 ];
14452 }
14453 return this._super( type, event, _data );
14454 }
14455 });
14456
14457 // fx option
14458 // The new animation options (show, hide) conflict with the old show callback.
14459 // The old fx option wins over show/hide anyway (always favor back-compat).
14460 // If a user wants to use the new animation API, they must give up the old API.
14461 $.widget( "ui.tabs", $.ui.tabs, {
14462 options: {
14463 fx: null // e.g. { height: "toggle", opacity: "toggle", duration: 200 }
14464 },
14465
14466 _getFx: function() {
14467 var hide, show,
14468 fx = this.options.fx;
14469
14470 if ( fx ) {
14471 if ( $.isArray( fx ) ) {
14472 hide = fx[ 0 ];
14473 show = fx[ 1 ];
14474 } else {
14475 hide = show = fx;
14476 }
14477 }
14478
14479 return fx ? { show: show, hide: hide } : null;
14480 },
14481
14482 _toggle: function( event, eventData ) {
14483 var that = this,
14484 toShow = eventData.newPanel,
14485 toHide = eventData.oldPanel,
14486 fx = this._getFx();
14487
14488 if ( !fx ) {
14489 return this._super( event, eventData );
14490 }
14491
14492 that.running = true;
14493
14494 function complete() {
14495 that.running = false;
14496 that._trigger( "activate", event, eventData );
14497 }
14498
14499 function show() {
14500 eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
14501
14502 if ( toShow.length && fx.show ) {
14503 toShow
14504 .animate( fx.show, fx.show.duration, function() {
14505 complete();
14506 });
14507 } else {
14508 toShow.show();
14509 complete();
14510 }
14511 }
14512
14513 // start out by hiding, then showing, then completing
14514 if ( toHide.length && fx.hide ) {
14515 toHide.animate( fx.hide, fx.hide.duration, function() {
14516 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
14517 show();
14518 });
14519 } else {
14520 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
14521 toHide.hide();
14522 show();
14523 }
14524 }
14525 });
14526}
14527
14528})( jQuery );
14529
14530(function( $ ) {
14531
14532var increments = 0;
14533
14534function addDescribedBy( elem, id ) {
14535 var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ );
14536 describedby.push( id );
14537 elem
14538 .data( "ui-tooltip-id", id )
14539 .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
14540}
14541
14542function removeDescribedBy( elem ) {
14543 var id = elem.data( "ui-tooltip-id" ),
14544 describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ),
14545 index = $.inArray( id, describedby );
14546 if ( index !== -1 ) {
14547 describedby.splice( index, 1 );
14548 }
14549
14550 elem.removeData( "ui-tooltip-id" );
14551 describedby = $.trim( describedby.join( " " ) );
14552 if ( describedby ) {
14553 elem.attr( "aria-describedby", describedby );
14554 } else {
14555 elem.removeAttr( "aria-describedby" );
14556 }
14557}
14558
14559$.widget( "ui.tooltip", {
14560 version: "1.9.2",
14561 options: {
14562 content: function() {
14563 return $( this ).attr( "title" );
14564 },
14565 hide: true,
14566 // Disabled elements have inconsistent behavior across browsers (#8661)
14567 items: "[title]:not([disabled])",
14568 position: {
14569 my: "left top+15",
14570 at: "left bottom",
14571 collision: "flipfit flip"
14572 },
14573 show: true,
14574 tooltipClass: null,
14575 track: false,
14576
14577 // callbacks
14578 close: null,
14579 open: null
14580 },
14581
14582 _create: function() {
14583 this._on({
14584 mouseover: "open",
14585 focusin: "open"
14586 });
14587
14588 // IDs of generated tooltips, needed for destroy
14589 this.tooltips = {};
14590 // IDs of parent tooltips where we removed the title attribute
14591 this.parents = {};
14592
14593 if ( this.options.disabled ) {
14594 this._disable();
14595 }
14596 },
14597
14598 _setOption: function( key, value ) {
14599 var that = this;
14600
14601 if ( key === "disabled" ) {
14602 this[ value ? "_disable" : "_enable" ]();
14603 this.options[ key ] = value;
14604 // disable element style changes
14605 return;
14606 }
14607
14608 this._super( key, value );
14609
14610 if ( key === "content" ) {
14611 $.each( this.tooltips, function( id, element ) {
14612 that._updateContent( element );
14613 });
14614 }
14615 },
14616
14617 _disable: function() {
14618 var that = this;
14619
14620 // close open tooltips
14621 $.each( this.tooltips, function( id, element ) {
14622 var event = $.Event( "blur" );
14623 event.target = event.currentTarget = element[0];
14624 that.close( event, true );
14625 });
14626
14627 // remove title attributes to prevent native tooltips
14628 this.element.find( this.options.items ).andSelf().each(function() {
14629 var element = $( this );
14630 if ( element.is( "[title]" ) ) {
14631 element
14632 .data( "ui-tooltip-title", element.attr( "title" ) )
14633 .attr( "title", "" );
14634 }
14635 });
14636 },
14637
14638 _enable: function() {
14639 // restore title attributes
14640 this.element.find( this.options.items ).andSelf().each(function() {
14641 var element = $( this );
14642 if ( element.data( "ui-tooltip-title" ) ) {
14643 element.attr( "title", element.data( "ui-tooltip-title" ) );
14644 }
14645 });
14646 },
14647
14648 open: function( event ) {
14649 var that = this,
14650 target = $( event ? event.target : this.element )
14651 // we need closest here due to mouseover bubbling,
14652 // but always pointing at the same event target
14653 .closest( this.options.items );
14654
14655 // No element to show a tooltip for or the tooltip is already open
14656 if ( !target.length || target.data( "ui-tooltip-id" ) ) {
14657 return;
14658 }
14659
14660 if ( target.attr( "title" ) ) {
14661 target.data( "ui-tooltip-title", target.attr( "title" ) );
14662 }
14663
14664 target.data( "ui-tooltip-open", true );
14665
14666 // kill parent tooltips, custom or native, for hover
14667 if ( event && event.type === "mouseover" ) {
14668 target.parents().each(function() {
14669 var parent = $( this ),
14670 blurEvent;
14671 if ( parent.data( "ui-tooltip-open" ) ) {
14672 blurEvent = $.Event( "blur" );
14673 blurEvent.target = blurEvent.currentTarget = this;
14674 that.close( blurEvent, true );
14675 }
14676 if ( parent.attr( "title" ) ) {
14677 parent.uniqueId();
14678 that.parents[ this.id ] = {
14679 element: this,
14680 title: parent.attr( "title" )
14681 };
14682 parent.attr( "title", "" );
14683 }
14684 });
14685 }
14686
14687 this._updateContent( target, event );
14688 },
14689
14690 _updateContent: function( target, event ) {
14691 var content,
14692 contentOption = this.options.content,
14693 that = this,
14694 eventType = event ? event.type : null;
14695
14696 if ( typeof contentOption === "string" ) {
14697 return this._open( event, target, contentOption );
14698 }
14699
14700 content = contentOption.call( target[0], function( response ) {
14701 // ignore async response if tooltip was closed already
14702 if ( !target.data( "ui-tooltip-open" ) ) {
14703 return;
14704 }
14705 // IE may instantly serve a cached response for ajax requests
14706 // delay this call to _open so the other call to _open runs first
14707 that._delay(function() {
14708 // jQuery creates a special event for focusin when it doesn't
14709 // exist natively. To improve performance, the native event
14710 // object is reused and the type is changed. Therefore, we can't
14711 // rely on the type being correct after the event finished
14712 // bubbling, so we set it back to the previous value. (#8740)
14713 if ( event ) {
14714 event.type = eventType;
14715 }
14716 this._open( event, target, response );
14717 });
14718 });
14719 if ( content ) {
14720 this._open( event, target, content );
14721 }
14722 },
14723
14724 _open: function( event, target, content ) {
14725 var tooltip, events, delayedShow,
14726 positionOption = $.extend( {}, this.options.position );
14727
14728 if ( !content ) {
14729 return;
14730 }
14731
14732 // Content can be updated multiple times. If the tooltip already
14733 // exists, then just update the content and bail.
14734 tooltip = this._find( target );
14735 if ( tooltip.length ) {
14736 tooltip.find( ".ui-tooltip-content" ).html( content );
14737 return;
14738 }
14739
14740 // if we have a title, clear it to prevent the native tooltip
14741 // we have to check first to avoid defining a title if none exists
14742 // (we don't want to cause an element to start matching [title])
14743 //
14744 // We use removeAttr only for key events, to allow IE to export the correct
14745 // accessible attributes. For mouse events, set to empty string to avoid
14746 // native tooltip showing up (happens only when removing inside mouseover).
14747 if ( target.is( "[title]" ) ) {
14748 if ( event && event.type === "mouseover" ) {
14749 target.attr( "title", "" );
14750 } else {
14751 target.removeAttr( "title" );
14752 }
14753 }
14754
14755 tooltip = this._tooltip( target );
14756 addDescribedBy( target, tooltip.attr( "id" ) );
14757 tooltip.find( ".ui-tooltip-content" ).html( content );
14758
14759 function position( event ) {
14760 positionOption.of = event;
14761 if ( tooltip.is( ":hidden" ) ) {
14762 return;
14763 }
14764 tooltip.position( positionOption );
14765 }
14766 if ( this.options.track && event && /^mouse/.test( event.type ) ) {
14767 this._on( this.document, {
14768 mousemove: position
14769 });
14770 // trigger once to override element-relative positioning
14771 position( event );
14772 } else {
14773 tooltip.position( $.extend({
14774 of: target
14775 }, this.options.position ) );
14776 }
14777
14778 tooltip.hide();
14779
14780 this._show( tooltip, this.options.show );
14781 // Handle tracking tooltips that are shown with a delay (#8644). As soon
14782 // as the tooltip is visible, position the tooltip using the most recent
14783 // event.
14784 if ( this.options.show && this.options.show.delay ) {
14785 delayedShow = setInterval(function() {
14786 if ( tooltip.is( ":visible" ) ) {
14787 position( positionOption.of );
14788 clearInterval( delayedShow );
14789 }
14790 }, $.fx.interval );
14791 }
14792
14793 this._trigger( "open", event, { tooltip: tooltip } );
14794
14795 events = {
14796 keyup: function( event ) {
14797 if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
14798 var fakeEvent = $.Event(event);
14799 fakeEvent.currentTarget = target[0];
14800 this.close( fakeEvent, true );
14801 }
14802 },
14803 remove: function() {
14804 this._removeTooltip( tooltip );
14805 }
14806 };
14807 if ( !event || event.type === "mouseover" ) {
14808 events.mouseleave = "close";
14809 }
14810 if ( !event || event.type === "focusin" ) {
14811 events.focusout = "close";
14812 }
14813 this._on( true, target, events );
14814 },
14815
14816 close: function( event ) {
14817 var that = this,
14818 target = $( event ? event.currentTarget : this.element ),
14819 tooltip = this._find( target );
14820
14821 // disabling closes the tooltip, so we need to track when we're closing
14822 // to avoid an infinite loop in case the tooltip becomes disabled on close
14823 if ( this.closing ) {
14824 return;
14825 }
14826
14827 // only set title if we had one before (see comment in _open())
14828 if ( target.data( "ui-tooltip-title" ) ) {
14829 target.attr( "title", target.data( "ui-tooltip-title" ) );
14830 }
14831
14832 removeDescribedBy( target );
14833
14834 tooltip.stop( true );
14835 this._hide( tooltip, this.options.hide, function() {
14836 that._removeTooltip( $( this ) );
14837 });
14838
14839 target.removeData( "ui-tooltip-open" );
14840 this._off( target, "mouseleave focusout keyup" );
14841 // Remove 'remove' binding only on delegated targets
14842 if ( target[0] !== this.element[0] ) {
14843 this._off( target, "remove" );
14844 }
14845 this._off( this.document, "mousemove" );
14846
14847 if ( event && event.type === "mouseleave" ) {
14848 $.each( this.parents, function( id, parent ) {
14849 $( parent.element ).attr( "title", parent.title );
14850 delete that.parents[ id ];
14851 });
14852 }
14853
14854 this.closing = true;
14855 this._trigger( "close", event, { tooltip: tooltip } );
14856 this.closing = false;
14857 },
14858
14859 _tooltip: function( element ) {
14860 var id = "ui-tooltip-" + increments++,
14861 tooltip = $( "<div>" )
14862 .attr({
14863 id: id,
14864 role: "tooltip"
14865 })
14866 .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " +
14867 ( this.options.tooltipClass || "" ) );
14868 $( "<div>" )
14869 .addClass( "ui-tooltip-content" )
14870 .appendTo( tooltip );
14871 tooltip.appendTo( this.document[0].body );
14872 if ( $.fn.bgiframe ) {
14873 tooltip.bgiframe();
14874 }
14875 this.tooltips[ id ] = element;
14876 return tooltip;
14877 },
14878
14879 _find: function( target ) {
14880 var id = target.data( "ui-tooltip-id" );
14881 return id ? $( "#" + id ) : $();
14882 },
14883
14884 _removeTooltip: function( tooltip ) {
14885 tooltip.remove();
14886 delete this.tooltips[ tooltip.attr( "id" ) ];
14887 },
14888
14889 _destroy: function() {
14890 var that = this;
14891
14892 // close open tooltips
14893 $.each( this.tooltips, function( id, element ) {
14894 // Delegate to close method to handle common cleanup
14895 var event = $.Event( "blur" );
14896 event.target = event.currentTarget = element[0];
14897 that.close( event, true );
14898
14899 // Remove immediately; destroying an open tooltip doesn't use the
14900 // hide animation
14901 $( "#" + id ).remove();
14902
14903 // Restore the title
14904 if ( element.data( "ui-tooltip-title" ) ) {
14905 element.attr( "title", element.data( "ui-tooltip-title" ) );
14906 element.removeData( "ui-tooltip-title" );
14907 }
14908 });
14909 }
14910});
14911
14912}( jQuery ) );