fixing librejs on defectivebydesign.org
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules / civicrm / packages / jquery / jquery-ui-1.9.0 / js / jquery-ui-1.9.0.custom.js
1 /*! jQuery UI - v1.9.0 - 2012-10-24
2 * http://jqueryui.com
3 * Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.position.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.menu.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js, jquery.ui.effect.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
4 * Copyright (c) 2012 jQuery Foundation and other contributors Licensed MIT */
5
6 (function( $, undefined ) {
7
8 var 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 || {};
15 if ( $.ui.version ) {
16 return;
17 }
18
19 $.extend( $.ui, {
20 version: "1.9.0",
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 (($.browser.msie && (/(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 // support: jQuery <1.8
127 if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
128 $.each( [ "Width", "Height" ], function( i, name ) {
129 var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
130 type = name.toLowerCase(),
131 orig = {
132 innerWidth: $.fn.innerWidth,
133 innerHeight: $.fn.innerHeight,
134 outerWidth: $.fn.outerWidth,
135 outerHeight: $.fn.outerHeight
136 };
137
138 function reduce( elem, size, border, margin ) {
139 $.each( side, function() {
140 size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
141 if ( border ) {
142 size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
143 }
144 if ( margin ) {
145 size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
146 }
147 });
148 return size;
149 }
150
151 $.fn[ "inner" + name ] = function( size ) {
152 if ( size === undefined ) {
153 return orig[ "inner" + name ].call( this );
154 }
155
156 return this.each(function() {
157 $( this ).css( type, reduce( this, size ) + "px" );
158 });
159 };
160
161 $.fn[ "outer" + name] = function( size, margin ) {
162 if ( typeof size !== "number" ) {
163 return orig[ "outer" + name ].call( this, size );
164 }
165
166 return this.each(function() {
167 $( this).css( type, reduce( this, size, true, margin ) + "px" );
168 });
169 };
170 });
171 }
172
173 // selectors
174 function focusable( element, isTabIndexNotNaN ) {
175 var map, mapName, img,
176 nodeName = element.nodeName.toLowerCase();
177 if ( "area" === nodeName ) {
178 map = element.parentNode;
179 mapName = map.name;
180 if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
181 return false;
182 }
183 img = $( "img[usemap=#" + mapName + "]" )[0];
184 return !!img && visible( img );
185 }
186 return ( /input|select|textarea|button|object/.test( nodeName ) ?
187 !element.disabled :
188 "a" === nodeName ?
189 element.href || isTabIndexNotNaN :
190 isTabIndexNotNaN) &&
191 // the element and all of its ancestors must be visible
192 visible( element );
193 }
194
195 function visible( element ) {
196 return !$( element ).parents().andSelf().filter(function() {
197 return $.css( this, "visibility" ) === "hidden" ||
198 $.expr.filters.hidden( this );
199 }).length;
200 }
201
202 $.extend( $.expr[ ":" ], {
203 data: $.expr.createPseudo ?
204 $.expr.createPseudo(function( dataName ) {
205 return function( elem ) {
206 return !!$.data( elem, dataName );
207 };
208 }) :
209 // support: jQuery <1.8
210 function( elem, i, match ) {
211 return !!$.data( elem, match[ 3 ] );
212 },
213
214 focusable: function( element ) {
215 return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
216 },
217
218 tabbable: function( element ) {
219 var tabIndex = $.attr( element, "tabindex" ),
220 isTabIndexNaN = isNaN( tabIndex );
221 return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
222 }
223 });
224
225 // support
226 $(function() {
227 var body = document.body,
228 div = body.appendChild( div = document.createElement( "div" ) );
229
230 // access offsetHeight before setting the style to prevent a layout bug
231 // in IE 9 which causes the element to continue to take up space even
232 // after it is removed from the DOM (#8026)
233 div.offsetHeight;
234
235 $.extend( div.style, {
236 minHeight: "100px",
237 height: "auto",
238 padding: 0,
239 borderWidth: 0
240 });
241
242 $.support.minHeight = div.offsetHeight === 100;
243 $.support.selectstart = "onselectstart" in div;
244
245 // set display to none to avoid a layout bug in IE
246 // http://dev.jquery.com/ticket/4014
247 body.removeChild( div ).style.display = "none";
248 });
249
250
251
252
253
254 // deprecated
255
256 $.fn.extend({
257 disableSelection: function() {
258 return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
259 ".ui-disableSelection", function( event ) {
260 event.preventDefault();
261 });
262 },
263
264 enableSelection: function() {
265 return this.unbind( ".ui-disableSelection" );
266 }
267 });
268
269 $.extend( $.ui, {
270 // $.ui.plugin is deprecated. Use the proxy pattern instead.
271 plugin: {
272 add: function( module, option, set ) {
273 var i,
274 proto = $.ui[ module ].prototype;
275 for ( i in set ) {
276 proto.plugins[ i ] = proto.plugins[ i ] || [];
277 proto.plugins[ i ].push( [ option, set[ i ] ] );
278 }
279 },
280 call: function( instance, name, args ) {
281 var i,
282 set = instance.plugins[ name ];
283 if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) {
284 return;
285 }
286
287 for ( i = 0; i < set.length; i++ ) {
288 if ( instance.options[ set[ i ][ 0 ] ] ) {
289 set[ i ][ 1 ].apply( instance.element, args );
290 }
291 }
292 }
293 },
294
295 contains: $.contains,
296
297 // only used by resizable
298 hasScroll: function( el, a ) {
299
300 //If overflow is hidden, the element might have extra content, but the user wants to hide it
301 if ( $( el ).css( "overflow" ) === "hidden") {
302 return false;
303 }
304
305 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
306 has = false;
307
308 if ( el[ scroll ] > 0 ) {
309 return true;
310 }
311
312 // TODO: determine which cases actually cause this to happen
313 // if the element doesn't have the scroll set, see if it's possible to
314 // set the scroll
315 el[ scroll ] = 1;
316 has = ( el[ scroll ] > 0 );
317 el[ scroll ] = 0;
318 return has;
319 },
320
321 // these are odd functions, fix the API or move into individual plugins
322 isOverAxis: function( x, reference, size ) {
323 //Determines when x coordinate is over "b" element axis
324 return ( x > reference ) && ( x < ( reference + size ) );
325 },
326 isOver: function( y, x, top, left, height, width ) {
327 //Determines when x, y coordinates is over "b" element
328 return $.ui.isOverAxis( y, top, height ) && $.ui.isOverAxis( x, left, width );
329 }
330 });
331
332 })( jQuery );
333 (function( $, undefined ) {
334
335 var uuid = 0,
336 slice = Array.prototype.slice,
337 _cleanData = $.cleanData;
338 $.cleanData = function( elems ) {
339 for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
340 try {
341 $( elem ).triggerHandler( "remove" );
342 // http://bugs.jquery.com/ticket/8235
343 } catch( e ) {}
344 }
345 _cleanData( elems );
346 };
347
348 $.widget = function( name, base, prototype ) {
349 var fullName, existingConstructor, constructor, basePrototype,
350 namespace = name.split( "." )[ 0 ];
351
352 name = name.split( "." )[ 1 ];
353 fullName = namespace + "-" + name;
354
355 if ( !prototype ) {
356 prototype = base;
357 base = $.Widget;
358 }
359
360 // create selector for plugin
361 $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
362 return !!$.data( elem, fullName );
363 };
364
365 $[ namespace ] = $[ namespace ] || {};
366 existingConstructor = $[ namespace ][ name ];
367 constructor = $[ namespace ][ name ] = function( options, element ) {
368 // allow instantiation without "new" keyword
369 if ( !this._createWidget ) {
370 return new constructor( options, element );
371 }
372
373 // allow instantiation without initializing for simple inheritance
374 // must use "new" keyword (the code above always passes args)
375 if ( arguments.length ) {
376 this._createWidget( options, element );
377 }
378 };
379 // extend with the existing constructor to carry over any static properties
380 $.extend( constructor, existingConstructor, {
381 version: prototype.version,
382 // copy the object used to create the prototype in case we need to
383 // redefine the widget later
384 _proto: $.extend( {}, prototype ),
385 // track widgets that inherit from this widget in case this widget is
386 // redefined after a widget inherits from it
387 _childConstructors: []
388 });
389
390 basePrototype = new base();
391 // we need to make the options hash a property directly on the new instance
392 // otherwise we'll modify the options hash on the prototype that we're
393 // inheriting from
394 basePrototype.options = $.widget.extend( {}, basePrototype.options );
395 $.each( prototype, function( prop, value ) {
396 if ( $.isFunction( value ) ) {
397 prototype[ prop ] = (function() {
398 var _super = function() {
399 return base.prototype[ prop ].apply( this, arguments );
400 },
401 _superApply = function( args ) {
402 return base.prototype[ prop ].apply( this, args );
403 };
404 return function() {
405 var __super = this._super,
406 __superApply = this._superApply,
407 returnValue;
408
409 this._super = _super;
410 this._superApply = _superApply;
411
412 returnValue = value.apply( this, arguments );
413
414 this._super = __super;
415 this._superApply = __superApply;
416
417 return returnValue;
418 };
419 })();
420 }
421 });
422 constructor.prototype = $.widget.extend( basePrototype, {
423 // TODO: remove support for widgetEventPrefix
424 // always use the name + a colon as the prefix, e.g., draggable:start
425 // don't prefix for widgets that aren't DOM-based
426 widgetEventPrefix: name
427 }, prototype, {
428 constructor: constructor,
429 namespace: namespace,
430 widgetName: name,
431 // TODO remove widgetBaseClass, see #8155
432 widgetBaseClass: fullName,
433 widgetFullName: fullName
434 });
435
436 // If this widget is being redefined then we need to find all widgets that
437 // are inheriting from it and redefine all of them so that they inherit from
438 // the new version of this widget. We're essentially trying to replace one
439 // level in the prototype chain.
440 if ( existingConstructor ) {
441 $.each( existingConstructor._childConstructors, function( i, child ) {
442 var childPrototype = child.prototype;
443
444 // redefine the child widget using the same prototype that was
445 // originally used, but inherit from the new version of the base
446 $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
447 });
448 // remove the list of existing child constructors from the old constructor
449 // so the old child constructors can be garbage collected
450 delete existingConstructor._childConstructors;
451 } else {
452 base._childConstructors.push( constructor );
453 }
454
455 $.widget.bridge( name, constructor );
456 };
457
458 $.widget.extend = function( target ) {
459 var input = slice.call( arguments, 1 ),
460 inputIndex = 0,
461 inputLength = input.length,
462 key,
463 value;
464 for ( ; inputIndex < inputLength; inputIndex++ ) {
465 for ( key in input[ inputIndex ] ) {
466 value = input[ inputIndex ][ key ];
467 if (input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
468 target[ key ] = $.isPlainObject( value ) ? $.widget.extend( {}, target[ key ], value ) : value;
469 }
470 }
471 }
472 return target;
473 };
474
475 $.widget.bridge = function( name, object ) {
476 var fullName = object.prototype.widgetFullName;
477 $.fn[ name ] = function( options ) {
478 var isMethodCall = typeof options === "string",
479 args = slice.call( arguments, 1 ),
480 returnValue = this;
481
482 // allow multiple hashes to be passed on init
483 options = !isMethodCall && args.length ?
484 $.widget.extend.apply( null, [ options ].concat(args) ) :
485 options;
486
487 if ( isMethodCall ) {
488 this.each(function() {
489 var methodValue,
490 instance = $.data( this, fullName );
491 if ( !instance ) {
492 return $.error( "cannot call methods on " + name + " prior to initialization; " +
493 "attempted to call method '" + options + "'" );
494 }
495 if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
496 return $.error( "no such method '" + options + "' for " + name + " widget instance" );
497 }
498 methodValue = instance[ options ].apply( instance, args );
499 if ( methodValue !== instance && methodValue !== undefined ) {
500 returnValue = methodValue && methodValue.jquery ?
501 returnValue.pushStack( methodValue.get() ) :
502 methodValue;
503 return false;
504 }
505 });
506 } else {
507 this.each(function() {
508 var instance = $.data( this, fullName );
509 if ( instance ) {
510 instance.option( options || {} )._init();
511 } else {
512 new object( options, this );
513 }
514 });
515 }
516
517 return returnValue;
518 };
519 };
520
521 $.Widget = function( options, element ) {};
522 $.Widget._childConstructors = [];
523
524 $.Widget.prototype = {
525 widgetName: "widget",
526 widgetEventPrefix: "",
527 defaultElement: "<div>",
528 options: {
529 disabled: false,
530
531 // callbacks
532 create: null
533 },
534 _createWidget: function( options, element ) {
535 element = $( element || this.defaultElement || this )[ 0 ];
536 this.element = $( element );
537 this.uuid = uuid++;
538 this.eventNamespace = "." + this.widgetName + this.uuid;
539 this.options = $.widget.extend( {},
540 this.options,
541 this._getCreateOptions(),
542 options );
543
544 this.bindings = $();
545 this.hoverable = $();
546 this.focusable = $();
547
548 if ( element !== this ) {
549 // 1.9 BC for #7810
550 // TODO remove dual storage
551 $.data( element, this.widgetName, this );
552 $.data( element, this.widgetFullName, this );
553 this._on({ remove: "destroy" });
554 this.document = $( element.style ?
555 // element within the document
556 element.ownerDocument :
557 // element is window or document
558 element.document || element );
559 this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
560 }
561
562 this._create();
563 this._trigger( "create", null, this._getCreateEventData() );
564 this._init();
565 },
566 _getCreateOptions: $.noop,
567 _getCreateEventData: $.noop,
568 _create: $.noop,
569 _init: $.noop,
570
571 destroy: function() {
572 this._destroy();
573 // we can probably remove the unbind calls in 2.0
574 // all event bindings should go through this._on()
575 this.element
576 .unbind( this.eventNamespace )
577 // 1.9 BC for #7810
578 // TODO remove dual storage
579 .removeData( this.widgetName )
580 .removeData( this.widgetFullName )
581 // support: jquery <1.6.3
582 // http://bugs.jquery.com/ticket/9413
583 .removeData( $.camelCase( this.widgetFullName ) );
584 this.widget()
585 .unbind( this.eventNamespace )
586 .removeAttr( "aria-disabled" )
587 .removeClass(
588 this.widgetFullName + "-disabled " +
589 "ui-state-disabled" );
590
591 // clean up events and states
592 this.bindings.unbind( this.eventNamespace );
593 this.hoverable.removeClass( "ui-state-hover" );
594 this.focusable.removeClass( "ui-state-focus" );
595 },
596 _destroy: $.noop,
597
598 widget: function() {
599 return this.element;
600 },
601
602 option: function( key, value ) {
603 var options = key,
604 parts,
605 curOption,
606 i;
607
608 if ( arguments.length === 0 ) {
609 // don't return a reference to the internal hash
610 return $.widget.extend( {}, this.options );
611 }
612
613 if ( typeof key === "string" ) {
614 // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
615 options = {};
616 parts = key.split( "." );
617 key = parts.shift();
618 if ( parts.length ) {
619 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
620 for ( i = 0; i < parts.length - 1; i++ ) {
621 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
622 curOption = curOption[ parts[ i ] ];
623 }
624 key = parts.pop();
625 if ( value === undefined ) {
626 return curOption[ key ] === undefined ? null : curOption[ key ];
627 }
628 curOption[ key ] = value;
629 } else {
630 if ( value === undefined ) {
631 return this.options[ key ] === undefined ? null : this.options[ key ];
632 }
633 options[ key ] = value;
634 }
635 }
636
637 this._setOptions( options );
638
639 return this;
640 },
641 _setOptions: function( options ) {
642 var key;
643
644 for ( key in options ) {
645 this._setOption( key, options[ key ] );
646 }
647
648 return this;
649 },
650 _setOption: function( key, value ) {
651 this.options[ key ] = value;
652
653 if ( key === "disabled" ) {
654 this.widget()
655 .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value )
656 .attr( "aria-disabled", value );
657 this.hoverable.removeClass( "ui-state-hover" );
658 this.focusable.removeClass( "ui-state-focus" );
659 }
660
661 return this;
662 },
663
664 enable: function() {
665 return this._setOption( "disabled", false );
666 },
667 disable: function() {
668 return this._setOption( "disabled", true );
669 },
670
671 _on: function( element, handlers ) {
672 // no element argument, shuffle and use this.element
673 if ( !handlers ) {
674 handlers = element;
675 element = this.element;
676 } else {
677 // accept selectors, DOM elements
678 element = $( element );
679 this.bindings = this.bindings.add( element );
680 }
681
682 var instance = this;
683 $.each( handlers, function( event, handler ) {
684 function handlerProxy() {
685 // allow widgets to customize the disabled handling
686 // - disabled as an array instead of boolean
687 // - disabled class as method for disabling individual parts
688 if ( instance.options.disabled === true ||
689 $( this ).hasClass( "ui-state-disabled" ) ) {
690 return;
691 }
692 return ( typeof handler === "string" ? instance[ handler ] : handler )
693 .apply( instance, arguments );
694 }
695
696 // copy the guid so direct unbinding works
697 if ( typeof handler !== "string" ) {
698 handlerProxy.guid = handler.guid =
699 handler.guid || handlerProxy.guid || $.guid++;
700 }
701
702 var match = event.match( /^(\w+)\s*(.*)$/ ),
703 eventName = match[1] + instance.eventNamespace,
704 selector = match[2];
705 if ( selector ) {
706 instance.widget().delegate( selector, eventName, handlerProxy );
707 } else {
708 element.bind( eventName, handlerProxy );
709 }
710 });
711 },
712
713 _off: function( element, eventName ) {
714 eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
715 element.unbind( eventName ).undelegate( eventName );
716 },
717
718 _delay: function( handler, delay ) {
719 function handlerProxy() {
720 return ( typeof handler === "string" ? instance[ handler ] : handler )
721 .apply( instance, arguments );
722 }
723 var instance = this;
724 return setTimeout( handlerProxy, delay || 0 );
725 },
726
727 _hoverable: function( element ) {
728 this.hoverable = this.hoverable.add( element );
729 this._on( element, {
730 mouseenter: function( event ) {
731 $( event.currentTarget ).addClass( "ui-state-hover" );
732 },
733 mouseleave: function( event ) {
734 $( event.currentTarget ).removeClass( "ui-state-hover" );
735 }
736 });
737 },
738
739 _focusable: function( element ) {
740 this.focusable = this.focusable.add( element );
741 this._on( element, {
742 focusin: function( event ) {
743 $( event.currentTarget ).addClass( "ui-state-focus" );
744 },
745 focusout: function( event ) {
746 $( event.currentTarget ).removeClass( "ui-state-focus" );
747 }
748 });
749 },
750
751 _trigger: function( type, event, data ) {
752 var prop, orig,
753 callback = this.options[ type ];
754
755 data = data || {};
756 event = $.Event( event );
757 event.type = ( type === this.widgetEventPrefix ?
758 type :
759 this.widgetEventPrefix + type ).toLowerCase();
760 // the original event may come from any element
761 // so we need to reset the target on the new event
762 event.target = this.element[ 0 ];
763
764 // copy original event properties over to the new event
765 orig = event.originalEvent;
766 if ( orig ) {
767 for ( prop in orig ) {
768 if ( !( prop in event ) ) {
769 event[ prop ] = orig[ prop ];
770 }
771 }
772 }
773
774 this.element.trigger( event, data );
775 return !( $.isFunction( callback ) &&
776 callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
777 event.isDefaultPrevented() );
778 }
779 };
780
781 $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
782 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
783 if ( typeof options === "string" ) {
784 options = { effect: options };
785 }
786 var hasOptions,
787 effectName = !options ?
788 method :
789 options === true || typeof options === "number" ?
790 defaultEffect :
791 options.effect || defaultEffect;
792 options = options || {};
793 if ( typeof options === "number" ) {
794 options = { duration: options };
795 }
796 hasOptions = !$.isEmptyObject( options );
797 options.complete = callback;
798 if ( options.delay ) {
799 element.delay( options.delay );
800 }
801 if ( hasOptions && $.effects && ( $.effects.effect[ effectName ] || $.uiBackCompat !== false && $.effects[ effectName ] ) ) {
802 element[ method ]( options );
803 } else if ( effectName !== method && element[ effectName ] ) {
804 element[ effectName ]( options.duration, options.easing, callback );
805 } else {
806 element.queue(function( next ) {
807 $( this )[ method ]();
808 if ( callback ) {
809 callback.call( element[ 0 ] );
810 }
811 next();
812 });
813 }
814 };
815 });
816
817 // DEPRECATED
818 if ( $.uiBackCompat !== false ) {
819 $.Widget.prototype._getCreateOptions = function() {
820 return $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ];
821 };
822 }
823
824 })( jQuery );
825 (function( $, undefined ) {
826
827 var mouseHandled = false;
828 $( document ).mouseup( function( e ) {
829 mouseHandled = false;
830 });
831
832 $.widget("ui.mouse", {
833 version: "1.9.0",
834 options: {
835 cancel: 'input,textarea,button,select,option',
836 distance: 1,
837 delay: 0
838 },
839 _mouseInit: function() {
840 var that = this;
841
842 this.element
843 .bind('mousedown.'+this.widgetName, function(event) {
844 return that._mouseDown(event);
845 })
846 .bind('click.'+this.widgetName, function(event) {
847 if (true === $.data(event.target, that.widgetName + '.preventClickEvent')) {
848 $.removeData(event.target, that.widgetName + '.preventClickEvent');
849 event.stopImmediatePropagation();
850 return false;
851 }
852 });
853
854 this.started = false;
855 },
856
857 // TODO: make sure destroying one instance of mouse doesn't mess with
858 // other instances of mouse
859 _mouseDestroy: function() {
860 this.element.unbind('.'+this.widgetName);
861 if ( this._mouseMoveDelegate ) {
862 $(document)
863 .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
864 .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
865 }
866 },
867
868 _mouseDown: function(event) {
869 // don't let more than one widget handle mouseStart
870 if( mouseHandled ) { return; }
871
872 // we may have missed mouseup (out of window)
873 (this._mouseStarted && this._mouseUp(event));
874
875 this._mouseDownEvent = event;
876
877 var that = this,
878 btnIsLeft = (event.which === 1),
879 // event.target.nodeName works around a bug in IE 8 with
880 // disabled inputs (#7620)
881 elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
882 if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
883 return true;
884 }
885
886 this.mouseDelayMet = !this.options.delay;
887 if (!this.mouseDelayMet) {
888 this._mouseDelayTimer = setTimeout(function() {
889 that.mouseDelayMet = true;
890 }, this.options.delay);
891 }
892
893 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
894 this._mouseStarted = (this._mouseStart(event) !== false);
895 if (!this._mouseStarted) {
896 event.preventDefault();
897 return true;
898 }
899 }
900
901 // Click event may never have fired (Gecko & Opera)
902 if (true === $.data(event.target, this.widgetName + '.preventClickEvent')) {
903 $.removeData(event.target, this.widgetName + '.preventClickEvent');
904 }
905
906 // these delegates are required to keep context
907 this._mouseMoveDelegate = function(event) {
908 return that._mouseMove(event);
909 };
910 this._mouseUpDelegate = function(event) {
911 return that._mouseUp(event);
912 };
913 $(document)
914 .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
915 .bind('mouseup.'+this.widgetName, this._mouseUpDelegate);
916
917 event.preventDefault();
918
919 mouseHandled = true;
920 return true;
921 },
922
923 _mouseMove: function(event) {
924 // IE mouseup check - mouseup happened when mouse was out of window
925 if ($.browser.msie && !(document.documentMode >= 9) && !event.button) {
926 return this._mouseUp(event);
927 }
928
929 if (this._mouseStarted) {
930 this._mouseDrag(event);
931 return event.preventDefault();
932 }
933
934 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
935 this._mouseStarted =
936 (this._mouseStart(this._mouseDownEvent, event) !== false);
937 (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
938 }
939
940 return !this._mouseStarted;
941 },
942
943 _mouseUp: function(event) {
944 $(document)
945 .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
946 .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
947
948 if (this._mouseStarted) {
949 this._mouseStarted = false;
950
951 if (event.target === this._mouseDownEvent.target) {
952 $.data(event.target, this.widgetName + '.preventClickEvent', true);
953 }
954
955 this._mouseStop(event);
956 }
957
958 return false;
959 },
960
961 _mouseDistanceMet: function(event) {
962 return (Math.max(
963 Math.abs(this._mouseDownEvent.pageX - event.pageX),
964 Math.abs(this._mouseDownEvent.pageY - event.pageY)
965 ) >= this.options.distance
966 );
967 },
968
969 _mouseDelayMet: function(event) {
970 return this.mouseDelayMet;
971 },
972
973 // These are placeholder methods, to be overriden by extending plugin
974 _mouseStart: function(event) {},
975 _mouseDrag: function(event) {},
976 _mouseStop: function(event) {},
977 _mouseCapture: function(event) { return true; }
978 });
979
980 })(jQuery);
981 (function( $, undefined ) {
982
983 $.ui = $.ui || {};
984
985 var cachedScrollbarWidth,
986 max = Math.max,
987 abs = Math.abs,
988 round = Math.round,
989 rhorizontal = /left|center|right/,
990 rvertical = /top|center|bottom/,
991 roffset = /[\+\-]\d+%?/,
992 rposition = /^\w+/,
993 rpercent = /%$/,
994 _position = $.fn.position;
995
996 function getOffsets( offsets, width, height ) {
997 return [
998 parseInt( offsets[ 0 ], 10 ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
999 parseInt( offsets[ 1 ], 10 ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
1000 ];
1001 }
1002 function parseCss( element, property ) {
1003 return parseInt( $.css( element, property ), 10 ) || 0;
1004 }
1005
1006 $.position = {
1007 scrollbarWidth: function() {
1008 if ( cachedScrollbarWidth !== undefined ) {
1009 return cachedScrollbarWidth;
1010 }
1011 var w1, w2,
1012 div = $( "<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
1013 innerDiv = div.children()[0];
1014
1015 $( "body" ).append( div );
1016 w1 = innerDiv.offsetWidth;
1017 div.css( "overflow", "scroll" );
1018
1019 w2 = innerDiv.offsetWidth;
1020
1021 if ( w1 === w2 ) {
1022 w2 = div[0].clientWidth;
1023 }
1024
1025 div.remove();
1026
1027 return (cachedScrollbarWidth = w1 - w2);
1028 },
1029 getScrollInfo: function( within ) {
1030 var overflowX = within.isWindow ? "" : within.element.css( "overflow-x" ),
1031 overflowY = within.isWindow ? "" : within.element.css( "overflow-y" ),
1032 hasOverflowX = overflowX === "scroll" ||
1033 ( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
1034 hasOverflowY = overflowY === "scroll" ||
1035 ( overflowY === "auto" && within.height < within.element[0].scrollHeight );
1036 return {
1037 width: hasOverflowX ? $.position.scrollbarWidth() : 0,
1038 height: hasOverflowY ? $.position.scrollbarWidth() : 0
1039 };
1040 },
1041 getWithinInfo: function( element ) {
1042 var withinElement = $( element || window ),
1043 isWindow = $.isWindow( withinElement[0] );
1044 return {
1045 element: withinElement,
1046 isWindow: isWindow,
1047 offset: withinElement.offset() || { left: 0, top: 0 },
1048 scrollLeft: withinElement.scrollLeft(),
1049 scrollTop: withinElement.scrollTop(),
1050 width: isWindow ? withinElement.width() : withinElement.outerWidth(),
1051 height: isWindow ? withinElement.height() : withinElement.outerHeight()
1052 };
1053 }
1054 };
1055
1056 $.fn.position = function( options ) {
1057 if ( !options || !options.of ) {
1058 return _position.apply( this, arguments );
1059 }
1060
1061 // make a copy, we don't want to modify arguments
1062 options = $.extend( {}, options );
1063
1064 var atOffset, targetWidth, targetHeight, targetOffset, basePosition,
1065 target = $( options.of ),
1066 within = $.position.getWithinInfo( options.within ),
1067 scrollInfo = $.position.getScrollInfo( within ),
1068 targetElem = target[0],
1069 collision = ( options.collision || "flip" ).split( " " ),
1070 offsets = {};
1071
1072 if ( targetElem.nodeType === 9 ) {
1073 targetWidth = target.width();
1074 targetHeight = target.height();
1075 targetOffset = { top: 0, left: 0 };
1076 } else if ( $.isWindow( targetElem ) ) {
1077 targetWidth = target.width();
1078 targetHeight = target.height();
1079 targetOffset = { top: target.scrollTop(), left: target.scrollLeft() };
1080 } else if ( targetElem.preventDefault ) {
1081 // force left top to allow flipping
1082 options.at = "left top";
1083 targetWidth = targetHeight = 0;
1084 targetOffset = { top: targetElem.pageY, left: targetElem.pageX };
1085 } else {
1086 targetWidth = target.outerWidth();
1087 targetHeight = target.outerHeight();
1088 targetOffset = target.offset();
1089 }
1090 // clone to reuse original targetOffset later
1091 basePosition = $.extend( {}, targetOffset );
1092
1093 // force my and at to have valid horizontal and vertical positions
1094 // if a value is missing or invalid, it will be converted to center
1095 $.each( [ "my", "at" ], function() {
1096 var pos = ( options[ this ] || "" ).split( " " ),
1097 horizontalOffset,
1098 verticalOffset;
1099
1100 if ( pos.length === 1) {
1101 pos = rhorizontal.test( pos[ 0 ] ) ?
1102 pos.concat( [ "center" ] ) :
1103 rvertical.test( pos[ 0 ] ) ?
1104 [ "center" ].concat( pos ) :
1105 [ "center", "center" ];
1106 }
1107 pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
1108 pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
1109
1110 // calculate offsets
1111 horizontalOffset = roffset.exec( pos[ 0 ] );
1112 verticalOffset = roffset.exec( pos[ 1 ] );
1113 offsets[ this ] = [
1114 horizontalOffset ? horizontalOffset[ 0 ] : 0,
1115 verticalOffset ? verticalOffset[ 0 ] : 0
1116 ];
1117
1118 // reduce to just the positions without the offsets
1119 options[ this ] = [
1120 rposition.exec( pos[ 0 ] )[ 0 ],
1121 rposition.exec( pos[ 1 ] )[ 0 ]
1122 ];
1123 });
1124
1125 // normalize collision option
1126 if ( collision.length === 1 ) {
1127 collision[ 1 ] = collision[ 0 ];
1128 }
1129
1130 if ( options.at[ 0 ] === "right" ) {
1131 basePosition.left += targetWidth;
1132 } else if ( options.at[ 0 ] === "center" ) {
1133 basePosition.left += targetWidth / 2;
1134 }
1135
1136 if ( options.at[ 1 ] === "bottom" ) {
1137 basePosition.top += targetHeight;
1138 } else if ( options.at[ 1 ] === "center" ) {
1139 basePosition.top += targetHeight / 2;
1140 }
1141
1142 atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
1143 basePosition.left += atOffset[ 0 ];
1144 basePosition.top += atOffset[ 1 ];
1145
1146 return this.each(function() {
1147 var collisionPosition, using,
1148 elem = $( this ),
1149 elemWidth = elem.outerWidth(),
1150 elemHeight = elem.outerHeight(),
1151 marginLeft = parseCss( this, "marginLeft" ),
1152 marginTop = parseCss( this, "marginTop" ),
1153 collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
1154 collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
1155 position = $.extend( {}, basePosition ),
1156 myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
1157
1158 if ( options.my[ 0 ] === "right" ) {
1159 position.left -= elemWidth;
1160 } else if ( options.my[ 0 ] === "center" ) {
1161 position.left -= elemWidth / 2;
1162 }
1163
1164 if ( options.my[ 1 ] === "bottom" ) {
1165 position.top -= elemHeight;
1166 } else if ( options.my[ 1 ] === "center" ) {
1167 position.top -= elemHeight / 2;
1168 }
1169
1170 position.left += myOffset[ 0 ];
1171 position.top += myOffset[ 1 ];
1172
1173 // if the browser doesn't support fractions, then round for consistent results
1174 if ( !$.support.offsetFractions ) {
1175 position.left = round( position.left );
1176 position.top = round( position.top );
1177 }
1178
1179 collisionPosition = {
1180 marginLeft: marginLeft,
1181 marginTop: marginTop
1182 };
1183
1184 $.each( [ "left", "top" ], function( i, dir ) {
1185 if ( $.ui.position[ collision[ i ] ] ) {
1186 $.ui.position[ collision[ i ] ][ dir ]( position, {
1187 targetWidth: targetWidth,
1188 targetHeight: targetHeight,
1189 elemWidth: elemWidth,
1190 elemHeight: elemHeight,
1191 collisionPosition: collisionPosition,
1192 collisionWidth: collisionWidth,
1193 collisionHeight: collisionHeight,
1194 offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
1195 my: options.my,
1196 at: options.at,
1197 within: within,
1198 elem : elem
1199 });
1200 }
1201 });
1202
1203 if ( $.fn.bgiframe ) {
1204 elem.bgiframe();
1205 }
1206
1207 if ( options.using ) {
1208 // adds feedback as second argument to using callback, if present
1209 using = function( props ) {
1210 var left = targetOffset.left - position.left,
1211 right = left + targetWidth - elemWidth,
1212 top = targetOffset.top - position.top,
1213 bottom = top + targetHeight - elemHeight,
1214 feedback = {
1215 target: {
1216 element: target,
1217 left: targetOffset.left,
1218 top: targetOffset.top,
1219 width: targetWidth,
1220 height: targetHeight
1221 },
1222 element: {
1223 element: elem,
1224 left: position.left,
1225 top: position.top,
1226 width: elemWidth,
1227 height: elemHeight
1228 },
1229 horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
1230 vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
1231 };
1232 if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
1233 feedback.horizontal = "center";
1234 }
1235 if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
1236 feedback.vertical = "middle";
1237 }
1238 if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
1239 feedback.important = "horizontal";
1240 } else {
1241 feedback.important = "vertical";
1242 }
1243 options.using.call( this, props, feedback );
1244 };
1245 }
1246
1247 elem.offset( $.extend( position, { using: using } ) );
1248 });
1249 };
1250
1251 $.ui.position = {
1252 fit: {
1253 left: function( position, data ) {
1254 var within = data.within,
1255 withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
1256 outerWidth = within.width,
1257 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1258 overLeft = withinOffset - collisionPosLeft,
1259 overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
1260 newOverRight;
1261
1262 // element is wider than within
1263 if ( data.collisionWidth > outerWidth ) {
1264 // element is initially over the left side of within
1265 if ( overLeft > 0 && overRight <= 0 ) {
1266 newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
1267 position.left += overLeft - newOverRight;
1268 // element is initially over right side of within
1269 } else if ( overRight > 0 && overLeft <= 0 ) {
1270 position.left = withinOffset;
1271 // element is initially over both left and right sides of within
1272 } else {
1273 if ( overLeft > overRight ) {
1274 position.left = withinOffset + outerWidth - data.collisionWidth;
1275 } else {
1276 position.left = withinOffset;
1277 }
1278 }
1279 // too far left -> align with left edge
1280 } else if ( overLeft > 0 ) {
1281 position.left += overLeft;
1282 // too far right -> align with right edge
1283 } else if ( overRight > 0 ) {
1284 position.left -= overRight;
1285 // adjust based on position and margin
1286 } else {
1287 position.left = max( position.left - collisionPosLeft, position.left );
1288 }
1289 },
1290 top: function( position, data ) {
1291 var within = data.within,
1292 withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
1293 outerHeight = data.within.height,
1294 collisionPosTop = position.top - data.collisionPosition.marginTop,
1295 overTop = withinOffset - collisionPosTop,
1296 overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
1297 newOverBottom;
1298
1299 // element is taller than within
1300 if ( data.collisionHeight > outerHeight ) {
1301 // element is initially over the top of within
1302 if ( overTop > 0 && overBottom <= 0 ) {
1303 newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
1304 position.top += overTop - newOverBottom;
1305 // element is initially over bottom of within
1306 } else if ( overBottom > 0 && overTop <= 0 ) {
1307 position.top = withinOffset;
1308 // element is initially over both top and bottom of within
1309 } else {
1310 if ( overTop > overBottom ) {
1311 position.top = withinOffset + outerHeight - data.collisionHeight;
1312 } else {
1313 position.top = withinOffset;
1314 }
1315 }
1316 // too far up -> align with top
1317 } else if ( overTop > 0 ) {
1318 position.top += overTop;
1319 // too far down -> align with bottom edge
1320 } else if ( overBottom > 0 ) {
1321 position.top -= overBottom;
1322 // adjust based on position and margin
1323 } else {
1324 position.top = max( position.top - collisionPosTop, position.top );
1325 }
1326 }
1327 },
1328 flip: {
1329 left: function( position, data ) {
1330 var within = data.within,
1331 withinOffset = within.offset.left + within.scrollLeft,
1332 outerWidth = within.width,
1333 offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
1334 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1335 overLeft = collisionPosLeft - offsetLeft,
1336 overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
1337 myOffset = data.my[ 0 ] === "left" ?
1338 -data.elemWidth :
1339 data.my[ 0 ] === "right" ?
1340 data.elemWidth :
1341 0,
1342 atOffset = data.at[ 0 ] === "left" ?
1343 data.targetWidth :
1344 data.at[ 0 ] === "right" ?
1345 -data.targetWidth :
1346 0,
1347 offset = -2 * data.offset[ 0 ],
1348 newOverRight,
1349 newOverLeft;
1350
1351 if ( overLeft < 0 ) {
1352 newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
1353 if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
1354 position.left += myOffset + atOffset + offset;
1355 }
1356 }
1357 else if ( overRight > 0 ) {
1358 newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
1359 if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
1360 position.left += myOffset + atOffset + offset;
1361 }
1362 }
1363 },
1364 top: function( position, data ) {
1365 var within = data.within,
1366 withinOffset = within.offset.top + within.scrollTop,
1367 outerHeight = within.height,
1368 offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
1369 collisionPosTop = position.top - data.collisionPosition.marginTop,
1370 overTop = collisionPosTop - offsetTop,
1371 overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
1372 top = data.my[ 1 ] === "top",
1373 myOffset = top ?
1374 -data.elemHeight :
1375 data.my[ 1 ] === "bottom" ?
1376 data.elemHeight :
1377 0,
1378 atOffset = data.at[ 1 ] === "top" ?
1379 data.targetHeight :
1380 data.at[ 1 ] === "bottom" ?
1381 -data.targetHeight :
1382 0,
1383 offset = -2 * data.offset[ 1 ],
1384 newOverTop,
1385 newOverBottom;
1386 if ( overTop < 0 ) {
1387 newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
1388 if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) {
1389 position.top += myOffset + atOffset + offset;
1390 }
1391 }
1392 else if ( overBottom > 0 ) {
1393 newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
1394 if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) {
1395 position.top += myOffset + atOffset + offset;
1396 }
1397 }
1398 }
1399 },
1400 flipfit: {
1401 left: function() {
1402 $.ui.position.flip.left.apply( this, arguments );
1403 $.ui.position.fit.left.apply( this, arguments );
1404 },
1405 top: function() {
1406 $.ui.position.flip.top.apply( this, arguments );
1407 $.ui.position.fit.top.apply( this, arguments );
1408 }
1409 }
1410 };
1411
1412 // fraction support test
1413 (function () {
1414 var testElement, testElementParent, testElementStyle, offsetLeft, i,
1415 body = document.getElementsByTagName( "body" )[ 0 ],
1416 div = document.createElement( "div" );
1417
1418 //Create a "fake body" for testing based on method used in jQuery.support
1419 testElement = document.createElement( body ? "div" : "body" );
1420 testElementStyle = {
1421 visibility: "hidden",
1422 width: 0,
1423 height: 0,
1424 border: 0,
1425 margin: 0,
1426 background: "none"
1427 };
1428 if ( body ) {
1429 $.extend( testElementStyle, {
1430 position: "absolute",
1431 left: "-1000px",
1432 top: "-1000px"
1433 });
1434 }
1435 for ( i in testElementStyle ) {
1436 testElement.style[ i ] = testElementStyle[ i ];
1437 }
1438 testElement.appendChild( div );
1439 testElementParent = body || document.documentElement;
1440 testElementParent.insertBefore( testElement, testElementParent.firstChild );
1441
1442 div.style.cssText = "position: absolute; left: 10.7432222px;";
1443
1444 offsetLeft = $( div ).offset().left;
1445 $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11;
1446
1447 testElement.innerHTML = "";
1448 testElementParent.removeChild( testElement );
1449 })();
1450
1451 // DEPRECATED
1452 if ( $.uiBackCompat !== false ) {
1453 // offset option
1454 (function( $ ) {
1455 var _position = $.fn.position;
1456 $.fn.position = function( options ) {
1457 if ( !options || !options.offset ) {
1458 return _position.call( this, options );
1459 }
1460 var offset = options.offset.split( " " ),
1461 at = options.at.split( " " );
1462 if ( offset.length === 1 ) {
1463 offset[ 1 ] = offset[ 0 ];
1464 }
1465 if ( /^\d/.test( offset[ 0 ] ) ) {
1466 offset[ 0 ] = "+" + offset[ 0 ];
1467 }
1468 if ( /^\d/.test( offset[ 1 ] ) ) {
1469 offset[ 1 ] = "+" + offset[ 1 ];
1470 }
1471 if ( at.length === 1 ) {
1472 if ( /left|center|right/.test( at[ 0 ] ) ) {
1473 at[ 1 ] = "center";
1474 } else {
1475 at[ 1 ] = at[ 0 ];
1476 at[ 0 ] = "center";
1477 }
1478 }
1479 return _position.call( this, $.extend( options, {
1480 at: at[ 0 ] + offset[ 0 ] + " " + at[ 1 ] + offset[ 1 ],
1481 offset: undefined
1482 } ) );
1483 };
1484 }( jQuery ) );
1485 }
1486
1487 }( jQuery ) );
1488 (function( $, undefined ) {
1489
1490 $.widget("ui.draggable", $.ui.mouse, {
1491 version: "1.9.0",
1492 widgetEventPrefix: "drag",
1493 options: {
1494 addClasses: true,
1495 appendTo: "parent",
1496 axis: false,
1497 connectToSortable: false,
1498 containment: false,
1499 cursor: "auto",
1500 cursorAt: false,
1501 grid: false,
1502 handle: false,
1503 helper: "original",
1504 iframeFix: false,
1505 opacity: false,
1506 refreshPositions: false,
1507 revert: false,
1508 revertDuration: 500,
1509 scope: "default",
1510 scroll: true,
1511 scrollSensitivity: 20,
1512 scrollSpeed: 20,
1513 snap: false,
1514 snapMode: "both",
1515 snapTolerance: 20,
1516 stack: false,
1517 zIndex: false
1518 },
1519 _create: function() {
1520
1521 if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position")))
1522 this.element[0].style.position = 'relative';
1523
1524 (this.options.addClasses && this.element.addClass("ui-draggable"));
1525 (this.options.disabled && this.element.addClass("ui-draggable-disabled"));
1526
1527 this._mouseInit();
1528
1529 },
1530
1531 _destroy: function() {
1532 this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
1533 this._mouseDestroy();
1534 },
1535
1536 _mouseCapture: function(event) {
1537
1538 var o = this.options;
1539
1540 // among others, prevent a drag on a resizable-handle
1541 if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle'))
1542 return false;
1543
1544 //Quit if we're not on a valid handle
1545 this.handle = this._getHandle(event);
1546 if (!this.handle)
1547 return false;
1548
1549 $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
1550 $('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>')
1551 .css({
1552 width: this.offsetWidth+"px", height: this.offsetHeight+"px",
1553 position: "absolute", opacity: "0.001", zIndex: 1000
1554 })
1555 .css($(this).offset())
1556 .appendTo("body");
1557 });
1558
1559 return true;
1560
1561 },
1562
1563 _mouseStart: function(event) {
1564
1565 var o = this.options;
1566
1567 //Create and append the visible helper
1568 this.helper = this._createHelper(event);
1569
1570 this.helper.addClass("ui-draggable-dragging");
1571
1572 //Cache the helper size
1573 this._cacheHelperProportions();
1574
1575 //If ddmanager is used for droppables, set the global draggable
1576 if($.ui.ddmanager)
1577 $.ui.ddmanager.current = this;
1578
1579 /*
1580 * - Position generation -
1581 * This block generates everything position related - it's the core of draggables.
1582 */
1583
1584 //Cache the margins of the original element
1585 this._cacheMargins();
1586
1587 //Store the helper's css position
1588 this.cssPosition = this.helper.css("position");
1589 this.scrollParent = this.helper.scrollParent();
1590
1591 //The element's absolute position on the page minus margins
1592 this.offset = this.positionAbs = this.element.offset();
1593 this.offset = {
1594 top: this.offset.top - this.margins.top,
1595 left: this.offset.left - this.margins.left
1596 };
1597
1598 $.extend(this.offset, {
1599 click: { //Where the click happened, relative to the element
1600 left: event.pageX - this.offset.left,
1601 top: event.pageY - this.offset.top
1602 },
1603 parent: this._getParentOffset(),
1604 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
1605 });
1606
1607 //Generate the original position
1608 this.originalPosition = this.position = this._generatePosition(event);
1609 this.originalPageX = event.pageX;
1610 this.originalPageY = event.pageY;
1611
1612 //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
1613 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
1614
1615 //Set a containment if given in the options
1616 if(o.containment)
1617 this._setContainment();
1618
1619 //Trigger event + callbacks
1620 if(this._trigger("start", event) === false) {
1621 this._clear();
1622 return false;
1623 }
1624
1625 //Recache the helper size
1626 this._cacheHelperProportions();
1627
1628 //Prepare the droppable offsets
1629 if ($.ui.ddmanager && !o.dropBehaviour)
1630 $.ui.ddmanager.prepareOffsets(this, event);
1631
1632
1633 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
1634
1635 //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
1636 if ( $.ui.ddmanager ) $.ui.ddmanager.dragStart(this, event);
1637
1638 return true;
1639 },
1640
1641 _mouseDrag: function(event, noPropagation) {
1642
1643 //Compute the helpers position
1644 this.position = this._generatePosition(event);
1645 this.positionAbs = this._convertPositionTo("absolute");
1646
1647 //Call plugins and callbacks and use the resulting position if something is returned
1648 if (!noPropagation) {
1649 var ui = this._uiHash();
1650 if(this._trigger('drag', event, ui) === false) {
1651 this._mouseUp({});
1652 return false;
1653 }
1654 this.position = ui.position;
1655 }
1656
1657 if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
1658 if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
1659 if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
1660
1661 return false;
1662 },
1663
1664 _mouseStop: function(event) {
1665
1666 //If we are using droppables, inform the manager about the drop
1667 var dropped = false;
1668 if ($.ui.ddmanager && !this.options.dropBehaviour)
1669 dropped = $.ui.ddmanager.drop(this, event);
1670
1671 //if a drop comes from outside (a sortable)
1672 if(this.dropped) {
1673 dropped = this.dropped;
1674 this.dropped = false;
1675 }
1676
1677 //if the original element is no longer in the DOM don't bother to continue (see #8269)
1678 var element = this.element[0], elementInDom = false;
1679 while ( element && (element = element.parentNode) ) {
1680 if (element == document ) {
1681 elementInDom = true;
1682 }
1683 }
1684 if ( !elementInDom && this.options.helper === "original" )
1685 return false;
1686
1687 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))) {
1688 var that = this;
1689 $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
1690 if(that._trigger("stop", event) !== false) {
1691 that._clear();
1692 }
1693 });
1694 } else {
1695 if(this._trigger("stop", event) !== false) {
1696 this._clear();
1697 }
1698 }
1699
1700 return false;
1701 },
1702
1703 _mouseUp: function(event) {
1704 //Remove frame helpers
1705 $("div.ui-draggable-iframeFix").each(function() {
1706 this.parentNode.removeChild(this);
1707 });
1708
1709 //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
1710 if( $.ui.ddmanager ) $.ui.ddmanager.dragStop(this, event);
1711
1712 return $.ui.mouse.prototype._mouseUp.call(this, event);
1713 },
1714
1715 cancel: function() {
1716
1717 if(this.helper.is(".ui-draggable-dragging")) {
1718 this._mouseUp({});
1719 } else {
1720 this._clear();
1721 }
1722
1723 return this;
1724
1725 },
1726
1727 _getHandle: function(event) {
1728
1729 var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false;
1730 $(this.options.handle, this.element)
1731 .find("*")
1732 .andSelf()
1733 .each(function() {
1734 if(this == event.target) handle = true;
1735 });
1736
1737 return handle;
1738
1739 },
1740
1741 _createHelper: function(event) {
1742
1743 var o = this.options;
1744 var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone().removeAttr('id') : this.element);
1745
1746 if(!helper.parents('body').length)
1747 helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo));
1748
1749 if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position")))
1750 helper.css("position", "absolute");
1751
1752 return helper;
1753
1754 },
1755
1756 _adjustOffsetFromHelper: function(obj) {
1757 if (typeof obj == 'string') {
1758 obj = obj.split(' ');
1759 }
1760 if ($.isArray(obj)) {
1761 obj = {left: +obj[0], top: +obj[1] || 0};
1762 }
1763 if ('left' in obj) {
1764 this.offset.click.left = obj.left + this.margins.left;
1765 }
1766 if ('right' in obj) {
1767 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
1768 }
1769 if ('top' in obj) {
1770 this.offset.click.top = obj.top + this.margins.top;
1771 }
1772 if ('bottom' in obj) {
1773 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
1774 }
1775 },
1776
1777 _getParentOffset: function() {
1778
1779 //Get the offsetParent and cache its position
1780 this.offsetParent = this.helper.offsetParent();
1781 var po = this.offsetParent.offset();
1782
1783 // This is a special case where we need to modify a offset calculated on start, since the following happened:
1784 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
1785 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
1786 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
1787 if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
1788 po.left += this.scrollParent.scrollLeft();
1789 po.top += this.scrollParent.scrollTop();
1790 }
1791
1792 if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information
1793 || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix
1794 po = { top: 0, left: 0 };
1795
1796 return {
1797 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
1798 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
1799 };
1800
1801 },
1802
1803 _getRelativeOffset: function() {
1804
1805 if(this.cssPosition == "relative") {
1806 var p = this.element.position();
1807 return {
1808 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
1809 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
1810 };
1811 } else {
1812 return { top: 0, left: 0 };
1813 }
1814
1815 },
1816
1817 _cacheMargins: function() {
1818 this.margins = {
1819 left: (parseInt(this.element.css("marginLeft"),10) || 0),
1820 top: (parseInt(this.element.css("marginTop"),10) || 0),
1821 right: (parseInt(this.element.css("marginRight"),10) || 0),
1822 bottom: (parseInt(this.element.css("marginBottom"),10) || 0)
1823 };
1824 },
1825
1826 _cacheHelperProportions: function() {
1827 this.helperProportions = {
1828 width: this.helper.outerWidth(),
1829 height: this.helper.outerHeight()
1830 };
1831 },
1832
1833 _setContainment: function() {
1834
1835 var o = this.options;
1836 if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
1837 if(o.containment == 'document' || o.containment == 'window') this.containment = [
1838 o.containment == 'document' ? 0 : $(window).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
1839 o.containment == 'document' ? 0 : $(window).scrollTop() - this.offset.relative.top - this.offset.parent.top,
1840 (o.containment == 'document' ? 0 : $(window).scrollLeft()) + $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left,
1841 (o.containment == 'document' ? 0 : $(window).scrollTop()) + ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
1842 ];
1843
1844 if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) {
1845 var c = $(o.containment);
1846 var ce = c[0]; if(!ce) return;
1847 var co = c.offset();
1848 var over = ($(ce).css("overflow") != 'hidden');
1849
1850 this.containment = [
1851 (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0),
1852 (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0),
1853 (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,
1854 (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
1855 ];
1856 this.relative_container = c;
1857
1858 } else if(o.containment.constructor == Array) {
1859 this.containment = o.containment;
1860 }
1861
1862 },
1863
1864 _convertPositionTo: function(d, pos) {
1865
1866 if(!pos) pos = this.position;
1867 var mod = d == "absolute" ? 1 : -1;
1868 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);
1869
1870 return {
1871 top: (
1872 pos.top // The absolute mouse position
1873 + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent
1874 + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border)
1875 - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
1876 ),
1877 left: (
1878 pos.left // The absolute mouse position
1879 + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent
1880 + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border)
1881 - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
1882 )
1883 };
1884
1885 },
1886
1887 _generatePosition: function(event) {
1888
1889 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);
1890 var pageX = event.pageX;
1891 var pageY = event.pageY;
1892
1893 /*
1894 * - Position constraining -
1895 * Constrain the position to a mix of grid, containment.
1896 */
1897
1898 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
1899 var containment;
1900 if(this.containment) {
1901 if (this.relative_container){
1902 var co = this.relative_container.offset();
1903 containment = [ this.containment[0] + co.left,
1904 this.containment[1] + co.top,
1905 this.containment[2] + co.left,
1906 this.containment[3] + co.top ];
1907 }
1908 else {
1909 containment = this.containment;
1910 }
1911
1912 if(event.pageX - this.offset.click.left < containment[0]) pageX = containment[0] + this.offset.click.left;
1913 if(event.pageY - this.offset.click.top < containment[1]) pageY = containment[1] + this.offset.click.top;
1914 if(event.pageX - this.offset.click.left > containment[2]) pageX = containment[2] + this.offset.click.left;
1915 if(event.pageY - this.offset.click.top > containment[3]) pageY = containment[3] + this.offset.click.top;
1916 }
1917
1918 if(o.grid) {
1919 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
1920 var top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
1921 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;
1922
1923 var left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
1924 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;
1925 }
1926
1927 }
1928
1929 return {
1930 top: (
1931 pageY // The absolute mouse position
1932 - this.offset.click.top // Click offset (relative to the element)
1933 - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent
1934 - this.offset.parent.top // The offsetParent's offset without borders (offset + border)
1935 + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
1936 ),
1937 left: (
1938 pageX // The absolute mouse position
1939 - this.offset.click.left // Click offset (relative to the element)
1940 - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent
1941 - this.offset.parent.left // The offsetParent's offset without borders (offset + border)
1942 + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
1943 )
1944 };
1945
1946 },
1947
1948 _clear: function() {
1949 this.helper.removeClass("ui-draggable-dragging");
1950 if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove();
1951 //if($.ui.ddmanager) $.ui.ddmanager.current = null;
1952 this.helper = null;
1953 this.cancelHelperRemoval = false;
1954 },
1955
1956 // From now on bulk stuff - mainly helpers
1957
1958 _trigger: function(type, event, ui) {
1959 ui = ui || this._uiHash();
1960 $.ui.plugin.call(this, type, [event, ui]);
1961 if(type == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins
1962 return $.Widget.prototype._trigger.call(this, type, event, ui);
1963 },
1964
1965 plugins: {},
1966
1967 _uiHash: function(event) {
1968 return {
1969 helper: this.helper,
1970 position: this.position,
1971 originalPosition: this.originalPosition,
1972 offset: this.positionAbs
1973 };
1974 }
1975
1976 });
1977
1978 $.ui.plugin.add("draggable", "connectToSortable", {
1979 start: function(event, ui) {
1980
1981 var inst = $(this).data("draggable"), o = inst.options,
1982 uiSortable = $.extend({}, ui, { item: inst.element });
1983 inst.sortables = [];
1984 $(o.connectToSortable).each(function() {
1985 var sortable = $.data(this, 'sortable');
1986 if (sortable && !sortable.options.disabled) {
1987 inst.sortables.push({
1988 instance: sortable,
1989 shouldRevert: sortable.options.revert
1990 });
1991 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).
1992 sortable._trigger("activate", event, uiSortable);
1993 }
1994 });
1995
1996 },
1997 stop: function(event, ui) {
1998
1999 //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
2000 var inst = $(this).data("draggable"),
2001 uiSortable = $.extend({}, ui, { item: inst.element });
2002
2003 $.each(inst.sortables, function() {
2004 if(this.instance.isOver) {
2005
2006 this.instance.isOver = 0;
2007
2008 inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
2009 this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
2010
2011 //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid'
2012 if(this.shouldRevert) this.instance.options.revert = true;
2013
2014 //Trigger the stop of the sortable
2015 this.instance._mouseStop(event);
2016
2017 this.instance.options.helper = this.instance.options._helper;
2018
2019 //If the helper has been the original item, restore properties in the sortable
2020 if(inst.options.helper == 'original')
2021 this.instance.currentItem.css({ top: 'auto', left: 'auto' });
2022
2023 } else {
2024 this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
2025 this.instance._trigger("deactivate", event, uiSortable);
2026 }
2027
2028 });
2029
2030 },
2031 drag: function(event, ui) {
2032
2033 var inst = $(this).data("draggable"), that = this;
2034
2035 var checkPos = function(o) {
2036 var dyClick = this.offset.click.top, dxClick = this.offset.click.left;
2037 var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left;
2038 var itemHeight = o.height, itemWidth = o.width;
2039 var itemTop = o.top, itemLeft = o.left;
2040
2041 return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth);
2042 };
2043
2044 $.each(inst.sortables, function(i) {
2045
2046 //Copy over some variables to allow calling the sortable's native _intersectsWith
2047 this.instance.positionAbs = inst.positionAbs;
2048 this.instance.helperProportions = inst.helperProportions;
2049 this.instance.offset.click = inst.offset.click;
2050
2051 if(this.instance._intersectsWith(this.instance.containerCache)) {
2052
2053 //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
2054 if(!this.instance.isOver) {
2055
2056 this.instance.isOver = 1;
2057 //Now we fake the start of dragging for the sortable instance,
2058 //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
2059 //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)
2060 this.instance.currentItem = $(that).clone().removeAttr('id').appendTo(this.instance.element).data("sortable-item", true);
2061 this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
2062 this.instance.options.helper = function() { return ui.helper[0]; };
2063
2064 event.target = this.instance.currentItem[0];
2065 this.instance._mouseCapture(event, true);
2066 this.instance._mouseStart(event, true, true);
2067
2068 //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
2069 this.instance.offset.click.top = inst.offset.click.top;
2070 this.instance.offset.click.left = inst.offset.click.left;
2071 this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
2072 this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
2073
2074 inst._trigger("toSortable", event);
2075 inst.dropped = this.instance.element; //draggable revert needs that
2076 //hack so receive/update callbacks work (mostly)
2077 inst.currentItem = inst.element;
2078 this.instance.fromOutside = inst;
2079
2080 }
2081
2082 //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
2083 if(this.instance.currentItem) this.instance._mouseDrag(event);
2084
2085 } else {
2086
2087 //If it doesn't intersect with the sortable, and it intersected before,
2088 //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
2089 if(this.instance.isOver) {
2090
2091 this.instance.isOver = 0;
2092 this.instance.cancelHelperRemoval = true;
2093
2094 //Prevent reverting on this forced stop
2095 this.instance.options.revert = false;
2096
2097 // The out event needs to be triggered independently
2098 this.instance._trigger('out', event, this.instance._uiHash(this.instance));
2099
2100 this.instance._mouseStop(event, true);
2101 this.instance.options.helper = this.instance.options._helper;
2102
2103 //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
2104 this.instance.currentItem.remove();
2105 if(this.instance.placeholder) this.instance.placeholder.remove();
2106
2107 inst._trigger("fromSortable", event);
2108 inst.dropped = false; //draggable revert needs that
2109 }
2110
2111 };
2112
2113 });
2114
2115 }
2116 });
2117
2118 $.ui.plugin.add("draggable", "cursor", {
2119 start: function(event, ui) {
2120 var t = $('body'), o = $(this).data('draggable').options;
2121 if (t.css("cursor")) o._cursor = t.css("cursor");
2122 t.css("cursor", o.cursor);
2123 },
2124 stop: function(event, ui) {
2125 var o = $(this).data('draggable').options;
2126 if (o._cursor) $('body').css("cursor", o._cursor);
2127 }
2128 });
2129
2130 $.ui.plugin.add("draggable", "opacity", {
2131 start: function(event, ui) {
2132 var t = $(ui.helper), o = $(this).data('draggable').options;
2133 if(t.css("opacity")) o._opacity = t.css("opacity");
2134 t.css('opacity', o.opacity);
2135 },
2136 stop: function(event, ui) {
2137 var o = $(this).data('draggable').options;
2138 if(o._opacity) $(ui.helper).css('opacity', o._opacity);
2139 }
2140 });
2141
2142 $.ui.plugin.add("draggable", "scroll", {
2143 start: function(event, ui) {
2144 var i = $(this).data("draggable");
2145 if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset();
2146 },
2147 drag: function(event, ui) {
2148
2149 var i = $(this).data("draggable"), o = i.options, scrolled = false;
2150
2151 if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') {
2152
2153 if(!o.axis || o.axis != 'x') {
2154 if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
2155 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
2156 else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity)
2157 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
2158 }
2159
2160 if(!o.axis || o.axis != 'y') {
2161 if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
2162 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
2163 else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity)
2164 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
2165 }
2166
2167 } else {
2168
2169 if(!o.axis || o.axis != 'x') {
2170 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
2171 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
2172 else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
2173 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
2174 }
2175
2176 if(!o.axis || o.axis != 'y') {
2177 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
2178 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
2179 else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
2180 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
2181 }
2182
2183 }
2184
2185 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
2186 $.ui.ddmanager.prepareOffsets(i, event);
2187
2188 }
2189 });
2190
2191 $.ui.plugin.add("draggable", "snap", {
2192 start: function(event, ui) {
2193
2194 var i = $(this).data("draggable"), o = i.options;
2195 i.snapElements = [];
2196
2197 $(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) : o.snap).each(function() {
2198 var $t = $(this); var $o = $t.offset();
2199 if(this != i.element[0]) i.snapElements.push({
2200 item: this,
2201 width: $t.outerWidth(), height: $t.outerHeight(),
2202 top: $o.top, left: $o.left
2203 });
2204 });
2205
2206 },
2207 drag: function(event, ui) {
2208
2209 var inst = $(this).data("draggable"), o = inst.options;
2210 var d = o.snapTolerance;
2211
2212 var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
2213 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
2214
2215 for (var i = inst.snapElements.length - 1; i >= 0; i--){
2216
2217 var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width,
2218 t = inst.snapElements[i].top, b = t + inst.snapElements[i].height;
2219
2220 //Yes, I know, this is insane ;)
2221 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))) {
2222 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 })));
2223 inst.snapElements[i].snapping = false;
2224 continue;
2225 }
2226
2227 if(o.snapMode != 'inner') {
2228 var ts = Math.abs(t - y2) <= d;
2229 var bs = Math.abs(b - y1) <= d;
2230 var ls = Math.abs(l - x2) <= d;
2231 var rs = Math.abs(r - x1) <= d;
2232 if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
2233 if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
2234 if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
2235 if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
2236 }
2237
2238 var first = (ts || bs || ls || rs);
2239
2240 if(o.snapMode != 'outer') {
2241 var ts = Math.abs(t - y1) <= d;
2242 var bs = Math.abs(b - y2) <= d;
2243 var ls = Math.abs(l - x1) <= d;
2244 var rs = Math.abs(r - x2) <= d;
2245 if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
2246 if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
2247 if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
2248 if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
2249 }
2250
2251 if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first))
2252 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
2253 inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
2254
2255 };
2256
2257 }
2258 });
2259
2260 $.ui.plugin.add("draggable", "stack", {
2261 start: function(event, ui) {
2262
2263 var o = $(this).data("draggable").options;
2264
2265 var group = $.makeArray($(o.stack)).sort(function(a,b) {
2266 return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0);
2267 });
2268 if (!group.length) { return; }
2269
2270 var min = parseInt(group[0].style.zIndex) || 0;
2271 $(group).each(function(i) {
2272 this.style.zIndex = min + i;
2273 });
2274
2275 this[0].style.zIndex = min + group.length;
2276
2277 }
2278 });
2279
2280 $.ui.plugin.add("draggable", "zIndex", {
2281 start: function(event, ui) {
2282 var t = $(ui.helper), o = $(this).data("draggable").options;
2283 if(t.css("zIndex")) o._zIndex = t.css("zIndex");
2284 t.css('zIndex', o.zIndex);
2285 },
2286 stop: function(event, ui) {
2287 var o = $(this).data("draggable").options;
2288 if(o._zIndex) $(ui.helper).css('zIndex', o._zIndex);
2289 }
2290 });
2291
2292 })(jQuery);
2293 (function( $, undefined ) {
2294
2295 $.widget("ui.droppable", {
2296 version: "1.9.0",
2297 widgetEventPrefix: "drop",
2298 options: {
2299 accept: '*',
2300 activeClass: false,
2301 addClasses: true,
2302 greedy: false,
2303 hoverClass: false,
2304 scope: 'default',
2305 tolerance: 'intersect'
2306 },
2307 _create: function() {
2308
2309 var o = this.options, accept = o.accept;
2310 this.isover = 0; this.isout = 1;
2311
2312 this.accept = $.isFunction(accept) ? accept : function(d) {
2313 return d.is(accept);
2314 };
2315
2316 //Store the droppable's proportions
2317 this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight };
2318
2319 // Add the reference and positions to the manager
2320 $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || [];
2321 $.ui.ddmanager.droppables[o.scope].push(this);
2322
2323 (o.addClasses && this.element.addClass("ui-droppable"));
2324
2325 },
2326
2327 _destroy: function() {
2328 var drop = $.ui.ddmanager.droppables[this.options.scope];
2329 for ( var i = 0; i < drop.length; i++ )
2330 if ( drop[i] == this )
2331 drop.splice(i, 1);
2332
2333 this.element.removeClass("ui-droppable ui-droppable-disabled");
2334 },
2335
2336 _setOption: function(key, value) {
2337
2338 if(key == 'accept') {
2339 this.accept = $.isFunction(value) ? value : function(d) {
2340 return d.is(value);
2341 };
2342 }
2343 $.Widget.prototype._setOption.apply(this, arguments);
2344 },
2345
2346 _activate: function(event) {
2347 var draggable = $.ui.ddmanager.current;
2348 if(this.options.activeClass) this.element.addClass(this.options.activeClass);
2349 (draggable && this._trigger('activate', event, this.ui(draggable)));
2350 },
2351
2352 _deactivate: function(event) {
2353 var draggable = $.ui.ddmanager.current;
2354 if(this.options.activeClass) this.element.removeClass(this.options.activeClass);
2355 (draggable && this._trigger('deactivate', event, this.ui(draggable)));
2356 },
2357
2358 _over: function(event) {
2359
2360 var draggable = $.ui.ddmanager.current;
2361 if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element
2362
2363 if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
2364 if(this.options.hoverClass) this.element.addClass(this.options.hoverClass);
2365 this._trigger('over', event, this.ui(draggable));
2366 }
2367
2368 },
2369
2370 _out: function(event) {
2371
2372 var draggable = $.ui.ddmanager.current;
2373 if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element
2374
2375 if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
2376 if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass);
2377 this._trigger('out', event, this.ui(draggable));
2378 }
2379
2380 },
2381
2382 _drop: function(event,custom) {
2383
2384 var draggable = custom || $.ui.ddmanager.current;
2385 if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element
2386
2387 var childrenIntersection = false;
2388 this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function() {
2389 var inst = $.data(this, 'droppable');
2390 if(
2391 inst.options.greedy
2392 && !inst.options.disabled
2393 && inst.options.scope == draggable.options.scope
2394 && inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element))
2395 && $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)
2396 ) { childrenIntersection = true; return false; }
2397 });
2398 if(childrenIntersection) return false;
2399
2400 if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
2401 if(this.options.activeClass) this.element.removeClass(this.options.activeClass);
2402 if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass);
2403 this._trigger('drop', event, this.ui(draggable));
2404 return this.element;
2405 }
2406
2407 return false;
2408
2409 },
2410
2411 ui: function(c) {
2412 return {
2413 draggable: (c.currentItem || c.element),
2414 helper: c.helper,
2415 position: c.position,
2416 offset: c.positionAbs
2417 };
2418 }
2419
2420 });
2421
2422 $.ui.intersect = function(draggable, droppable, toleranceMode) {
2423
2424 if (!droppable.offset) return false;
2425
2426 var x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width,
2427 y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height;
2428 var l = droppable.offset.left, r = l + droppable.proportions.width,
2429 t = droppable.offset.top, b = t + droppable.proportions.height;
2430
2431 switch (toleranceMode) {
2432 case 'fit':
2433 return (l <= x1 && x2 <= r
2434 && t <= y1 && y2 <= b);
2435 break;
2436 case 'intersect':
2437 return (l < x1 + (draggable.helperProportions.width / 2) // Right Half
2438 && x2 - (draggable.helperProportions.width / 2) < r // Left Half
2439 && t < y1 + (draggable.helperProportions.height / 2) // Bottom Half
2440 && y2 - (draggable.helperProportions.height / 2) < b ); // Top Half
2441 break;
2442 case 'pointer':
2443 var draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left),
2444 draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top),
2445 isOver = $.ui.isOver(draggableTop, draggableLeft, t, l, droppable.proportions.height, droppable.proportions.width);
2446 return isOver;
2447 break;
2448 case 'touch':
2449 return (
2450 (y1 >= t && y1 <= b) || // Top edge touching
2451 (y2 >= t && y2 <= b) || // Bottom edge touching
2452 (y1 < t && y2 > b) // Surrounded vertically
2453 ) && (
2454 (x1 >= l && x1 <= r) || // Left edge touching
2455 (x2 >= l && x2 <= r) || // Right edge touching
2456 (x1 < l && x2 > r) // Surrounded horizontally
2457 );
2458 break;
2459 default:
2460 return false;
2461 break;
2462 }
2463
2464 };
2465
2466 /*
2467 This manager tracks offsets of draggables and droppables
2468 */
2469 $.ui.ddmanager = {
2470 current: null,
2471 droppables: { 'default': [] },
2472 prepareOffsets: function(t, event) {
2473
2474 var m = $.ui.ddmanager.droppables[t.options.scope] || [];
2475 var type = event ? event.type : null; // workaround for #2317
2476 var list = (t.currentItem || t.element).find(":data(droppable)").andSelf();
2477
2478 droppablesLoop: for (var i = 0; i < m.length; i++) {
2479
2480 if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) continue; //No disabled and non-accepted
2481 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
2482 m[i].visible = m[i].element.css("display") != "none"; if(!m[i].visible) continue; //If the element is not visible, continue
2483
2484 if(type == "mousedown") m[i]._activate.call(m[i], event); //Activate the droppable if used directly from draggables
2485
2486 m[i].offset = m[i].element.offset();
2487 m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight };
2488
2489 }
2490
2491 },
2492 drop: function(draggable, event) {
2493
2494 var dropped = false;
2495 $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
2496
2497 if(!this.options) return;
2498 if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance))
2499 dropped = this._drop.call(this, event) || dropped;
2500
2501 if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
2502 this.isout = 1; this.isover = 0;
2503 this._deactivate.call(this, event);
2504 }
2505
2506 });
2507 return dropped;
2508
2509 },
2510 dragStart: function( draggable, event ) {
2511 //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
2512 draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
2513 if( !draggable.options.refreshPositions ) $.ui.ddmanager.prepareOffsets( draggable, event );
2514 });
2515 },
2516 drag: function(draggable, event) {
2517
2518 //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
2519 if(draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event);
2520
2521 //Run through all droppables and check their positions based on specific tolerance options
2522 $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
2523
2524 if(this.options.disabled || this.greedyChild || !this.visible) return;
2525 var intersects = $.ui.intersect(draggable, this, this.options.tolerance);
2526
2527 var c = !intersects && this.isover == 1 ? 'isout' : (intersects && this.isover == 0 ? 'isover' : null);
2528 if(!c) return;
2529
2530 var parentInstance;
2531 if (this.options.greedy) {
2532 // find droppable parents with same scope
2533 var scope = this.options.scope;
2534 var parent = this.element.parents(':data(droppable)').filter(function () {
2535 return $.data(this, 'droppable').options.scope === scope;
2536 });
2537
2538 if (parent.length) {
2539 parentInstance = $.data(parent[0], 'droppable');
2540 parentInstance.greedyChild = (c == 'isover' ? 1 : 0);
2541 }
2542 }
2543
2544 // we just moved into a greedy child
2545 if (parentInstance && c == 'isover') {
2546 parentInstance['isover'] = 0;
2547 parentInstance['isout'] = 1;
2548 parentInstance._out.call(parentInstance, event);
2549 }
2550
2551 this[c] = 1; this[c == 'isout' ? 'isover' : 'isout'] = 0;
2552 this[c == "isover" ? "_over" : "_out"].call(this, event);
2553
2554 // we just moved out of a greedy child
2555 if (parentInstance && c == 'isout') {
2556 parentInstance['isout'] = 0;
2557 parentInstance['isover'] = 1;
2558 parentInstance._over.call(parentInstance, event);
2559 }
2560 });
2561
2562 },
2563 dragStop: function( draggable, event ) {
2564 draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
2565 //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
2566 if( !draggable.options.refreshPositions ) $.ui.ddmanager.prepareOffsets( draggable, event );
2567 }
2568 };
2569
2570 })(jQuery);
2571 (function( $, undefined ) {
2572
2573 $.widget("ui.resizable", $.ui.mouse, {
2574 version: "1.9.0",
2575 widgetEventPrefix: "resize",
2576 options: {
2577 alsoResize: false,
2578 animate: false,
2579 animateDuration: "slow",
2580 animateEasing: "swing",
2581 aspectRatio: false,
2582 autoHide: false,
2583 containment: false,
2584 ghost: false,
2585 grid: false,
2586 handles: "e,s,se",
2587 helper: false,
2588 maxHeight: null,
2589 maxWidth: null,
2590 minHeight: 10,
2591 minWidth: 10,
2592 zIndex: 1000
2593 },
2594 _create: function() {
2595
2596 var that = this, o = this.options;
2597 this.element.addClass("ui-resizable");
2598
2599 $.extend(this, {
2600 _aspectRatio: !!(o.aspectRatio),
2601 aspectRatio: o.aspectRatio,
2602 originalElement: this.element,
2603 _proportionallyResizeElements: [],
2604 _helper: o.helper || o.ghost || o.animate ? o.helper || 'ui-resizable-helper' : null
2605 });
2606
2607 //Wrap the element if it cannot hold child nodes
2608 if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {
2609
2610 //Create a wrapper element and set the wrapper to the new current internal element
2611 this.element.wrap(
2612 $('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({
2613 position: this.element.css('position'),
2614 width: this.element.outerWidth(),
2615 height: this.element.outerHeight(),
2616 top: this.element.css('top'),
2617 left: this.element.css('left')
2618 })
2619 );
2620
2621 //Overwrite the original this.element
2622 this.element = this.element.parent().data(
2623 "resizable", this.element.data('resizable')
2624 );
2625
2626 this.elementIsWrapper = true;
2627
2628 //Move margins to the wrapper
2629 this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") });
2630 this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});
2631
2632 //Prevent Safari textarea resize
2633 this.originalResizeStyle = this.originalElement.css('resize');
2634 this.originalElement.css('resize', 'none');
2635
2636 //Push the actual element to our proportionallyResize internal array
2637 this._proportionallyResizeElements.push(this.originalElement.css({ position: 'static', zoom: 1, display: 'block' }));
2638
2639 // avoid IE jump (hard set the margin)
2640 this.originalElement.css({ margin: this.originalElement.css('margin') });
2641
2642 // fix handlers offset
2643 this._proportionallyResize();
2644
2645 }
2646
2647 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' });
2648 if(this.handles.constructor == String) {
2649
2650 if(this.handles == 'all') this.handles = 'n,e,s,w,se,sw,ne,nw';
2651 var n = this.handles.split(","); this.handles = {};
2652
2653 for(var i = 0; i < n.length; i++) {
2654
2655 var handle = $.trim(n[i]), hname = 'ui-resizable-'+handle;
2656 var axis = $('<div class="ui-resizable-handle ' + hname + '"></div>');
2657
2658 // Apply zIndex to all handles - see #7960
2659 axis.css({ zIndex: o.zIndex });
2660
2661 //TODO : What's going on here?
2662 if ('se' == handle) {
2663 axis.addClass('ui-icon ui-icon-gripsmall-diagonal-se');
2664 };
2665
2666 //Insert into internal handles object and append to element
2667 this.handles[handle] = '.ui-resizable-'+handle;
2668 this.element.append(axis);
2669 }
2670
2671 }
2672
2673 this._renderAxis = function(target) {
2674
2675 target = target || this.element;
2676
2677 for(var i in this.handles) {
2678
2679 if(this.handles[i].constructor == String)
2680 this.handles[i] = $(this.handles[i], this.element).show();
2681
2682 //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)
2683 if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {
2684
2685 var axis = $(this.handles[i], this.element), padWrapper = 0;
2686
2687 //Checking the correct pad and border
2688 padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
2689
2690 //The padding type i have to apply...
2691 var padPos = [ 'padding',
2692 /ne|nw|n/.test(i) ? 'Top' :
2693 /se|sw|s/.test(i) ? 'Bottom' :
2694 /^e$/.test(i) ? 'Right' : 'Left' ].join("");
2695
2696 target.css(padPos, padWrapper);
2697
2698 this._proportionallyResize();
2699
2700 }
2701
2702 //TODO: What's that good for? There's not anything to be executed left
2703 if(!$(this.handles[i]).length)
2704 continue;
2705
2706 }
2707 };
2708
2709 //TODO: make renderAxis a prototype function
2710 this._renderAxis(this.element);
2711
2712 this._handles = $('.ui-resizable-handle', this.element)
2713 .disableSelection();
2714
2715 //Matching axis name
2716 this._handles.mouseover(function() {
2717 if (!that.resizing) {
2718 if (this.className)
2719 var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
2720 //Axis, default = se
2721 that.axis = axis && axis[1] ? axis[1] : 'se';
2722 }
2723 });
2724
2725 //If we want to auto hide the elements
2726 if (o.autoHide) {
2727 this._handles.hide();
2728 $(this.element)
2729 .addClass("ui-resizable-autohide")
2730 .mouseenter(function() {
2731 if (o.disabled) return;
2732 $(this).removeClass("ui-resizable-autohide");
2733 that._handles.show();
2734 })
2735 .mouseleave(function(){
2736 if (o.disabled) return;
2737 if (!that.resizing) {
2738 $(this).addClass("ui-resizable-autohide");
2739 that._handles.hide();
2740 }
2741 });
2742 }
2743
2744 //Initialize the mouse interaction
2745 this._mouseInit();
2746
2747 },
2748
2749 _destroy: function() {
2750
2751 this._mouseDestroy();
2752
2753 var _destroy = function(exp) {
2754 $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
2755 .removeData("resizable").removeData("ui-resizable").unbind(".resizable").find('.ui-resizable-handle').remove();
2756 };
2757
2758 //TODO: Unwrap at same DOM position
2759 if (this.elementIsWrapper) {
2760 _destroy(this.element);
2761 var wrapper = this.element;
2762 wrapper.after(
2763 this.originalElement.css({
2764 position: wrapper.css('position'),
2765 width: wrapper.outerWidth(),
2766 height: wrapper.outerHeight(),
2767 top: wrapper.css('top'),
2768 left: wrapper.css('left')
2769 })
2770 ).remove();
2771 }
2772
2773 this.originalElement.css('resize', this.originalResizeStyle);
2774 _destroy(this.originalElement);
2775
2776 return this;
2777 },
2778
2779 _mouseCapture: function(event) {
2780 var handle = false;
2781 for (var i in this.handles) {
2782 if ($(this.handles[i])[0] == event.target) {
2783 handle = true;
2784 }
2785 }
2786
2787 return !this.options.disabled && handle;
2788 },
2789
2790 _mouseStart: function(event) {
2791
2792 var o = this.options, iniPos = this.element.position(), el = this.element;
2793
2794 this.resizing = true;
2795 this.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() };
2796
2797 // bugfix for http://dev.jquery.com/ticket/1749
2798 if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) {
2799 el.css({ position: 'absolute', top: iniPos.top, left: iniPos.left });
2800 }
2801
2802 this._renderProxy();
2803
2804 var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top'));
2805
2806 if (o.containment) {
2807 curleft += $(o.containment).scrollLeft() || 0;
2808 curtop += $(o.containment).scrollTop() || 0;
2809 }
2810
2811 //Store needed variables
2812 this.offset = this.helper.offset();
2813 this.position = { left: curleft, top: curtop };
2814 this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
2815 this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
2816 this.originalPosition = { left: curleft, top: curtop };
2817 this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };
2818 this.originalMousePosition = { left: event.pageX, top: event.pageY };
2819
2820 //Aspect Ratio
2821 this.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1);
2822
2823 var cursor = $('.ui-resizable-' + this.axis).css('cursor');
2824 $('body').css('cursor', cursor == 'auto' ? this.axis + '-resize' : cursor);
2825
2826 el.addClass("ui-resizable-resizing");
2827 this._propagate("start", event);
2828 return true;
2829 },
2830
2831 _mouseDrag: function(event) {
2832
2833 //Increase performance, avoid regex
2834 var el = this.helper, o = this.options, props = {},
2835 that = this, smp = this.originalMousePosition, a = this.axis;
2836
2837 var dx = (event.pageX-smp.left)||0, dy = (event.pageY-smp.top)||0;
2838 var trigger = this._change[a];
2839 if (!trigger) return false;
2840
2841 // Calculate the attrs that will be change
2842 var data = trigger.apply(this, [event, dx, dy]);
2843
2844 // Put this in the mouseDrag handler since the user can start pressing shift while resizing
2845 this._updateVirtualBoundaries(event.shiftKey);
2846 if (this._aspectRatio || event.shiftKey)
2847 data = this._updateRatio(data, event);
2848
2849 data = this._respectSize(data, event);
2850
2851 // plugins callbacks need to be called first
2852 this._propagate("resize", event);
2853
2854 el.css({
2855 top: this.position.top + "px", left: this.position.left + "px",
2856 width: this.size.width + "px", height: this.size.height + "px"
2857 });
2858
2859 if (!this._helper && this._proportionallyResizeElements.length)
2860 this._proportionallyResize();
2861
2862 this._updateCache(data);
2863
2864 // calling the user callback at the end
2865 this._trigger('resize', event, this.ui());
2866
2867 return false;
2868 },
2869
2870 _mouseStop: function(event) {
2871
2872 this.resizing = false;
2873 var o = this.options, that = this;
2874
2875 if(this._helper) {
2876 var pr = this._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName),
2877 soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : that.sizeDiff.height,
2878 soffsetw = ista ? 0 : that.sizeDiff.width;
2879
2880 var s = { width: (that.helper.width() - soffsetw), height: (that.helper.height() - soffseth) },
2881 left = (parseInt(that.element.css('left'), 10) + (that.position.left - that.originalPosition.left)) || null,
2882 top = (parseInt(that.element.css('top'), 10) + (that.position.top - that.originalPosition.top)) || null;
2883
2884 if (!o.animate)
2885 this.element.css($.extend(s, { top: top, left: left }));
2886
2887 that.helper.height(that.size.height);
2888 that.helper.width(that.size.width);
2889
2890 if (this._helper && !o.animate) this._proportionallyResize();
2891 }
2892
2893 $('body').css('cursor', 'auto');
2894
2895 this.element.removeClass("ui-resizable-resizing");
2896
2897 this._propagate("stop", event);
2898
2899 if (this._helper) this.helper.remove();
2900 return false;
2901
2902 },
2903
2904 _updateVirtualBoundaries: function(forceAspectRatio) {
2905 var o = this.options, pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b;
2906
2907 b = {
2908 minWidth: isNumber(o.minWidth) ? o.minWidth : 0,
2909 maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity,
2910 minHeight: isNumber(o.minHeight) ? o.minHeight : 0,
2911 maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity
2912 };
2913
2914 if(this._aspectRatio || forceAspectRatio) {
2915 // We want to create an enclosing box whose aspect ration is the requested one
2916 // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension
2917 pMinWidth = b.minHeight * this.aspectRatio;
2918 pMinHeight = b.minWidth / this.aspectRatio;
2919 pMaxWidth = b.maxHeight * this.aspectRatio;
2920 pMaxHeight = b.maxWidth / this.aspectRatio;
2921
2922 if(pMinWidth > b.minWidth) b.minWidth = pMinWidth;
2923 if(pMinHeight > b.minHeight) b.minHeight = pMinHeight;
2924 if(pMaxWidth < b.maxWidth) b.maxWidth = pMaxWidth;
2925 if(pMaxHeight < b.maxHeight) b.maxHeight = pMaxHeight;
2926 }
2927 this._vBoundaries = b;
2928 },
2929
2930 _updateCache: function(data) {
2931 var o = this.options;
2932 this.offset = this.helper.offset();
2933 if (isNumber(data.left)) this.position.left = data.left;
2934 if (isNumber(data.top)) this.position.top = data.top;
2935 if (isNumber(data.height)) this.size.height = data.height;
2936 if (isNumber(data.width)) this.size.width = data.width;
2937 },
2938
2939 _updateRatio: function(data, event) {
2940
2941 var o = this.options, cpos = this.position, csize = this.size, a = this.axis;
2942
2943 if (isNumber(data.height)) data.width = (data.height * this.aspectRatio);
2944 else if (isNumber(data.width)) data.height = (data.width / this.aspectRatio);
2945
2946 if (a == 'sw') {
2947 data.left = cpos.left + (csize.width - data.width);
2948 data.top = null;
2949 }
2950 if (a == 'nw') {
2951 data.top = cpos.top + (csize.height - data.height);
2952 data.left = cpos.left + (csize.width - data.width);
2953 }
2954
2955 return data;
2956 },
2957
2958 _respectSize: function(data, event) {
2959
2960 var el = this.helper, o = this._vBoundaries, pRatio = this._aspectRatio || event.shiftKey, a = this.axis,
2961 ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
2962 isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height);
2963
2964 if (isminw) data.width = o.minWidth;
2965 if (isminh) data.height = o.minHeight;
2966 if (ismaxw) data.width = o.maxWidth;
2967 if (ismaxh) data.height = o.maxHeight;
2968
2969 var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height;
2970 var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
2971
2972 if (isminw && cw) data.left = dw - o.minWidth;
2973 if (ismaxw && cw) data.left = dw - o.maxWidth;
2974 if (isminh && ch) data.top = dh - o.minHeight;
2975 if (ismaxh && ch) data.top = dh - o.maxHeight;
2976
2977 // fixing jump error on top/left - bug #2330
2978 var isNotwh = !data.width && !data.height;
2979 if (isNotwh && !data.left && data.top) data.top = null;
2980 else if (isNotwh && !data.top && data.left) data.left = null;
2981
2982 return data;
2983 },
2984
2985 _proportionallyResize: function() {
2986
2987 var o = this.options;
2988 if (!this._proportionallyResizeElements.length) return;
2989 var element = this.helper || this.element;
2990
2991 for (var i=0; i < this._proportionallyResizeElements.length; i++) {
2992
2993 var prel = this._proportionallyResizeElements[i];
2994
2995 if (!this.borderDif) {
2996 var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')],
2997 p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')];
2998
2999 this.borderDif = $.map(b, function(v, i) {
3000 var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0;
3001 return border + padding;
3002 });
3003 }
3004
3005 prel.css({
3006 height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0,
3007 width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0
3008 });
3009
3010 };
3011
3012 },
3013
3014 _renderProxy: function() {
3015
3016 var el = this.element, o = this.options;
3017 this.elementOffset = el.offset();
3018
3019 if(this._helper) {
3020
3021 this.helper = this.helper || $('<div style="overflow:hidden;"></div>');
3022
3023 // fix ie6 offset TODO: This seems broken
3024 var ie6 = $.browser.msie && $.browser.version < 7, ie6offset = (ie6 ? 1 : 0),
3025 pxyoffset = ( ie6 ? 2 : -1 );
3026
3027 this.helper.addClass(this._helper).css({
3028 width: this.element.outerWidth() + pxyoffset,
3029 height: this.element.outerHeight() + pxyoffset,
3030 position: 'absolute',
3031 left: this.elementOffset.left - ie6offset +'px',
3032 top: this.elementOffset.top - ie6offset +'px',
3033 zIndex: ++o.zIndex //TODO: Don't modify option
3034 });
3035
3036 this.helper
3037 .appendTo("body")
3038 .disableSelection();
3039
3040 } else {
3041 this.helper = this.element;
3042 }
3043
3044 },
3045
3046 _change: {
3047 e: function(event, dx, dy) {
3048 return { width: this.originalSize.width + dx };
3049 },
3050 w: function(event, dx, dy) {
3051 var o = this.options, cs = this.originalSize, sp = this.originalPosition;
3052 return { left: sp.left + dx, width: cs.width - dx };
3053 },
3054 n: function(event, dx, dy) {
3055 var o = this.options, cs = this.originalSize, sp = this.originalPosition;
3056 return { top: sp.top + dy, height: cs.height - dy };
3057 },
3058 s: function(event, dx, dy) {
3059 return { height: this.originalSize.height + dy };
3060 },
3061 se: function(event, dx, dy) {
3062 return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
3063 },
3064 sw: function(event, dx, dy) {
3065 return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
3066 },
3067 ne: function(event, dx, dy) {
3068 return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
3069 },
3070 nw: function(event, dx, dy) {
3071 return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
3072 }
3073 },
3074
3075 _propagate: function(n, event) {
3076 $.ui.plugin.call(this, n, [event, this.ui()]);
3077 (n != "resize" && this._trigger(n, event, this.ui()));
3078 },
3079
3080 plugins: {},
3081
3082 ui: function() {
3083 return {
3084 originalElement: this.originalElement,
3085 element: this.element,
3086 helper: this.helper,
3087 position: this.position,
3088 size: this.size,
3089 originalSize: this.originalSize,
3090 originalPosition: this.originalPosition
3091 };
3092 }
3093
3094 });
3095
3096 /*
3097 * Resizable Extensions
3098 */
3099
3100 $.ui.plugin.add("resizable", "alsoResize", {
3101
3102 start: function (event, ui) {
3103 var that = $(this).data("resizable"), o = that.options;
3104
3105 var _store = function (exp) {
3106 $(exp).each(function() {
3107 var el = $(this);
3108 el.data("resizable-alsoresize", {
3109 width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
3110 left: parseInt(el.css('left'), 10), top: parseInt(el.css('top'), 10)
3111 });
3112 });
3113 };
3114
3115 if (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) {
3116 if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); }
3117 else { $.each(o.alsoResize, function (exp) { _store(exp); }); }
3118 }else{
3119 _store(o.alsoResize);
3120 }
3121 },
3122
3123 resize: function (event, ui) {
3124 var that = $(this).data("resizable"), o = that.options, os = that.originalSize, op = that.originalPosition;
3125
3126 var delta = {
3127 height: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0,
3128 top: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0
3129 },
3130
3131 _alsoResize = function (exp, c) {
3132 $(exp).each(function() {
3133 var el = $(this), start = $(this).data("resizable-alsoresize"), style = {},
3134 css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ['width', 'height'] : ['width', 'height', 'top', 'left'];
3135
3136 $.each(css, function (i, prop) {
3137 var sum = (start[prop]||0) + (delta[prop]||0);
3138 if (sum && sum >= 0)
3139 style[prop] = sum || null;
3140 });
3141
3142 el.css(style);
3143 });
3144 };
3145
3146 if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) {
3147 $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); });
3148 }else{
3149 _alsoResize(o.alsoResize);
3150 }
3151 },
3152
3153 stop: function (event, ui) {
3154 $(this).removeData("resizable-alsoresize");
3155 }
3156 });
3157
3158 $.ui.plugin.add("resizable", "animate", {
3159
3160 stop: function(event, ui) {
3161 var that = $(this).data("resizable"), o = that.options;
3162
3163 var pr = that._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName),
3164 soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : that.sizeDiff.height,
3165 soffsetw = ista ? 0 : that.sizeDiff.width;
3166
3167 var style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) },
3168 left = (parseInt(that.element.css('left'), 10) + (that.position.left - that.originalPosition.left)) || null,
3169 top = (parseInt(that.element.css('top'), 10) + (that.position.top - that.originalPosition.top)) || null;
3170
3171 that.element.animate(
3172 $.extend(style, top && left ? { top: top, left: left } : {}), {
3173 duration: o.animateDuration,
3174 easing: o.animateEasing,
3175 step: function() {
3176
3177 var data = {
3178 width: parseInt(that.element.css('width'), 10),
3179 height: parseInt(that.element.css('height'), 10),
3180 top: parseInt(that.element.css('top'), 10),
3181 left: parseInt(that.element.css('left'), 10)
3182 };
3183
3184 if (pr && pr.length) $(pr[0]).css({ width: data.width, height: data.height });
3185
3186 // propagating resize, and updating values for each animation step
3187 that._updateCache(data);
3188 that._propagate("resize", event);
3189
3190 }
3191 }
3192 );
3193 }
3194
3195 });
3196
3197 $.ui.plugin.add("resizable", "containment", {
3198
3199 start: function(event, ui) {
3200 var that = $(this).data("resizable"), o = that.options, el = that.element;
3201 var oc = o.containment, ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc;
3202 if (!ce) return;
3203
3204 that.containerElement = $(ce);
3205
3206 if (/document/.test(oc) || oc == document) {
3207 that.containerOffset = { left: 0, top: 0 };
3208 that.containerPosition = { left: 0, top: 0 };
3209
3210 that.parentData = {
3211 element: $(document), left: 0, top: 0,
3212 width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight
3213 };
3214 }
3215
3216 // i'm a node, so compute top, left, right, bottom
3217 else {
3218 var element = $(ce), p = [];
3219 $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); });
3220
3221 that.containerOffset = element.offset();
3222 that.containerPosition = element.position();
3223 that.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) };
3224
3225 var co = that.containerOffset, ch = that.containerSize.height, cw = that.containerSize.width,
3226 width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch);
3227
3228 that.parentData = {
3229 element: ce, left: co.left, top: co.top, width: width, height: height
3230 };
3231 }
3232 },
3233
3234 resize: function(event, ui) {
3235 var that = $(this).data("resizable"), o = that.options,
3236 ps = that.containerSize, co = that.containerOffset, cs = that.size, cp = that.position,
3237 pRatio = that._aspectRatio || event.shiftKey, cop = { top:0, left:0 }, ce = that.containerElement;
3238
3239 if (ce[0] != document && (/static/).test(ce.css('position'))) cop = co;
3240
3241 if (cp.left < (that._helper ? co.left : 0)) {
3242 that.size.width = that.size.width + (that._helper ? (that.position.left - co.left) : (that.position.left - cop.left));
3243 if (pRatio) that.size.height = that.size.width / that.aspectRatio;
3244 that.position.left = o.helper ? co.left : 0;
3245 }
3246
3247 if (cp.top < (that._helper ? co.top : 0)) {
3248 that.size.height = that.size.height + (that._helper ? (that.position.top - co.top) : that.position.top);
3249 if (pRatio) that.size.width = that.size.height * that.aspectRatio;
3250 that.position.top = that._helper ? co.top : 0;
3251 }
3252
3253 that.offset.left = that.parentData.left+that.position.left;
3254 that.offset.top = that.parentData.top+that.position.top;
3255
3256 var woset = Math.abs( (that._helper ? that.offset.left - cop.left : (that.offset.left - cop.left)) + that.sizeDiff.width ),
3257 hoset = Math.abs( (that._helper ? that.offset.top - cop.top : (that.offset.top - co.top)) + that.sizeDiff.height );
3258
3259 var isParent = that.containerElement.get(0) == that.element.parent().get(0),
3260 isOffsetRelative = /relative|absolute/.test(that.containerElement.css('position'));
3261
3262 if(isParent && isOffsetRelative) woset -= that.parentData.left;
3263
3264 if (woset + that.size.width >= that.parentData.width) {
3265 that.size.width = that.parentData.width - woset;
3266 if (pRatio) that.size.height = that.size.width / that.aspectRatio;
3267 }
3268
3269 if (hoset + that.size.height >= that.parentData.height) {
3270 that.size.height = that.parentData.height - hoset;
3271 if (pRatio) that.size.width = that.size.height * that.aspectRatio;
3272 }
3273 },
3274
3275 stop: function(event, ui){
3276 var that = $(this).data("resizable"), o = that.options, cp = that.position,
3277 co = that.containerOffset, cop = that.containerPosition, ce = that.containerElement;
3278
3279 var helper = $(that.helper), ho = helper.offset(), w = helper.outerWidth() - that.sizeDiff.width, h = helper.outerHeight() - that.sizeDiff.height;
3280
3281 if (that._helper && !o.animate && (/relative/).test(ce.css('position')))
3282 $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
3283
3284 if (that._helper && !o.animate && (/static/).test(ce.css('position')))
3285 $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
3286
3287 }
3288 });
3289
3290 $.ui.plugin.add("resizable", "ghost", {
3291
3292 start: function(event, ui) {
3293
3294 var that = $(this).data("resizable"), o = that.options, cs = that.size;
3295
3296 that.ghost = that.originalElement.clone();
3297 that.ghost
3298 .css({ opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 })
3299 .addClass('ui-resizable-ghost')
3300 .addClass(typeof o.ghost == 'string' ? o.ghost : '');
3301
3302 that.ghost.appendTo(that.helper);
3303
3304 },
3305
3306 resize: function(event, ui){
3307 var that = $(this).data("resizable"), o = that.options;
3308 if (that.ghost) that.ghost.css({ position: 'relative', height: that.size.height, width: that.size.width });
3309 },
3310
3311 stop: function(event, ui){
3312 var that = $(this).data("resizable"), o = that.options;
3313 if (that.ghost && that.helper) that.helper.get(0).removeChild(that.ghost.get(0));
3314 }
3315
3316 });
3317
3318 $.ui.plugin.add("resizable", "grid", {
3319
3320 resize: function(event, ui) {
3321 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;
3322 o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid;
3323 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);
3324
3325 if (/^(se|s|e)$/.test(a)) {
3326 that.size.width = os.width + ox;
3327 that.size.height = os.height + oy;
3328 }
3329 else if (/^(ne)$/.test(a)) {
3330 that.size.width = os.width + ox;
3331 that.size.height = os.height + oy;
3332 that.position.top = op.top - oy;
3333 }
3334 else if (/^(sw)$/.test(a)) {
3335 that.size.width = os.width + ox;
3336 that.size.height = os.height + oy;
3337 that.position.left = op.left - ox;
3338 }
3339 else {
3340 that.size.width = os.width + ox;
3341 that.size.height = os.height + oy;
3342 that.position.top = op.top - oy;
3343 that.position.left = op.left - ox;
3344 }
3345 }
3346
3347 });
3348
3349 var num = function(v) {
3350 return parseInt(v, 10) || 0;
3351 };
3352
3353 var isNumber = function(value) {
3354 return !isNaN(parseInt(value, 10));
3355 };
3356
3357 })(jQuery);
3358 (function( $, undefined ) {
3359
3360 $.widget("ui.selectable", $.ui.mouse, {
3361 version: "1.9.0",
3362 options: {
3363 appendTo: 'body',
3364 autoRefresh: true,
3365 distance: 0,
3366 filter: '*',
3367 tolerance: 'touch'
3368 },
3369 _create: function() {
3370 var that = this;
3371
3372 this.element.addClass("ui-selectable");
3373
3374 this.dragged = false;
3375
3376 // cache selectee children based on filter
3377 var selectees;
3378 this.refresh = function() {
3379 selectees = $(that.options.filter, that.element[0]);
3380 selectees.addClass("ui-selectee");
3381 selectees.each(function() {
3382 var $this = $(this);
3383 var pos = $this.offset();
3384 $.data(this, "selectable-item", {
3385 element: this,
3386 $element: $this,
3387 left: pos.left,
3388 top: pos.top,
3389 right: pos.left + $this.outerWidth(),
3390 bottom: pos.top + $this.outerHeight(),
3391 startselected: false,
3392 selected: $this.hasClass('ui-selected'),
3393 selecting: $this.hasClass('ui-selecting'),
3394 unselecting: $this.hasClass('ui-unselecting')
3395 });
3396 });
3397 };
3398 this.refresh();
3399
3400 this.selectees = selectees.addClass("ui-selectee");
3401
3402 this._mouseInit();
3403
3404 this.helper = $("<div class='ui-selectable-helper'></div>");
3405 },
3406
3407 _destroy: function() {
3408 this.selectees
3409 .removeClass("ui-selectee")
3410 .removeData("selectable-item");
3411 this.element
3412 .removeClass("ui-selectable ui-selectable-disabled");
3413 this._mouseDestroy();
3414 },
3415
3416 _mouseStart: function(event) {
3417 var that = this;
3418
3419 this.opos = [event.pageX, event.pageY];
3420
3421 if (this.options.disabled)
3422 return;
3423
3424 var options = this.options;
3425
3426 this.selectees = $(options.filter, this.element[0]);
3427
3428 this._trigger("start", event);
3429
3430 $(options.appendTo).append(this.helper);
3431 // position helper (lasso)
3432 this.helper.css({
3433 "left": event.clientX,
3434 "top": event.clientY,
3435 "width": 0,
3436 "height": 0
3437 });
3438
3439 if (options.autoRefresh) {
3440 this.refresh();
3441 }
3442
3443 this.selectees.filter('.ui-selected').each(function() {
3444 var selectee = $.data(this, "selectable-item");
3445 selectee.startselected = true;
3446 if (!event.metaKey && !event.ctrlKey) {
3447 selectee.$element.removeClass('ui-selected');
3448 selectee.selected = false;
3449 selectee.$element.addClass('ui-unselecting');
3450 selectee.unselecting = true;
3451 // selectable UNSELECTING callback
3452 that._trigger("unselecting", event, {
3453 unselecting: selectee.element
3454 });
3455 }
3456 });
3457
3458 $(event.target).parents().andSelf().each(function() {
3459 var selectee = $.data(this, "selectable-item");
3460 if (selectee) {
3461 var doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass('ui-selected');
3462 selectee.$element
3463 .removeClass(doSelect ? "ui-unselecting" : "ui-selected")
3464 .addClass(doSelect ? "ui-selecting" : "ui-unselecting");
3465 selectee.unselecting = !doSelect;
3466 selectee.selecting = doSelect;
3467 selectee.selected = doSelect;
3468 // selectable (UN)SELECTING callback
3469 if (doSelect) {
3470 that._trigger("selecting", event, {
3471 selecting: selectee.element
3472 });
3473 } else {
3474 that._trigger("unselecting", event, {
3475 unselecting: selectee.element
3476 });
3477 }
3478 return false;
3479 }
3480 });
3481
3482 },
3483
3484 _mouseDrag: function(event) {
3485 var that = this;
3486 this.dragged = true;
3487
3488 if (this.options.disabled)
3489 return;
3490
3491 var options = this.options;
3492
3493 var x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY;
3494 if (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; }
3495 if (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; }
3496 this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1});
3497
3498 this.selectees.each(function() {
3499 var selectee = $.data(this, "selectable-item");
3500 //prevent helper from being selected if appendTo: selectable
3501 if (!selectee || selectee.element == that.element[0])
3502 return;
3503 var hit = false;
3504 if (options.tolerance == 'touch') {
3505 hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
3506 } else if (options.tolerance == 'fit') {
3507 hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
3508 }
3509
3510 if (hit) {
3511 // SELECT
3512 if (selectee.selected) {
3513 selectee.$element.removeClass('ui-selected');
3514 selectee.selected = false;
3515 }
3516 if (selectee.unselecting) {
3517 selectee.$element.removeClass('ui-unselecting');
3518 selectee.unselecting = false;
3519 }
3520 if (!selectee.selecting) {
3521 selectee.$element.addClass('ui-selecting');
3522 selectee.selecting = true;
3523 // selectable SELECTING callback
3524 that._trigger("selecting", event, {
3525 selecting: selectee.element
3526 });
3527 }
3528 } else {
3529 // UNSELECT
3530 if (selectee.selecting) {
3531 if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
3532 selectee.$element.removeClass('ui-selecting');
3533 selectee.selecting = false;
3534 selectee.$element.addClass('ui-selected');
3535 selectee.selected = true;
3536 } else {
3537 selectee.$element.removeClass('ui-selecting');
3538 selectee.selecting = false;
3539 if (selectee.startselected) {
3540 selectee.$element.addClass('ui-unselecting');
3541 selectee.unselecting = true;
3542 }
3543 // selectable UNSELECTING callback
3544 that._trigger("unselecting", event, {
3545 unselecting: selectee.element
3546 });
3547 }
3548 }
3549 if (selectee.selected) {
3550 if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
3551 selectee.$element.removeClass('ui-selected');
3552 selectee.selected = false;
3553
3554 selectee.$element.addClass('ui-unselecting');
3555 selectee.unselecting = true;
3556 // selectable UNSELECTING callback
3557 that._trigger("unselecting", event, {
3558 unselecting: selectee.element
3559 });
3560 }
3561 }
3562 }
3563 });
3564
3565 return false;
3566 },
3567
3568 _mouseStop: function(event) {
3569 var that = this;
3570
3571 this.dragged = false;
3572
3573 var options = this.options;
3574
3575 $('.ui-unselecting', this.element[0]).each(function() {
3576 var selectee = $.data(this, "selectable-item");
3577 selectee.$element.removeClass('ui-unselecting');
3578 selectee.unselecting = false;
3579 selectee.startselected = false;
3580 that._trigger("unselected", event, {
3581 unselected: selectee.element
3582 });
3583 });
3584 $('.ui-selecting', this.element[0]).each(function() {
3585 var selectee = $.data(this, "selectable-item");
3586 selectee.$element.removeClass('ui-selecting').addClass('ui-selected');
3587 selectee.selecting = false;
3588 selectee.selected = true;
3589 selectee.startselected = true;
3590 that._trigger("selected", event, {
3591 selected: selectee.element
3592 });
3593 });
3594 this._trigger("stop", event);
3595
3596 this.helper.remove();
3597
3598 return false;
3599 }
3600
3601 });
3602
3603 })(jQuery);
3604 (function( $, undefined ) {
3605
3606 $.widget("ui.sortable", $.ui.mouse, {
3607 version: "1.9.0",
3608 widgetEventPrefix: "sort",
3609 ready: false,
3610 options: {
3611 appendTo: "parent",
3612 axis: false,
3613 connectWith: false,
3614 containment: false,
3615 cursor: 'auto',
3616 cursorAt: false,
3617 dropOnEmpty: true,
3618 forcePlaceholderSize: false,
3619 forceHelperSize: false,
3620 grid: false,
3621 handle: false,
3622 helper: "original",
3623 items: '> *',
3624 opacity: false,
3625 placeholder: false,
3626 revert: false,
3627 scroll: true,
3628 scrollSensitivity: 20,
3629 scrollSpeed: 20,
3630 scope: "default",
3631 tolerance: "intersect",
3632 zIndex: 1000
3633 },
3634 _create: function() {
3635
3636 var o = this.options;
3637 this.containerCache = {};
3638 this.element.addClass("ui-sortable");
3639
3640 //Get the items
3641 this.refresh();
3642
3643 //Let's determine if the items are being displayed horizontally
3644 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;
3645
3646 //Let's determine the parent's offset
3647 this.offset = this.element.offset();
3648
3649 //Initialize mouse events for interaction
3650 this._mouseInit();
3651
3652 //We're ready to go
3653 this.ready = true
3654
3655 },
3656
3657 _destroy: function() {
3658 this.element
3659 .removeClass("ui-sortable ui-sortable-disabled");
3660 this._mouseDestroy();
3661
3662 for ( var i = this.items.length - 1; i >= 0; i-- )
3663 this.items[i].item.removeData(this.widgetName + "-item");
3664
3665 return this;
3666 },
3667
3668 _setOption: function(key, value){
3669 if ( key === "disabled" ) {
3670 this.options[ key ] = value;
3671
3672 this.widget().toggleClass( "ui-sortable-disabled", !!value );
3673 } else {
3674 // Don't call widget base _setOption for disable as it adds ui-state-disabled class
3675 $.Widget.prototype._setOption.apply(this, arguments);
3676 }
3677 },
3678
3679 _mouseCapture: function(event, overrideHandle) {
3680 var that = this;
3681
3682 if (this.reverting) {
3683 return false;
3684 }
3685
3686 if(this.options.disabled || this.options.type == 'static') return false;
3687
3688 //We have to refresh the items data once first
3689 this._refreshItems(event);
3690
3691 //Find out if the clicked node (or one of its parents) is a actual item in this.items
3692 var currentItem = null, nodes = $(event.target).parents().each(function() {
3693 if($.data(this, that.widgetName + '-item') == that) {
3694 currentItem = $(this);
3695 return false;
3696 }
3697 });
3698 if($.data(event.target, that.widgetName + '-item') == that) currentItem = $(event.target);
3699
3700 if(!currentItem) return false;
3701 if(this.options.handle && !overrideHandle) {
3702 var validHandle = false;
3703
3704 $(this.options.handle, currentItem).find("*").andSelf().each(function() { if(this == event.target) validHandle = true; });
3705 if(!validHandle) return false;
3706 }
3707
3708 this.currentItem = currentItem;
3709 this._removeCurrentsFromItems();
3710 return true;
3711
3712 },
3713
3714 _mouseStart: function(event, overrideHandle, noActivation) {
3715
3716 var o = this.options;
3717 this.currentContainer = this;
3718
3719 //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
3720 this.refreshPositions();
3721
3722 //Create and append the visible helper
3723 this.helper = this._createHelper(event);
3724
3725 //Cache the helper size
3726 this._cacheHelperProportions();
3727
3728 /*
3729 * - Position generation -
3730 * This block generates everything position related - it's the core of draggables.
3731 */
3732
3733 //Cache the margins of the original element
3734 this._cacheMargins();
3735
3736 //Get the next scrolling parent
3737 this.scrollParent = this.helper.scrollParent();
3738
3739 //The element's absolute position on the page minus margins
3740 this.offset = this.currentItem.offset();
3741 this.offset = {
3742 top: this.offset.top - this.margins.top,
3743 left: this.offset.left - this.margins.left
3744 };
3745
3746 $.extend(this.offset, {
3747 click: { //Where the click happened, relative to the element
3748 left: event.pageX - this.offset.left,
3749 top: event.pageY - this.offset.top
3750 },
3751 parent: this._getParentOffset(),
3752 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
3753 });
3754
3755 // Only after we got the offset, we can change the helper's position to absolute
3756 // TODO: Still need to figure out a way to make relative sorting possible
3757 this.helper.css("position", "absolute");
3758 this.cssPosition = this.helper.css("position");
3759
3760 //Generate the original position
3761 this.originalPosition = this._generatePosition(event);
3762 this.originalPageX = event.pageX;
3763 this.originalPageY = event.pageY;
3764
3765 //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
3766 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
3767
3768 //Cache the former DOM position
3769 this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
3770
3771 //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
3772 if(this.helper[0] != this.currentItem[0]) {
3773 this.currentItem.hide();
3774 }
3775
3776 //Create the placeholder
3777 this._createPlaceholder();
3778
3779 //Set a containment if given in the options
3780 if(o.containment)
3781 this._setContainment();
3782
3783 if(o.cursor) { // cursor option
3784 if ($('body').css("cursor")) this._storedCursor = $('body').css("cursor");
3785 $('body').css("cursor", o.cursor);
3786 }
3787
3788 if(o.opacity) { // opacity option
3789 if (this.helper.css("opacity")) this._storedOpacity = this.helper.css("opacity");
3790 this.helper.css("opacity", o.opacity);
3791 }
3792
3793 if(o.zIndex) { // zIndex option
3794 if (this.helper.css("zIndex")) this._storedZIndex = this.helper.css("zIndex");
3795 this.helper.css("zIndex", o.zIndex);
3796 }
3797
3798 //Prepare scrolling
3799 if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML')
3800 this.overflowOffset = this.scrollParent.offset();
3801
3802 //Call callbacks
3803 this._trigger("start", event, this._uiHash());
3804
3805 //Recache the helper size
3806 if(!this._preserveHelperProportions)
3807 this._cacheHelperProportions();
3808
3809
3810 //Post 'activate' events to possible containers
3811 if(!noActivation) {
3812 for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i]._trigger("activate", event, this._uiHash(this)); }
3813 }
3814
3815 //Prepare possible droppables
3816 if($.ui.ddmanager)
3817 $.ui.ddmanager.current = this;
3818
3819 if ($.ui.ddmanager && !o.dropBehaviour)
3820 $.ui.ddmanager.prepareOffsets(this, event);
3821
3822 this.dragging = true;
3823
3824 this.helper.addClass("ui-sortable-helper");
3825 this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
3826 return true;
3827
3828 },
3829
3830 _mouseDrag: function(event) {
3831
3832 //Compute the helpers position
3833 this.position = this._generatePosition(event);
3834 this.positionAbs = this._convertPositionTo("absolute");
3835
3836 if (!this.lastPositionAbs) {
3837 this.lastPositionAbs = this.positionAbs;
3838 }
3839
3840 //Do scrolling
3841 if(this.options.scroll) {
3842 var o = this.options, scrolled = false;
3843 if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') {
3844
3845 if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
3846 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
3847 else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity)
3848 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
3849
3850 if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
3851 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
3852 else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity)
3853 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
3854
3855 } else {
3856
3857 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
3858 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
3859 else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
3860 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
3861
3862 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
3863 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
3864 else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
3865 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
3866
3867 }
3868
3869 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
3870 $.ui.ddmanager.prepareOffsets(this, event);
3871 }
3872
3873 //Regenerate the absolute position used for position checks
3874 this.positionAbs = this._convertPositionTo("absolute");
3875
3876 //Set the helper position
3877 if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
3878 if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
3879
3880 //Rearrange
3881 for (var i = this.items.length - 1; i >= 0; i--) {
3882
3883 //Cache variables and intersection, continue if no intersection
3884 var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item);
3885 if (!intersection) continue;
3886
3887 // Only put the placeholder inside the current Container, skip all
3888 // items form other containers. This works because when moving
3889 // an item from one container to another the
3890 // currentContainer is switched before the placeholder is moved.
3891 //
3892 // Without this moving items in "sub-sortables" can cause the placeholder to jitter
3893 // beetween the outer and inner container.
3894 if (item.instance !== this.currentContainer) continue;
3895
3896 if (itemElement != this.currentItem[0] //cannot intersect with itself
3897 && this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before
3898 && !$.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked
3899 && (this.options.type == 'semi-dynamic' ? !$.contains(this.element[0], itemElement) : true)
3900 //&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container
3901 ) {
3902
3903 this.direction = intersection == 1 ? "down" : "up";
3904
3905 if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) {
3906 this._rearrange(event, item);
3907 } else {
3908 break;
3909 }
3910
3911 this._trigger("change", event, this._uiHash());
3912 break;
3913 }
3914 }
3915
3916 //Post events to containers
3917 this._contactContainers(event);
3918
3919 //Interconnect with droppables
3920 if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
3921
3922 //Call callbacks
3923 this._trigger('sort', event, this._uiHash());
3924
3925 this.lastPositionAbs = this.positionAbs;
3926 return false;
3927
3928 },
3929
3930 _mouseStop: function(event, noPropagation) {
3931
3932 if(!event) return;
3933
3934 //If we are using droppables, inform the manager about the drop
3935 if ($.ui.ddmanager && !this.options.dropBehaviour)
3936 $.ui.ddmanager.drop(this, event);
3937
3938 if(this.options.revert) {
3939 var that = this;
3940 var cur = this.placeholder.offset();
3941
3942 this.reverting = true;
3943
3944 $(this.helper).animate({
3945 left: cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft),
3946 top: cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop)
3947 }, parseInt(this.options.revert, 10) || 500, function() {
3948 that._clear(event);
3949 });
3950 } else {
3951 this._clear(event, noPropagation);
3952 }
3953
3954 return false;
3955
3956 },
3957
3958 cancel: function() {
3959
3960 if(this.dragging) {
3961
3962 this._mouseUp({ target: null });
3963
3964 if(this.options.helper == "original")
3965 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
3966 else
3967 this.currentItem.show();
3968
3969 //Post deactivating events to containers
3970 for (var i = this.containers.length - 1; i >= 0; i--){
3971 this.containers[i]._trigger("deactivate", null, this._uiHash(this));
3972 if(this.containers[i].containerCache.over) {
3973 this.containers[i]._trigger("out", null, this._uiHash(this));
3974 this.containers[i].containerCache.over = 0;
3975 }
3976 }
3977
3978 }
3979
3980 if (this.placeholder) {
3981 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
3982 if(this.placeholder[0].parentNode) this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
3983 if(this.options.helper != "original" && this.helper && this.helper[0].parentNode) this.helper.remove();
3984
3985 $.extend(this, {
3986 helper: null,
3987 dragging: false,
3988 reverting: false,
3989 _noFinalSort: null
3990 });
3991
3992 if(this.domPosition.prev) {
3993 $(this.domPosition.prev).after(this.currentItem);
3994 } else {
3995 $(this.domPosition.parent).prepend(this.currentItem);
3996 }
3997 }
3998
3999 return this;
4000
4001 },
4002
4003 serialize: function(o) {
4004
4005 var items = this._getItemsAsjQuery(o && o.connected);
4006 var str = []; o = o || {};
4007
4008 $(items).each(function() {
4009 var res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
4010 if(res) str.push((o.key || res[1]+'[]')+'='+(o.key && o.expression ? res[1] : res[2]));
4011 });
4012
4013 if(!str.length && o.key) {
4014 str.push(o.key + '=');
4015 }
4016
4017 return str.join('&');
4018
4019 },
4020
4021 toArray: function(o) {
4022
4023 var items = this._getItemsAsjQuery(o && o.connected);
4024 var ret = []; o = o || {};
4025
4026 items.each(function() { ret.push($(o.item || this).attr(o.attribute || 'id') || ''); });
4027 return ret;
4028
4029 },
4030
4031 /* Be careful with the following core functions */
4032 _intersectsWith: function(item) {
4033
4034 var x1 = this.positionAbs.left,
4035 x2 = x1 + this.helperProportions.width,
4036 y1 = this.positionAbs.top,
4037 y2 = y1 + this.helperProportions.height;
4038
4039 var l = item.left,
4040 r = l + item.width,
4041 t = item.top,
4042 b = t + item.height;
4043
4044 var dyClick = this.offset.click.top,
4045 dxClick = this.offset.click.left;
4046
4047 var isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r;
4048
4049 if( this.options.tolerance == "pointer"
4050 || this.options.forcePointerForContainers
4051 || (this.options.tolerance != "pointer" && this.helperProportions[this.floating ? 'width' : 'height'] > item[this.floating ? 'width' : 'height'])
4052 ) {
4053 return isOverElement;
4054 } else {
4055
4056 return (l < x1 + (this.helperProportions.width / 2) // Right Half
4057 && x2 - (this.helperProportions.width / 2) < r // Left Half
4058 && t < y1 + (this.helperProportions.height / 2) // Bottom Half
4059 && y2 - (this.helperProportions.height / 2) < b ); // Top Half
4060
4061 }
4062 },
4063
4064 _intersectsWithPointer: function(item) {
4065
4066 var isOverElementHeight = (this.options.axis === 'x') || $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
4067 isOverElementWidth = (this.options.axis === 'y') || $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
4068 isOverElement = isOverElementHeight && isOverElementWidth,
4069 verticalDirection = this._getDragVerticalDirection(),
4070 horizontalDirection = this._getDragHorizontalDirection();
4071
4072 if (!isOverElement)
4073 return false;
4074
4075 return this.floating ?
4076 ( ((horizontalDirection && horizontalDirection == "right") || verticalDirection == "down") ? 2 : 1 )
4077 : ( verticalDirection && (verticalDirection == "down" ? 2 : 1) );
4078
4079 },
4080
4081 _intersectsWithSides: function(item) {
4082
4083 var isOverBottomHalf = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
4084 isOverRightHalf = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
4085 verticalDirection = this._getDragVerticalDirection(),
4086 horizontalDirection = this._getDragHorizontalDirection();
4087
4088 if (this.floating && horizontalDirection) {
4089 return ((horizontalDirection == "right" && isOverRightHalf) || (horizontalDirection == "left" && !isOverRightHalf));
4090 } else {
4091 return verticalDirection && ((verticalDirection == "down" && isOverBottomHalf) || (verticalDirection == "up" && !isOverBottomHalf));
4092 }
4093
4094 },
4095
4096 _getDragVerticalDirection: function() {
4097 var delta = this.positionAbs.top - this.lastPositionAbs.top;
4098 return delta != 0 && (delta > 0 ? "down" : "up");
4099 },
4100
4101 _getDragHorizontalDirection: function() {
4102 var delta = this.positionAbs.left - this.lastPositionAbs.left;
4103 return delta != 0 && (delta > 0 ? "right" : "left");
4104 },
4105
4106 refresh: function(event) {
4107 this._refreshItems(event);
4108 this.refreshPositions();
4109 return this;
4110 },
4111
4112 _connectWith: function() {
4113 var options = this.options;
4114 return options.connectWith.constructor == String
4115 ? [options.connectWith]
4116 : options.connectWith;
4117 },
4118
4119 _getItemsAsjQuery: function(connected) {
4120
4121 var items = [];
4122 var queries = [];
4123 var connectWith = this._connectWith();
4124
4125 if(connectWith && connected) {
4126 for (var i = connectWith.length - 1; i >= 0; i--){
4127 var cur = $(connectWith[i]);
4128 for (var j = cur.length - 1; j >= 0; j--){
4129 var inst = $.data(cur[j], this.widgetName);
4130 if(inst && inst != this && !inst.options.disabled) {
4131 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]);
4132 }
4133 };
4134 };
4135 }
4136
4137 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]);
4138
4139 for (var i = queries.length - 1; i >= 0; i--){
4140 queries[i][0].each(function() {
4141 items.push(this);
4142 });
4143 };
4144
4145 return $(items);
4146
4147 },
4148
4149 _removeCurrentsFromItems: function() {
4150
4151 var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
4152
4153 for (var i=0; i < this.items.length; i++) {
4154
4155 for (var j=0; j < list.length; j++) {
4156 if(list[j] == this.items[i].item[0])
4157 this.items.splice(i,1);
4158 };
4159
4160 };
4161
4162 },
4163
4164 _refreshItems: function(event) {
4165
4166 this.items = [];
4167 this.containers = [this];
4168 var items = this.items;
4169 var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]];
4170 var connectWith = this._connectWith();
4171
4172 if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
4173 for (var i = connectWith.length - 1; i >= 0; i--){
4174 var cur = $(connectWith[i]);
4175 for (var j = cur.length - 1; j >= 0; j--){
4176 var inst = $.data(cur[j], this.widgetName);
4177 if(inst && inst != this && !inst.options.disabled) {
4178 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
4179 this.containers.push(inst);
4180 }
4181 };
4182 };
4183 }
4184
4185 for (var i = queries.length - 1; i >= 0; i--) {
4186 var targetData = queries[i][1];
4187 var _queries = queries[i][0];
4188
4189 for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) {
4190 var item = $(_queries[j]);
4191
4192 item.data(this.widgetName + '-item', targetData); // Data for target checking (mouse manager)
4193
4194 items.push({
4195 item: item,
4196 instance: targetData,
4197 width: 0, height: 0,
4198 left: 0, top: 0
4199 });
4200 };
4201 };
4202
4203 },
4204
4205 refreshPositions: function(fast) {
4206
4207 //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
4208 if(this.offsetParent && this.helper) {
4209 this.offset.parent = this._getParentOffset();
4210 }
4211
4212 for (var i = this.items.length - 1; i >= 0; i--){
4213 var item = this.items[i];
4214
4215 //We ignore calculating positions of all connected containers when we're not over them
4216 if(item.instance != this.currentContainer && this.currentContainer && item.item[0] != this.currentItem[0])
4217 continue;
4218
4219 var t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
4220
4221 if (!fast) {
4222 item.width = t.outerWidth();
4223 item.height = t.outerHeight();
4224 }
4225
4226 var p = t.offset();
4227 item.left = p.left;
4228 item.top = p.top;
4229 };
4230
4231 if(this.options.custom && this.options.custom.refreshContainers) {
4232 this.options.custom.refreshContainers.call(this);
4233 } else {
4234 for (var i = this.containers.length - 1; i >= 0; i--){
4235 var p = this.containers[i].element.offset();
4236 this.containers[i].containerCache.left = p.left;
4237 this.containers[i].containerCache.top = p.top;
4238 this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
4239 this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
4240 };
4241 }
4242
4243 return this;
4244 },
4245
4246 _createPlaceholder: function(that) {
4247 that = that || this;
4248 var o = that.options;
4249
4250 if(!o.placeholder || o.placeholder.constructor == String) {
4251 var className = o.placeholder;
4252 o.placeholder = {
4253 element: function() {
4254
4255 var el = $(document.createElement(that.currentItem[0].nodeName))
4256 .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
4257 .removeClass("ui-sortable-helper")[0];
4258
4259 if(!className)
4260 el.style.visibility = "hidden";
4261
4262 return el;
4263 },
4264 update: function(container, p) {
4265
4266 // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
4267 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
4268 if(className && !o.forcePlaceholderSize) return;
4269
4270 //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
4271 if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css('paddingTop')||0, 10) - parseInt(that.currentItem.css('paddingBottom')||0, 10)); };
4272 if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css('paddingLeft')||0, 10) - parseInt(that.currentItem.css('paddingRight')||0, 10)); };
4273 }
4274 };
4275 }
4276
4277 //Create the placeholder
4278 that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));
4279
4280 //Append it after the actual current item
4281 that.currentItem.after(that.placeholder);
4282
4283 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
4284 o.placeholder.update(that, that.placeholder);
4285
4286 },
4287
4288 _contactContainers: function(event) {
4289
4290 // get innermost container that intersects with item
4291 var innermostContainer = null, innermostIndex = null;
4292
4293
4294 for (var i = this.containers.length - 1; i >= 0; i--){
4295
4296 // never consider a container that's located within the item itself
4297 if($.contains(this.currentItem[0], this.containers[i].element[0]))
4298 continue;
4299
4300 if(this._intersectsWith(this.containers[i].containerCache)) {
4301
4302 // if we've already found a container and it's more "inner" than this, then continue
4303 if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0]))
4304 continue;
4305
4306 innermostContainer = this.containers[i];
4307 innermostIndex = i;
4308
4309 } else {
4310 // container doesn't intersect. trigger "out" event if necessary
4311 if(this.containers[i].containerCache.over) {
4312 this.containers[i]._trigger("out", event, this._uiHash(this));
4313 this.containers[i].containerCache.over = 0;
4314 }
4315 }
4316
4317 }
4318
4319 // if no intersecting containers found, return
4320 if(!innermostContainer) return;
4321
4322 // move the item into the container if it's not there already
4323 if(this.containers.length === 1) {
4324 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
4325 this.containers[innermostIndex].containerCache.over = 1;
4326 } else if(this.currentContainer != this.containers[innermostIndex]) {
4327
4328 //When entering a new container, we will find the item with the least distance and append our item near it
4329 var dist = 10000; var itemWithLeastDistance = null; var base = this.positionAbs[this.containers[innermostIndex].floating ? 'left' : 'top'];
4330 for (var j = this.items.length - 1; j >= 0; j--) {
4331 if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) continue;
4332 var cur = this.containers[innermostIndex].floating ? this.items[j].item.offset().left : this.items[j].item.offset().top;
4333 if(Math.abs(cur - base) < dist) {
4334 dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j];
4335 this.direction = (cur - base > 0) ? 'down' : 'up';
4336 }
4337 }
4338
4339 if(!itemWithLeastDistance && !this.options.dropOnEmpty) //Check if dropOnEmpty is enabled
4340 return;
4341
4342 this.currentContainer = this.containers[innermostIndex];
4343 itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
4344 this._trigger("change", event, this._uiHash());
4345 this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
4346
4347 //Update the placeholder
4348 this.options.placeholder.update(this.currentContainer, this.placeholder);
4349
4350 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
4351 this.containers[innermostIndex].containerCache.over = 1;
4352 }
4353
4354
4355 },
4356
4357 _createHelper: function(event) {
4358
4359 var o = this.options;
4360 var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper == 'clone' ? this.currentItem.clone() : this.currentItem);
4361
4362 if(!helper.parents('body').length) //Add the helper to the DOM if that didn't happen already
4363 $(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
4364
4365 if(helper[0] == this.currentItem[0])
4366 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") };
4367
4368 if(helper[0].style.width == '' || o.forceHelperSize) helper.width(this.currentItem.width());
4369 if(helper[0].style.height == '' || o.forceHelperSize) helper.height(this.currentItem.height());
4370
4371 return helper;
4372
4373 },
4374
4375 _adjustOffsetFromHelper: function(obj) {
4376 if (typeof obj == 'string') {
4377 obj = obj.split(' ');
4378 }
4379 if ($.isArray(obj)) {
4380 obj = {left: +obj[0], top: +obj[1] || 0};
4381 }
4382 if ('left' in obj) {
4383 this.offset.click.left = obj.left + this.margins.left;
4384 }
4385 if ('right' in obj) {
4386 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
4387 }
4388 if ('top' in obj) {
4389 this.offset.click.top = obj.top + this.margins.top;
4390 }
4391 if ('bottom' in obj) {
4392 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
4393 }
4394 },
4395
4396 _getParentOffset: function() {
4397
4398
4399 //Get the offsetParent and cache its position
4400 this.offsetParent = this.helper.offsetParent();
4401 var po = this.offsetParent.offset();
4402
4403 // This is a special case where we need to modify a offset calculated on start, since the following happened:
4404 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
4405 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
4406 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
4407 if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
4408 po.left += this.scrollParent.scrollLeft();
4409 po.top += this.scrollParent.scrollTop();
4410 }
4411
4412 if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information
4413 || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix
4414 po = { top: 0, left: 0 };
4415
4416 return {
4417 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
4418 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
4419 };
4420
4421 },
4422
4423 _getRelativeOffset: function() {
4424
4425 if(this.cssPosition == "relative") {
4426 var p = this.currentItem.position();
4427 return {
4428 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
4429 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
4430 };
4431 } else {
4432 return { top: 0, left: 0 };
4433 }
4434
4435 },
4436
4437 _cacheMargins: function() {
4438 this.margins = {
4439 left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
4440 top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
4441 };
4442 },
4443
4444 _cacheHelperProportions: function() {
4445 this.helperProportions = {
4446 width: this.helper.outerWidth(),
4447 height: this.helper.outerHeight()
4448 };
4449 },
4450
4451 _setContainment: function() {
4452
4453 var o = this.options;
4454 if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
4455 if(o.containment == 'document' || o.containment == 'window') this.containment = [
4456 0 - this.offset.relative.left - this.offset.parent.left,
4457 0 - this.offset.relative.top - this.offset.parent.top,
4458 $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left,
4459 ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
4460 ];
4461
4462 if(!(/^(document|window|parent)$/).test(o.containment)) {
4463 var ce = $(o.containment)[0];
4464 var co = $(o.containment).offset();
4465 var over = ($(ce).css("overflow") != 'hidden');
4466
4467 this.containment = [
4468 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
4469 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
4470 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,
4471 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
4472 ];
4473 }
4474
4475 },
4476
4477 _convertPositionTo: function(d, pos) {
4478
4479 if(!pos) pos = this.position;
4480 var mod = d == "absolute" ? 1 : -1;
4481 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);
4482
4483 return {
4484 top: (
4485 pos.top // The absolute mouse position
4486 + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent
4487 + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border)
4488 - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
4489 ),
4490 left: (
4491 pos.left // The absolute mouse position
4492 + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent
4493 + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border)
4494 - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
4495 )
4496 };
4497
4498 },
4499
4500 _generatePosition: function(event) {
4501
4502 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);
4503
4504 // This is another very weird special case that only happens for relative elements:
4505 // 1. If the css position is relative
4506 // 2. and the scroll parent is the document or similar to the offset parent
4507 // we have to refresh the relative offset during the scroll so there are no jumps
4508 if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) {
4509 this.offset.relative = this._getRelativeOffset();
4510 }
4511
4512 var pageX = event.pageX;
4513 var pageY = event.pageY;
4514
4515 /*
4516 * - Position constraining -
4517 * Constrain the position to a mix of grid, containment.
4518 */
4519
4520 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
4521
4522 if(this.containment) {
4523 if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left;
4524 if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top;
4525 if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left;
4526 if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top;
4527 }
4528
4529 if(o.grid) {
4530 var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
4531 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;
4532
4533 var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
4534 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;
4535 }
4536
4537 }
4538
4539 return {
4540 top: (
4541 pageY // The absolute mouse position
4542 - this.offset.click.top // Click offset (relative to the element)
4543 - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent
4544 - this.offset.parent.top // The offsetParent's offset without borders (offset + border)
4545 + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
4546 ),
4547 left: (
4548 pageX // The absolute mouse position
4549 - this.offset.click.left // Click offset (relative to the element)
4550 - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent
4551 - this.offset.parent.left // The offsetParent's offset without borders (offset + border)
4552 + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
4553 )
4554 };
4555
4556 },
4557
4558 _rearrange: function(event, i, a, hardRefresh) {
4559
4560 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));
4561
4562 //Various things done here to improve the performance:
4563 // 1. we create a setTimeout, that calls refreshPositions
4564 // 2. on the instance, we have a counter variable, that get's higher after every append
4565 // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
4566 // 4. this lets only the last addition to the timeout stack through
4567 this.counter = this.counter ? ++this.counter : 1;
4568 var counter = this.counter;
4569
4570 this._delay(function() {
4571 if(counter == this.counter) this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
4572 });
4573
4574 },
4575
4576 _clear: function(event, noPropagation) {
4577
4578 this.reverting = false;
4579 // We delay all events that have to be triggered to after the point where the placeholder has been removed and
4580 // everything else normalized again
4581 var delayedTriggers = [];
4582
4583 // We first have to update the dom position of the actual currentItem
4584 // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
4585 if(!this._noFinalSort && this.currentItem.parent().length) this.placeholder.before(this.currentItem);
4586 this._noFinalSort = null;
4587
4588 if(this.helper[0] == this.currentItem[0]) {
4589 for(var i in this._storedCSS) {
4590 if(this._storedCSS[i] == 'auto' || this._storedCSS[i] == 'static') this._storedCSS[i] = '';
4591 }
4592 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
4593 } else {
4594 this.currentItem.show();
4595 }
4596
4597 if(this.fromOutside && !noPropagation) delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
4598 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
4599
4600 // Check if the items Container has Changed and trigger appropriate
4601 // events.
4602 if (this !== this.currentContainer) {
4603 if(!noPropagation) {
4604 delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
4605 delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
4606 delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
4607 }
4608 }
4609
4610
4611 //Post events to containers
4612 for (var i = this.containers.length - 1; i >= 0; i--){
4613 if(!noPropagation) delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
4614 if(this.containers[i].containerCache.over) {
4615 delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
4616 this.containers[i].containerCache.over = 0;
4617 }
4618 }
4619
4620 //Do what was originally in plugins
4621 if(this._storedCursor) $('body').css("cursor", this._storedCursor); //Reset cursor
4622 if(this._storedOpacity) this.helper.css("opacity", this._storedOpacity); //Reset opacity
4623 if(this._storedZIndex) this.helper.css("zIndex", this._storedZIndex == 'auto' ? '' : this._storedZIndex); //Reset z-index
4624
4625 this.dragging = false;
4626 if(this.cancelHelperRemoval) {
4627 if(!noPropagation) {
4628 this._trigger("beforeStop", event, this._uiHash());
4629 for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events
4630 this._trigger("stop", event, this._uiHash());
4631 }
4632
4633 this.fromOutside = false;
4634 return false;
4635 }
4636
4637 if(!noPropagation) this._trigger("beforeStop", event, this._uiHash());
4638
4639 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
4640 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
4641
4642 if(this.helper[0] != this.currentItem[0]) this.helper.remove(); this.helper = null;
4643
4644 if(!noPropagation) {
4645 for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events
4646 this._trigger("stop", event, this._uiHash());
4647 }
4648
4649 this.fromOutside = false;
4650 return true;
4651
4652 },
4653
4654 _trigger: function() {
4655 if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
4656 this.cancel();
4657 }
4658 },
4659
4660 _uiHash: function(_inst) {
4661 var inst = _inst || this;
4662 return {
4663 helper: inst.helper,
4664 placeholder: inst.placeholder || $([]),
4665 position: inst.position,
4666 originalPosition: inst.originalPosition,
4667 offset: inst.positionAbs,
4668 item: inst.currentItem,
4669 sender: _inst ? _inst.element : null
4670 };
4671 }
4672
4673 });
4674
4675 })(jQuery);
4676 (function( $, undefined ) {
4677
4678 var uid = 0,
4679 hideProps = {},
4680 showProps = {};
4681
4682 hideProps.height = hideProps.paddingTop = hideProps.paddingBottom =
4683 hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide";
4684 showProps.height = showProps.paddingTop = showProps.paddingBottom =
4685 showProps.borderTopWidth = showProps.borderBottomWidth = "show";
4686
4687 $.widget( "ui.accordion", {
4688 version: "1.9.0",
4689 options: {
4690 active: 0,
4691 animate: {},
4692 collapsible: false,
4693 event: "click",
4694 header: "> li > :first-child,> :not(li):even",
4695 heightStyle: "auto",
4696 icons: {
4697 activeHeader: "ui-icon-triangle-1-s",
4698 header: "ui-icon-triangle-1-e"
4699 },
4700
4701 // callbacks
4702 activate: null,
4703 beforeActivate: null
4704 },
4705
4706 _create: function() {
4707 var accordionId = this.accordionId = "ui-accordion-" +
4708 (this.element.attr( "id" ) || ++uid),
4709 options = this.options;
4710
4711 this.prevShow = this.prevHide = $();
4712 this.element.addClass( "ui-accordion ui-widget ui-helper-reset" );
4713
4714 this.headers = this.element.find( options.header )
4715 .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" );
4716 this._hoverable( this.headers );
4717 this._focusable( this.headers );
4718
4719 this.headers.next()
4720 .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
4721 .hide();
4722
4723 // don't allow collapsible: false and active: false
4724 if ( !options.collapsible && options.active === false ) {
4725 options.active = 0;
4726 }
4727 // handle negative values
4728 if ( options.active < 0 ) {
4729 options.active += this.headers.length;
4730 }
4731 this.active = this._findActive( options.active )
4732 .addClass( "ui-accordion-header-active ui-state-active" )
4733 .toggleClass( "ui-corner-all ui-corner-top" );
4734 this.active.next()
4735 .addClass( "ui-accordion-content-active" )
4736 .show();
4737
4738 this._createIcons();
4739 this.originalHeight = this.element[0].style.height;
4740 this.refresh();
4741
4742 // ARIA
4743 this.element.attr( "role", "tablist" );
4744
4745 this.headers
4746 .attr( "role", "tab" )
4747 .each(function( i ) {
4748 var header = $( this ),
4749 headerId = header.attr( "id" ),
4750 panel = header.next(),
4751 panelId = panel.attr( "id" );
4752 if ( !headerId ) {
4753 headerId = accordionId + "-header-" + i;
4754 header.attr( "id", headerId );
4755 }
4756 if ( !panelId ) {
4757 panelId = accordionId + "-panel-" + i;
4758 panel.attr( "id", panelId );
4759 }
4760 header.attr( "aria-controls", panelId );
4761 panel.attr( "aria-labelledby", headerId );
4762 })
4763 .next()
4764 .attr( "role", "tabpanel" );
4765
4766 this.headers
4767 .not( this.active )
4768 .attr({
4769 "aria-selected": "false",
4770 tabIndex: -1
4771 })
4772 .next()
4773 .attr({
4774 "aria-expanded": "false",
4775 "aria-hidden": "true"
4776 })
4777 .hide();
4778
4779 // make sure at least one header is in the tab order
4780 if ( !this.active.length ) {
4781 this.headers.eq( 0 ).attr( "tabIndex", 0 );
4782 } else {
4783 this.active.attr({
4784 "aria-selected": "true",
4785 tabIndex: 0
4786 })
4787 .next()
4788 .attr({
4789 "aria-expanded": "true",
4790 "aria-hidden": "false"
4791 });
4792 }
4793
4794 this._on( this.headers, { keydown: "_keydown" });
4795 this._on( this.headers.next(), { keydown: "_panelKeyDown" });
4796 this._setupEvents( options.event );
4797 },
4798
4799 _getCreateEventData: function() {
4800 return {
4801 header: this.active,
4802 content: !this.active.length ? $() : this.active.next()
4803 };
4804 },
4805
4806 _createIcons: function() {
4807 var icons = this.options.icons;
4808 if ( icons ) {
4809 $( "<span>" )
4810 .addClass( "ui-accordion-header-icon ui-icon " + icons.header )
4811 .prependTo( this.headers );
4812 this.active.children( ".ui-accordion-header-icon" )
4813 .removeClass( icons.header )
4814 .addClass( icons.activeHeader );
4815 this.headers.addClass( "ui-accordion-icons" );
4816 }
4817 },
4818
4819 _destroyIcons: function() {
4820 this.headers
4821 .removeClass( "ui-accordion-icons" )
4822 .children( ".ui-accordion-header-icon" )
4823 .remove();
4824 },
4825
4826 _destroy: function() {
4827 var contents;
4828
4829 // clean up main element
4830 this.element
4831 .removeClass( "ui-accordion ui-widget ui-helper-reset" )
4832 .removeAttr( "role" );
4833
4834 // clean up headers
4835 this.headers
4836 .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" )
4837 .removeAttr( "role" )
4838 .removeAttr( "aria-selected" )
4839 .removeAttr( "aria-controls" )
4840 .removeAttr( "tabIndex" )
4841 .each(function() {
4842 if ( /^ui-accordion/.test( this.id ) ) {
4843 this.removeAttribute( "id" );
4844 }
4845 });
4846 this._destroyIcons();
4847
4848 // clean up content panels
4849 contents = this.headers.next()
4850 .css( "display", "" )
4851 .removeAttr( "role" )
4852 .removeAttr( "aria-expanded" )
4853 .removeAttr( "aria-hidden" )
4854 .removeAttr( "aria-labelledby" )
4855 .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" )
4856 .each(function() {
4857 if ( /^ui-accordion/.test( this.id ) ) {
4858 this.removeAttribute( "id" );
4859 }
4860 });
4861 if ( this.options.heightStyle !== "content" ) {
4862 this.element.css( "height", this.originalHeight );
4863 contents.css( "height", "" );
4864 }
4865 },
4866
4867 _setOption: function( key, value ) {
4868 if ( key === "active" ) {
4869 // _activate() will handle invalid values and update this.options
4870 this._activate( value );
4871 return;
4872 }
4873
4874 if ( key === "event" ) {
4875 if ( this.options.event ) {
4876 this._off( this.headers, this.options.event );
4877 }
4878 this._setupEvents( value );
4879 }
4880
4881 this._super( key, value );
4882
4883 // setting collapsible: false while collapsed; open first panel
4884 if ( key === "collapsible" && !value && this.options.active === false ) {
4885 this._activate( 0 );
4886 }
4887
4888 if ( key === "icons" ) {
4889 this._destroyIcons();
4890 if ( value ) {
4891 this._createIcons();
4892 }
4893 }
4894
4895 // #5332 - opacity doesn't cascade to positioned elements in IE
4896 // so we need to add the disabled class to the headers and panels
4897 if ( key === "disabled" ) {
4898 this.headers.add( this.headers.next() )
4899 .toggleClass( "ui-state-disabled", !!value );
4900 }
4901 },
4902
4903 _keydown: function( event ) {
4904 if ( event.altKey || event.ctrlKey ) {
4905 return;
4906 }
4907
4908 var keyCode = $.ui.keyCode,
4909 length = this.headers.length,
4910 currentIndex = this.headers.index( event.target ),
4911 toFocus = false;
4912
4913 switch ( event.keyCode ) {
4914 case keyCode.RIGHT:
4915 case keyCode.DOWN:
4916 toFocus = this.headers[ ( currentIndex + 1 ) % length ];
4917 break;
4918 case keyCode.LEFT:
4919 case keyCode.UP:
4920 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
4921 break;
4922 case keyCode.SPACE:
4923 case keyCode.ENTER:
4924 this._eventHandler( event );
4925 break;
4926 case keyCode.HOME:
4927 toFocus = this.headers[ 0 ];
4928 break;
4929 case keyCode.END:
4930 toFocus = this.headers[ length - 1 ];
4931 break;
4932 }
4933
4934 if ( toFocus ) {
4935 $( event.target ).attr( "tabIndex", -1 );
4936 $( toFocus ).attr( "tabIndex", 0 );
4937 toFocus.focus();
4938 event.preventDefault();
4939 }
4940 },
4941
4942 _panelKeyDown : function( event ) {
4943 if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
4944 $( event.currentTarget ).prev().focus();
4945 }
4946 },
4947
4948 refresh: function() {
4949 var maxHeight, overflow,
4950 heightStyle = this.options.heightStyle,
4951 parent = this.element.parent();
4952
4953 this.element.css( "height", this.originalHeight );
4954
4955 if ( heightStyle === "fill" ) {
4956 // IE 6 treats height like minHeight, so we need to turn off overflow
4957 // in order to get a reliable height
4958 // we use the minHeight support test because we assume that only
4959 // browsers that don't support minHeight will treat height as minHeight
4960 if ( !$.support.minHeight ) {
4961 overflow = parent.css( "overflow" );
4962 parent.css( "overflow", "hidden");
4963 }
4964 maxHeight = parent.height();
4965 this.element.siblings( ":visible" ).each(function() {
4966 var elem = $( this ),
4967 position = elem.css( "position" );
4968
4969 if ( position === "absolute" || position === "fixed" ) {
4970 return;
4971 }
4972 maxHeight -= elem.outerHeight( true );
4973 });
4974 if ( overflow ) {
4975 parent.css( "overflow", overflow );
4976 }
4977
4978 this.headers.each(function() {
4979 maxHeight -= $( this ).outerHeight( true );
4980 });
4981
4982 this.headers.next()
4983 .each(function() {
4984 $( this ).height( Math.max( 0, maxHeight -
4985 $( this ).innerHeight() + $( this ).height() ) );
4986 })
4987 .css( "overflow", "auto" );
4988 } else if ( heightStyle === "auto" ) {
4989 maxHeight = 0;
4990 this.headers.next()
4991 .each(function() {
4992 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
4993 })
4994 .height( maxHeight );
4995 }
4996
4997 if ( heightStyle !== "content" ) {
4998 this.element.height( this.element.height() );
4999 }
5000 },
5001
5002 _activate: function( index ) {
5003 var active = this._findActive( index )[ 0 ];
5004
5005 // trying to activate the already active panel
5006 if ( active === this.active[ 0 ] ) {
5007 return;
5008 }
5009
5010 // trying to collapse, simulate a click on the currently active header
5011 active = active || this.active[ 0 ];
5012
5013 this._eventHandler({
5014 target: active,
5015 currentTarget: active,
5016 preventDefault: $.noop
5017 });
5018 },
5019
5020 _findActive: function( selector ) {
5021 return typeof selector === "number" ? this.headers.eq( selector ) : $();
5022 },
5023
5024 _setupEvents: function( event ) {
5025 var events = {};
5026 if ( !event ) {
5027 return;
5028 }
5029 $.each( event.split(" "), function( index, eventName ) {
5030 events[ eventName ] = "_eventHandler";
5031 });
5032 this._on( this.headers, events );
5033 },
5034
5035 _eventHandler: function( event ) {
5036 var options = this.options,
5037 active = this.active,
5038 clicked = $( event.currentTarget ),
5039 clickedIsActive = clicked[ 0 ] === active[ 0 ],
5040 collapsing = clickedIsActive && options.collapsible,
5041 toShow = collapsing ? $() : clicked.next(),
5042 toHide = active.next(),
5043 eventData = {
5044 oldHeader: active,
5045 oldPanel: toHide,
5046 newHeader: collapsing ? $() : clicked,
5047 newPanel: toShow
5048 };
5049
5050 event.preventDefault();
5051
5052 if (
5053 // click on active header, but not collapsible
5054 ( clickedIsActive && !options.collapsible ) ||
5055 // allow canceling activation
5056 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
5057 return;
5058 }
5059
5060 options.active = collapsing ? false : this.headers.index( clicked );
5061
5062 // when the call to ._toggle() comes after the class changes
5063 // it causes a very odd bug in IE 8 (see #6720)
5064 this.active = clickedIsActive ? $() : clicked;
5065 this._toggle( eventData );
5066
5067 // switch classes
5068 // corner classes on the previously active header stay after the animation
5069 active.removeClass( "ui-accordion-header-active ui-state-active" );
5070 if ( options.icons ) {
5071 active.children( ".ui-accordion-header-icon" )
5072 .removeClass( options.icons.activeHeader )
5073 .addClass( options.icons.header );
5074 }
5075
5076 if ( !clickedIsActive ) {
5077 clicked
5078 .removeClass( "ui-corner-all" )
5079 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" );
5080 if ( options.icons ) {
5081 clicked.children( ".ui-accordion-header-icon" )
5082 .removeClass( options.icons.header )
5083 .addClass( options.icons.activeHeader );
5084 }
5085
5086 clicked
5087 .next()
5088 .addClass( "ui-accordion-content-active" );
5089 }
5090 },
5091
5092 _toggle: function( data ) {
5093 var toShow = data.newPanel,
5094 toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
5095
5096 // handle activating a panel during the animation for another activation
5097 this.prevShow.add( this.prevHide ).stop( true, true );
5098 this.prevShow = toShow;
5099 this.prevHide = toHide;
5100
5101 if ( this.options.animate ) {
5102 this._animate( toShow, toHide, data );
5103 } else {
5104 toHide.hide();
5105 toShow.show();
5106 this._toggleComplete( data );
5107 }
5108
5109 toHide.attr({
5110 "aria-expanded": "false",
5111 "aria-hidden": "true"
5112 });
5113 toHide.prev().attr( "aria-selected", "false" );
5114 // if we're switching panels, remove the old header from the tab order
5115 // if we're opening from collapsed state, remove the previous header from the tab order
5116 // if we're collapsing, then keep the collapsing header in the tab order
5117 if ( toShow.length && toHide.length ) {
5118 toHide.prev().attr( "tabIndex", -1 );
5119 } else if ( toShow.length ) {
5120 this.headers.filter(function() {
5121 return $( this ).attr( "tabIndex" ) === 0;
5122 })
5123 .attr( "tabIndex", -1 );
5124 }
5125
5126 toShow
5127 .attr({
5128 "aria-expanded": "true",
5129 "aria-hidden": "false"
5130 })
5131 .prev()
5132 .attr({
5133 "aria-selected": "true",
5134 tabIndex: 0
5135 });
5136 },
5137
5138 _animate: function( toShow, toHide, data ) {
5139 var total, easing, duration,
5140 that = this,
5141 adjust = 0,
5142 down = toShow.length &&
5143 ( !toHide.length || ( toShow.index() < toHide.index() ) ),
5144 animate = this.options.animate || {},
5145 options = down && animate.down || animate,
5146 complete = function() {
5147 that._toggleComplete( data );
5148 };
5149
5150 if ( typeof options === "number" ) {
5151 duration = options;
5152 }
5153 if ( typeof options === "string" ) {
5154 easing = options;
5155 }
5156 // fall back from options to animation in case of partial down settings
5157 easing = easing || options.easing || animate.easing;
5158 duration = duration || options.duration || animate.duration;
5159
5160 if ( !toHide.length ) {
5161 return toShow.animate( showProps, duration, easing, complete );
5162 }
5163 if ( !toShow.length ) {
5164 return toHide.animate( hideProps, duration, easing, complete );
5165 }
5166
5167 total = toShow.show().outerHeight();
5168 toHide.animate( hideProps, {
5169 duration: duration,
5170 easing: easing,
5171 step: function( now, fx ) {
5172 fx.now = Math.round( now );
5173 }
5174 });
5175 toShow
5176 .hide()
5177 .animate( showProps, {
5178 duration: duration,
5179 easing: easing,
5180 complete: complete,
5181 step: function( now, fx ) {
5182 fx.now = Math.round( now );
5183 if ( fx.prop !== "height" ) {
5184 adjust += fx.now;
5185 } else if ( that.options.heightStyle !== "content" ) {
5186 fx.now = Math.round( total - toHide.outerHeight() - adjust );
5187 adjust = 0;
5188 }
5189 }
5190 });
5191 },
5192
5193 _toggleComplete: function( data ) {
5194 var toHide = data.oldPanel;
5195
5196 toHide
5197 .removeClass( "ui-accordion-content-active" )
5198 .prev()
5199 .removeClass( "ui-corner-top" )
5200 .addClass( "ui-corner-all" );
5201
5202 // Work around for rendering bug in IE (#5421)
5203 if ( toHide.length ) {
5204 toHide.parent()[0].className = toHide.parent()[0].className;
5205 }
5206
5207 this._trigger( "activate", null, data );
5208 }
5209 });
5210
5211
5212
5213 // DEPRECATED
5214 if ( $.uiBackCompat !== false ) {
5215 // navigation options
5216 (function( $, prototype ) {
5217 $.extend( prototype.options, {
5218 navigation: false,
5219 navigationFilter: function() {
5220 return this.href.toLowerCase() === location.href.toLowerCase();
5221 }
5222 });
5223
5224 var _create = prototype._create;
5225 prototype._create = function() {
5226 if ( this.options.navigation ) {
5227 var that = this,
5228 headers = this.element.find( this.options.header ),
5229 content = headers.next(),
5230 current = headers.add( content )
5231 .find( "a" )
5232 .filter( this.options.navigationFilter )
5233 [ 0 ];
5234 if ( current ) {
5235 headers.add( content ).each( function( index ) {
5236 if ( $.contains( this, current ) ) {
5237 that.options.active = Math.floor( index / 2 );
5238 return false;
5239 }
5240 });
5241 }
5242 }
5243 _create.call( this );
5244 };
5245 }( jQuery, jQuery.ui.accordion.prototype ) );
5246
5247 // height options
5248 (function( $, prototype ) {
5249 $.extend( prototype.options, {
5250 heightStyle: null, // remove default so we fall back to old values
5251 autoHeight: true, // use heightStyle: "auto"
5252 clearStyle: false, // use heightStyle: "content"
5253 fillSpace: false // use heightStyle: "fill"
5254 });
5255
5256 var _create = prototype._create,
5257 _setOption = prototype._setOption;
5258
5259 $.extend( prototype, {
5260 _create: function() {
5261 this.options.heightStyle = this.options.heightStyle ||
5262 this._mergeHeightStyle();
5263
5264 _create.call( this );
5265 },
5266
5267 _setOption: function( key, value ) {
5268 if ( key === "autoHeight" || key === "clearStyle" || key === "fillSpace" ) {
5269 this.options.heightStyle = this._mergeHeightStyle();
5270 }
5271 _setOption.apply( this, arguments );
5272 },
5273
5274 _mergeHeightStyle: function() {
5275 var options = this.options;
5276
5277 if ( options.fillSpace ) {
5278 return "fill";
5279 }
5280
5281 if ( options.clearStyle ) {
5282 return "content";
5283 }
5284
5285 if ( options.autoHeight ) {
5286 return "auto";
5287 }
5288 }
5289 });
5290 }( jQuery, jQuery.ui.accordion.prototype ) );
5291
5292 // icon options
5293 (function( $, prototype ) {
5294 $.extend( prototype.options.icons, {
5295 activeHeader: null, // remove default so we fall back to old values
5296 headerSelected: "ui-icon-triangle-1-s"
5297 });
5298
5299 var _createIcons = prototype._createIcons;
5300 prototype._createIcons = function() {
5301 if ( this.options.icons ) {
5302 this.options.icons.activeHeader = this.options.icons.activeHeader ||
5303 this.options.icons.headerSelected;
5304 }
5305 _createIcons.call( this );
5306 };
5307 }( jQuery, jQuery.ui.accordion.prototype ) );
5308
5309 // expanded active option, activate method
5310 (function( $, prototype ) {
5311 prototype.activate = prototype._activate;
5312
5313 var _findActive = prototype._findActive;
5314 prototype._findActive = function( index ) {
5315 if ( index === -1 ) {
5316 index = false;
5317 }
5318 if ( index && typeof index !== "number" ) {
5319 index = this.headers.index( this.headers.filter( index ) );
5320 if ( index === -1 ) {
5321 index = false;
5322 }
5323 }
5324 return _findActive.call( this, index );
5325 };
5326 }( jQuery, jQuery.ui.accordion.prototype ) );
5327
5328 // resize method
5329 jQuery.ui.accordion.prototype.resize = jQuery.ui.accordion.prototype.refresh;
5330
5331 // change events
5332 (function( $, prototype ) {
5333 $.extend( prototype.options, {
5334 change: null,
5335 changestart: null
5336 });
5337
5338 var _trigger = prototype._trigger;
5339 prototype._trigger = function( type, event, data ) {
5340 var ret = _trigger.apply( this, arguments );
5341 if ( !ret ) {
5342 return false;
5343 }
5344
5345 if ( type === "beforeActivate" ) {
5346 ret = _trigger.call( this, "changestart", event, {
5347 oldHeader: data.oldHeader,
5348 oldContent: data.oldPanel,
5349 newHeader: data.newHeader,
5350 newContent: data.newPanel
5351 });
5352 } else if ( type === "activate" ) {
5353 ret = _trigger.call( this, "change", event, {
5354 oldHeader: data.oldHeader,
5355 oldContent: data.oldPanel,
5356 newHeader: data.newHeader,
5357 newContent: data.newPanel
5358 });
5359 }
5360 return ret;
5361 };
5362 }( jQuery, jQuery.ui.accordion.prototype ) );
5363
5364 // animated option
5365 // NOTE: this only provides support for "slide", "bounceslide", and easings
5366 // not the full $.ui.accordion.animations API
5367 (function( $, prototype ) {
5368 $.extend( prototype.options, {
5369 animate: null,
5370 animated: "slide"
5371 });
5372
5373 var _create = prototype._create;
5374 prototype._create = function() {
5375 var options = this.options;
5376 if ( options.animate === null ) {
5377 if ( !options.animated ) {
5378 options.animate = false;
5379 } else if ( options.animated === "slide" ) {
5380 options.animate = 300;
5381 } else if ( options.animated === "bounceslide" ) {
5382 options.animate = {
5383 duration: 200,
5384 down: {
5385 easing: "easeOutBounce",
5386 duration: 1000
5387 }
5388 };
5389 } else {
5390 options.animate = options.animated;
5391 }
5392 }
5393
5394 _create.call( this );
5395 };
5396 }( jQuery, jQuery.ui.accordion.prototype ) );
5397 }
5398
5399 })( jQuery );
5400 (function( $, undefined ) {
5401
5402 // used to prevent race conditions with remote data sources
5403 var requestIndex = 0;
5404
5405 $.widget( "ui.autocomplete", {
5406 version: "1.9.0",
5407 defaultElement: "<input>",
5408 options: {
5409 appendTo: "body",
5410 autoFocus: false,
5411 delay: 300,
5412 minLength: 1,
5413 position: {
5414 my: "left top",
5415 at: "left bottom",
5416 collision: "none"
5417 },
5418 source: null,
5419
5420 // callbacks
5421 change: null,
5422 close: null,
5423 focus: null,
5424 open: null,
5425 response: null,
5426 search: null,
5427 select: null
5428 },
5429
5430 pending: 0,
5431
5432 _create: function() {
5433 // Some browsers only repeat keydown events, not keypress events,
5434 // so we use the suppressKeyPress flag to determine if we've already
5435 // handled the keydown event. #7269
5436 // Unfortunately the code for & in keypress is the same as the up arrow,
5437 // so we use the suppressKeyPressRepeat flag to avoid handling keypress
5438 // events when we know the keydown event was used to modify the
5439 // search term. #7799
5440 var suppressKeyPress, suppressKeyPressRepeat, suppressInput;
5441
5442 this.isMultiLine = this._isMultiLine();
5443 this.valueMethod = this.element[ this.element.is( "input,textarea" ) ? "val" : "text" ];
5444 this.isNewMenu = true;
5445
5446 this.element
5447 .addClass( "ui-autocomplete-input" )
5448 .attr( "autocomplete", "off" );
5449
5450 this._on({
5451 keydown: function( event ) {
5452 if ( this.element.prop( "readOnly" ) ) {
5453 suppressKeyPress = true;
5454 suppressInput = true;
5455 suppressKeyPressRepeat = true;
5456 return;
5457 }
5458
5459 suppressKeyPress = false;
5460 suppressInput = false;
5461 suppressKeyPressRepeat = false;
5462 var keyCode = $.ui.keyCode;
5463 switch( event.keyCode ) {
5464 case keyCode.PAGE_UP:
5465 suppressKeyPress = true;
5466 this._move( "previousPage", event );
5467 break;
5468 case keyCode.PAGE_DOWN:
5469 suppressKeyPress = true;
5470 this._move( "nextPage", event );
5471 break;
5472 case keyCode.UP:
5473 suppressKeyPress = true;
5474 this._keyEvent( "previous", event );
5475 break;
5476 case keyCode.DOWN:
5477 suppressKeyPress = true;
5478 this._keyEvent( "next", event );
5479 break;
5480 case keyCode.ENTER:
5481 case keyCode.NUMPAD_ENTER:
5482 // when menu is open and has focus
5483 if ( this.menu.active ) {
5484 // #6055 - Opera still allows the keypress to occur
5485 // which causes forms to submit
5486 suppressKeyPress = true;
5487 event.preventDefault();
5488 this.menu.select( event );
5489 }
5490 break;
5491 case keyCode.TAB:
5492 if ( this.menu.active ) {
5493 this.menu.select( event );
5494 }
5495 break;
5496 case keyCode.ESCAPE:
5497 if ( this.menu.element.is( ":visible" ) ) {
5498 this._value( this.term );
5499 this.close( event );
5500 // Different browsers have different default behavior for escape
5501 // Single press can mean undo or clear
5502 // Double press in IE means clear the whole form
5503 event.preventDefault();
5504 }
5505 break;
5506 default:
5507 suppressKeyPressRepeat = true;
5508 // search timeout should be triggered before the input value is changed
5509 this._searchTimeout( event );
5510 break;
5511 }
5512 },
5513 keypress: function( event ) {
5514 if ( suppressKeyPress ) {
5515 suppressKeyPress = false;
5516 event.preventDefault();
5517 return;
5518 }
5519 if ( suppressKeyPressRepeat ) {
5520 return;
5521 }
5522
5523 // replicate some key handlers to allow them to repeat in Firefox and Opera
5524 var keyCode = $.ui.keyCode;
5525 switch( event.keyCode ) {
5526 case keyCode.PAGE_UP:
5527 this._move( "previousPage", event );
5528 break;
5529 case keyCode.PAGE_DOWN:
5530 this._move( "nextPage", event );
5531 break;
5532 case keyCode.UP:
5533 this._keyEvent( "previous", event );
5534 break;
5535 case keyCode.DOWN:
5536 this._keyEvent( "next", event );
5537 break;
5538 }
5539 },
5540 input: function( event ) {
5541 if ( suppressInput ) {
5542 suppressInput = false;
5543 event.preventDefault();
5544 return;
5545 }
5546 this._searchTimeout( event );
5547 },
5548 focus: function() {
5549 this.selectedItem = null;
5550 this.previous = this._value();
5551 },
5552 blur: function( event ) {
5553 if ( this.cancelBlur ) {
5554 delete this.cancelBlur;
5555 return;
5556 }
5557
5558 clearTimeout( this.searching );
5559 this.close( event );
5560 this._change( event );
5561 }
5562 });
5563
5564 this._initSource();
5565 this.menu = $( "<ul>" )
5566 .addClass( "ui-autocomplete" )
5567 .appendTo( this.document.find( this.options.appendTo || "body" )[ 0 ] )
5568 .menu({
5569 // custom key handling for now
5570 input: $(),
5571 // disable ARIA support, the live region takes care of that
5572 role: null
5573 })
5574 .zIndex( this.element.zIndex() + 1 )
5575 .hide()
5576 .data( "menu" );
5577 this._on( this.menu.element, {
5578 mousedown: function( event ) {
5579 // prevent moving focus out of the text field
5580 event.preventDefault();
5581
5582 // IE doesn't prevent moving focus even with event.preventDefault()
5583 // so we set a flag to know when we should ignore the blur event
5584 this.cancelBlur = true;
5585 this._delay(function() {
5586 delete this.cancelBlur;
5587 });
5588
5589 // clicking on the scrollbar causes focus to shift to the body
5590 // but we can't detect a mouseup or a click immediately afterward
5591 // so we have to track the next mousedown and close the menu if
5592 // the user clicks somewhere outside of the autocomplete
5593 var menuElement = this.menu.element[ 0 ];
5594 if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
5595 this._delay(function() {
5596 var that = this;
5597 this.document.one( "mousedown", function( event ) {
5598 if ( event.target !== that.element[ 0 ] &&
5599 event.target !== menuElement &&
5600 !$.contains( menuElement, event.target ) ) {
5601 that.close();
5602 }
5603 });
5604 });
5605 }
5606 },
5607 menufocus: function( event, ui ) {
5608 // #7024 - Prevent accidental activation of menu items in Firefox
5609 if ( this.isNewMenu ) {
5610 this.isNewMenu = false;
5611 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
5612 this.menu.blur();
5613
5614 this.document.one( "mousemove", function() {
5615 $( event.target ).trigger( event.originalEvent );
5616 });
5617
5618 return;
5619 }
5620 }
5621
5622 // back compat for _renderItem using item.autocomplete, via #7810
5623 // TODO remove the fallback, see #8156
5624 var item = ui.item.data( "ui-autocomplete-item" ) || ui.item.data( "item.autocomplete" );
5625 if ( false !== this._trigger( "focus", event, { item: item } ) ) {
5626 // use value to match what will end up in the input, if it was a key event
5627 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
5628 this._value( item.value );
5629 }
5630 } else {
5631 // Normally the input is populated with the item's value as the
5632 // menu is navigated, causing screen readers to notice a change and
5633 // announce the item. Since the focus event was canceled, this doesn't
5634 // happen, so we update the live region so that screen readers can
5635 // still notice the change and announce it.
5636 this.liveRegion.text( item.value );
5637 }
5638 },
5639 menuselect: function( event, ui ) {
5640 // back compat for _renderItem using item.autocomplete, via #7810
5641 // TODO remove the fallback, see #8156
5642 var item = ui.item.data( "ui-autocomplete-item" ) || ui.item.data( "item.autocomplete" ),
5643 previous = this.previous;
5644
5645 // only trigger when focus was lost (click on menu)
5646 if ( this.element[0] !== this.document[0].activeElement ) {
5647 this.element.focus();
5648 this.previous = previous;
5649 // #6109 - IE triggers two focus events and the second
5650 // is asynchronous, so we need to reset the previous
5651 // term synchronously and asynchronously :-(
5652 this._delay(function() {
5653 this.previous = previous;
5654 this.selectedItem = item;
5655 });
5656 }
5657
5658 if ( false !== this._trigger( "select", event, { item: item } ) ) {
5659 this._value( item.value );
5660 }
5661 // reset the term after the select event
5662 // this allows custom select handling to work properly
5663 this.term = this._value();
5664
5665 this.close( event );
5666 this.selectedItem = item;
5667 }
5668 });
5669
5670 this.liveRegion = $( "<span>", {
5671 role: "status",
5672 "aria-live": "polite"
5673 })
5674 .addClass( "ui-helper-hidden-accessible" )
5675 .insertAfter( this.element );
5676
5677 if ( $.fn.bgiframe ) {
5678 this.menu.element.bgiframe();
5679 }
5680
5681 // turning off autocomplete prevents the browser from remembering the
5682 // value when navigating through history, so we re-enable autocomplete
5683 // if the page is unloaded before the widget is destroyed. #7790
5684 this._on( this.window, {
5685 beforeunload: function() {
5686 this.element.removeAttr( "autocomplete" );
5687 }
5688 });
5689 },
5690
5691 _destroy: function() {
5692 clearTimeout( this.searching );
5693 this.element
5694 .removeClass( "ui-autocomplete-input" )
5695 .removeAttr( "autocomplete" );
5696 this.menu.element.remove();
5697 this.liveRegion.remove();
5698 },
5699
5700 _setOption: function( key, value ) {
5701 this._super( key, value );
5702 if ( key === "source" ) {
5703 this._initSource();
5704 }
5705 if ( key === "appendTo" ) {
5706 this.menu.element.appendTo( this.document.find( value || "body" )[0] );
5707 }
5708 if ( key === "disabled" && value && this.xhr ) {
5709 this.xhr.abort();
5710 }
5711 },
5712
5713 _isMultiLine: function() {
5714 // Textareas are always multi-line
5715 if ( this.element.is( "textarea" ) ) {
5716 return true;
5717 }
5718 // Inputs are always single-line, even if inside a contentEditable element
5719 // IE also treats inputs as contentEditable
5720 if ( this.element.is( "input" ) ) {
5721 return false;
5722 }
5723 // All other element types are determined by whether or not they're contentEditable
5724 return this.element.prop( "isContentEditable" );
5725 },
5726
5727 _initSource: function() {
5728 var array, url,
5729 that = this;
5730 if ( $.isArray(this.options.source) ) {
5731 array = this.options.source;
5732 this.source = function( request, response ) {
5733 response( $.ui.autocomplete.filter( array, request.term ) );
5734 };
5735 } else if ( typeof this.options.source === "string" ) {
5736 url = this.options.source;
5737 this.source = function( request, response ) {
5738 if ( that.xhr ) {
5739 that.xhr.abort();
5740 }
5741 that.xhr = $.ajax({
5742 url: url,
5743 data: request,
5744 dataType: "json",
5745 success: function( data, status ) {
5746 response( data );
5747 },
5748 error: function() {
5749 response( [] );
5750 }
5751 });
5752 };
5753 } else {
5754 this.source = this.options.source;
5755 }
5756 },
5757
5758 _searchTimeout: function( event ) {
5759 clearTimeout( this.searching );
5760 this.searching = this._delay(function() {
5761 // only search if the value has changed
5762 if ( this.term !== this._value() ) {
5763 this.selectedItem = null;
5764 this.search( null, event );
5765 }
5766 }, this.options.delay );
5767 },
5768
5769 search: function( value, event ) {
5770 value = value != null ? value : this._value();
5771
5772 // always save the actual value, not the one passed as an argument
5773 this.term = this._value();
5774
5775 if ( value.length < this.options.minLength ) {
5776 return this.close( event );
5777 }
5778
5779 if ( this._trigger( "search", event ) === false ) {
5780 return;
5781 }
5782
5783 return this._search( value );
5784 },
5785
5786 _search: function( value ) {
5787 this.pending++;
5788 this.element.addClass( "ui-autocomplete-loading" );
5789 this.cancelSearch = false;
5790
5791 this.source( { term: value }, this._response() );
5792 },
5793
5794 _response: function() {
5795 var that = this,
5796 index = ++requestIndex;
5797
5798 return function( content ) {
5799 if ( index === requestIndex ) {
5800 that.__response( content );
5801 }
5802
5803 that.pending--;
5804 if ( !that.pending ) {
5805 that.element.removeClass( "ui-autocomplete-loading" );
5806 }
5807 };
5808 },
5809
5810 __response: function( content ) {
5811 if ( content ) {
5812 content = this._normalize( content );
5813 }
5814 this._trigger( "response", null, { content: content } );
5815 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
5816 this._suggest( content );
5817 this._trigger( "open" );
5818 } else {
5819 // use ._close() instead of .close() so we don't cancel future searches
5820 this._close();
5821 }
5822 },
5823
5824 close: function( event ) {
5825 this.cancelSearch = true;
5826 this._close( event );
5827 },
5828
5829 _close: function( event ) {
5830 if ( this.menu.element.is( ":visible" ) ) {
5831 this.menu.element.hide();
5832 this.menu.blur();
5833 this.isNewMenu = true;
5834 this._trigger( "close", event );
5835 }
5836 },
5837
5838 _change: function( event ) {
5839 if ( this.previous !== this._value() ) {
5840 this._trigger( "change", event, { item: this.selectedItem } );
5841 }
5842 },
5843
5844 _normalize: function( items ) {
5845 // assume all items have the right format when the first item is complete
5846 if ( items.length && items[0].label && items[0].value ) {
5847 return items;
5848 }
5849 return $.map( items, function( item ) {
5850 if ( typeof item === "string" ) {
5851 return {
5852 label: item,
5853 value: item
5854 };
5855 }
5856 return $.extend({
5857 label: item.label || item.value,
5858 value: item.value || item.label
5859 }, item );
5860 });
5861 },
5862
5863 _suggest: function( items ) {
5864 var ul = this.menu.element
5865 .empty()
5866 .zIndex( this.element.zIndex() + 1 );
5867 this._renderMenu( ul, items );
5868 this.menu.refresh();
5869
5870 // size and position menu
5871 ul.show();
5872 this._resizeMenu();
5873 ul.position( $.extend({
5874 of: this.element
5875 }, this.options.position ));
5876
5877 if ( this.options.autoFocus ) {
5878 this.menu.next();
5879 }
5880 },
5881
5882 _resizeMenu: function() {
5883 var ul = this.menu.element;
5884 ul.outerWidth( Math.max(
5885 // Firefox wraps long text (possibly a rounding bug)
5886 // so we add 1px to avoid the wrapping (#7513)
5887 ul.width( "" ).outerWidth() + 1,
5888 this.element.outerWidth()
5889 ) );
5890 },
5891
5892 _renderMenu: function( ul, items ) {
5893 var that = this;
5894 $.each( items, function( index, item ) {
5895 that._renderItemData( ul, item );
5896 });
5897 },
5898
5899 _renderItemData: function( ul, item ) {
5900 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
5901 },
5902
5903 _renderItem: function( ul, item ) {
5904 return $( "<li>" )
5905 .append( $( "<a>" ).text( item.label ) )
5906 .appendTo( ul );
5907 },
5908
5909 _move: function( direction, event ) {
5910 if ( !this.menu.element.is( ":visible" ) ) {
5911 this.search( null, event );
5912 return;
5913 }
5914 if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
5915 this.menu.isLastItem() && /^next/.test( direction ) ) {
5916 this._value( this.term );
5917 this.menu.blur();
5918 return;
5919 }
5920 this.menu[ direction ]( event );
5921 },
5922
5923 widget: function() {
5924 return this.menu.element;
5925 },
5926
5927 _value: function( value ) {
5928 return this.valueMethod.apply( this.element, arguments );
5929 },
5930
5931 _keyEvent: function( keyEvent, event ) {
5932 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
5933 this._move( keyEvent, event );
5934
5935 // prevents moving cursor to beginning/end of the text field in some browsers
5936 event.preventDefault();
5937 }
5938 }
5939 });
5940
5941 $.extend( $.ui.autocomplete, {
5942 escapeRegex: function( value ) {
5943 return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
5944 },
5945 filter: function(array, term) {
5946 var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
5947 return $.grep( array, function(value) {
5948 return matcher.test( value.label || value.value || value );
5949 });
5950 }
5951 });
5952
5953
5954 // live region extension, adding a `messages` option
5955 // NOTE: This is an experimental API. We are still investigating
5956 // a full solution for string manipulation and internationalization.
5957 $.widget( "ui.autocomplete", $.ui.autocomplete, {
5958 options: {
5959 messages: {
5960 noResults: "No search results.",
5961 results: function( amount ) {
5962 return amount + ( amount > 1 ? " results are" : " result is" ) +
5963 " available, use up and down arrow keys to navigate.";
5964 }
5965 }
5966 },
5967
5968 __response: function( content ) {
5969 var message;
5970 this._superApply( arguments );
5971 if ( this.options.disabled || this.cancelSearch ) {
5972 return;
5973 }
5974 if ( content && content.length ) {
5975 message = this.options.messages.results( content.length );
5976 } else {
5977 message = this.options.messages.noResults;
5978 }
5979 this.liveRegion.text( message );
5980 }
5981 });
5982
5983
5984 }( jQuery ));
5985 (function( $, undefined ) {
5986
5987 var lastActive, startXPos, startYPos, clickDragged,
5988 baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
5989 stateClasses = "ui-state-hover ui-state-active ",
5990 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",
5991 formResetHandler = function() {
5992 var buttons = $( this ).find( ":ui-button" );
5993 setTimeout(function() {
5994 buttons.button( "refresh" );
5995 }, 1 );
5996 },
5997 radioGroup = function( radio ) {
5998 var name = radio.name,
5999 form = radio.form,
6000 radios = $( [] );
6001 if ( name ) {
6002 if ( form ) {
6003 radios = $( form ).find( "[name='" + name + "']" );
6004 } else {
6005 radios = $( "[name='" + name + "']", radio.ownerDocument )
6006 .filter(function() {
6007 return !this.form;
6008 });
6009 }
6010 }
6011 return radios;
6012 };
6013
6014 $.widget( "ui.button", {
6015 version: "1.9.0",
6016 defaultElement: "<button>",
6017 options: {
6018 disabled: null,
6019 text: true,
6020 label: null,
6021 icons: {
6022 primary: null,
6023 secondary: null
6024 }
6025 },
6026 _create: function() {
6027 this.element.closest( "form" )
6028 .unbind( "reset" + this.eventNamespace )
6029 .bind( "reset" + this.eventNamespace, formResetHandler );
6030
6031 if ( typeof this.options.disabled !== "boolean" ) {
6032 this.options.disabled = !!this.element.prop( "disabled" );
6033 } else {
6034 this.element.prop( "disabled", this.options.disabled );
6035 }
6036
6037 this._determineButtonType();
6038 this.hasTitle = !!this.buttonElement.attr( "title" );
6039
6040 var that = this,
6041 options = this.options,
6042 toggleButton = this.type === "checkbox" || this.type === "radio",
6043 hoverClass = "ui-state-hover" + ( !toggleButton ? " ui-state-active" : "" ),
6044 focusClass = "ui-state-focus";
6045
6046 if ( options.label === null ) {
6047 options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html());
6048 }
6049
6050 this.buttonElement
6051 .addClass( baseClasses )
6052 .attr( "role", "button" )
6053 .bind( "mouseenter" + this.eventNamespace, function() {
6054 if ( options.disabled ) {
6055 return;
6056 }
6057 $( this ).addClass( "ui-state-hover" );
6058 if ( this === lastActive ) {
6059 $( this ).addClass( "ui-state-active" );
6060 }
6061 })
6062 .bind( "mouseleave" + this.eventNamespace, function() {
6063 if ( options.disabled ) {
6064 return;
6065 }
6066 $( this ).removeClass( hoverClass );
6067 })
6068 .bind( "click" + this.eventNamespace, function( event ) {
6069 if ( options.disabled ) {
6070 event.preventDefault();
6071 event.stopImmediatePropagation();
6072 }
6073 });
6074
6075 this.element
6076 .bind( "focus" + this.eventNamespace, function() {
6077 // no need to check disabled, focus won't be triggered anyway
6078 that.buttonElement.addClass( focusClass );
6079 })
6080 .bind( "blur" + this.eventNamespace, function() {
6081 that.buttonElement.removeClass( focusClass );
6082 });
6083
6084 if ( toggleButton ) {
6085 this.element.bind( "change" + this.eventNamespace, function() {
6086 if ( clickDragged ) {
6087 return;
6088 }
6089 that.refresh();
6090 });
6091 // if mouse moves between mousedown and mouseup (drag) set clickDragged flag
6092 // prevents issue where button state changes but checkbox/radio checked state
6093 // does not in Firefox (see ticket #6970)
6094 this.buttonElement
6095 .bind( "mousedown" + this.eventNamespace, function( event ) {
6096 if ( options.disabled ) {
6097 return;
6098 }
6099 clickDragged = false;
6100 startXPos = event.pageX;
6101 startYPos = event.pageY;
6102 })
6103 .bind( "mouseup" + this.eventNamespace, function( event ) {
6104 if ( options.disabled ) {
6105 return;
6106 }
6107 if ( startXPos !== event.pageX || startYPos !== event.pageY ) {
6108 clickDragged = true;
6109 }
6110 });
6111 }
6112
6113 if ( this.type === "checkbox" ) {
6114 this.buttonElement.bind( "click" + this.eventNamespace, function() {
6115 if ( options.disabled || clickDragged ) {
6116 return false;
6117 }
6118 $( this ).toggleClass( "ui-state-active" );
6119 that.buttonElement.attr( "aria-pressed", that.element[0].checked );
6120 });
6121 } else if ( this.type === "radio" ) {
6122 this.buttonElement.bind( "click" + this.eventNamespace, function() {
6123 if ( options.disabled || clickDragged ) {
6124 return false;
6125 }
6126 $( this ).addClass( "ui-state-active" );
6127 that.buttonElement.attr( "aria-pressed", "true" );
6128
6129 var radio = that.element[ 0 ];
6130 radioGroup( radio )
6131 .not( radio )
6132 .map(function() {
6133 return $( this ).button( "widget" )[ 0 ];
6134 })
6135 .removeClass( "ui-state-active" )
6136 .attr( "aria-pressed", "false" );
6137 });
6138 } else {
6139 this.buttonElement
6140 .bind( "mousedown" + this.eventNamespace, function() {
6141 if ( options.disabled ) {
6142 return false;
6143 }
6144 $( this ).addClass( "ui-state-active" );
6145 lastActive = this;
6146 that.document.one( "mouseup", function() {
6147 lastActive = null;
6148 });
6149 })
6150 .bind( "mouseup" + this.eventNamespace, function() {
6151 if ( options.disabled ) {
6152 return false;
6153 }
6154 $( this ).removeClass( "ui-state-active" );
6155 })
6156 .bind( "keydown" + this.eventNamespace, function(event) {
6157 if ( options.disabled ) {
6158 return false;
6159 }
6160 if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) {
6161 $( this ).addClass( "ui-state-active" );
6162 }
6163 })
6164 .bind( "keyup" + this.eventNamespace, function() {
6165 $( this ).removeClass( "ui-state-active" );
6166 });
6167
6168 if ( this.buttonElement.is("a") ) {
6169 this.buttonElement.keyup(function(event) {
6170 if ( event.keyCode === $.ui.keyCode.SPACE ) {
6171 // TODO pass through original event correctly (just as 2nd argument doesn't work)
6172 $( this ).click();
6173 }
6174 });
6175 }
6176 }
6177
6178 // TODO: pull out $.Widget's handling for the disabled option into
6179 // $.Widget.prototype._setOptionDisabled so it's easy to proxy and can
6180 // be overridden by individual plugins
6181 this._setOption( "disabled", options.disabled );
6182 this._resetButton();
6183 },
6184
6185 _determineButtonType: function() {
6186 var ancestor, labelSelector, checked;
6187
6188 if ( this.element.is("[type=checkbox]") ) {
6189 this.type = "checkbox";
6190 } else if ( this.element.is("[type=radio]") ) {
6191 this.type = "radio";
6192 } else if ( this.element.is("input") ) {
6193 this.type = "input";
6194 } else {
6195 this.type = "button";
6196 }
6197
6198 if ( this.type === "checkbox" || this.type === "radio" ) {
6199 // we don't search against the document in case the element
6200 // is disconnected from the DOM
6201 ancestor = this.element.parents().last();
6202 labelSelector = "label[for='" + this.element.attr("id") + "']";
6203 this.buttonElement = ancestor.find( labelSelector );
6204 if ( !this.buttonElement.length ) {
6205 ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
6206 this.buttonElement = ancestor.filter( labelSelector );
6207 if ( !this.buttonElement.length ) {
6208 this.buttonElement = ancestor.find( labelSelector );
6209 }
6210 }
6211 this.element.addClass( "ui-helper-hidden-accessible" );
6212
6213 checked = this.element.is( ":checked" );
6214 if ( checked ) {
6215 this.buttonElement.addClass( "ui-state-active" );
6216 }
6217 this.buttonElement.prop( "aria-pressed", checked );
6218 } else {
6219 this.buttonElement = this.element;
6220 }
6221 },
6222
6223 widget: function() {
6224 return this.buttonElement;
6225 },
6226
6227 _destroy: function() {
6228 this.element
6229 .removeClass( "ui-helper-hidden-accessible" );
6230 this.buttonElement
6231 .removeClass( baseClasses + " " + stateClasses + " " + typeClasses )
6232 .removeAttr( "role" )
6233 .removeAttr( "aria-pressed" )
6234 .html( this.buttonElement.find(".ui-button-text").html() );
6235
6236 if ( !this.hasTitle ) {
6237 this.buttonElement.removeAttr( "title" );
6238 }
6239 },
6240
6241 _setOption: function( key, value ) {
6242 this._super( key, value );
6243 if ( key === "disabled" ) {
6244 if ( value ) {
6245 this.element.prop( "disabled", true );
6246 } else {
6247 this.element.prop( "disabled", false );
6248 }
6249 return;
6250 }
6251 this._resetButton();
6252 },
6253
6254 refresh: function() {
6255 var isDisabled = this.element.is( ":disabled" );
6256 if ( isDisabled !== this.options.disabled ) {
6257 this._setOption( "disabled", isDisabled );
6258 }
6259 if ( this.type === "radio" ) {
6260 radioGroup( this.element[0] ).each(function() {
6261 if ( $( this ).is( ":checked" ) ) {
6262 $( this ).button( "widget" )
6263 .addClass( "ui-state-active" )
6264 .attr( "aria-pressed", "true" );
6265 } else {
6266 $( this ).button( "widget" )
6267 .removeClass( "ui-state-active" )
6268 .attr( "aria-pressed", "false" );
6269 }
6270 });
6271 } else if ( this.type === "checkbox" ) {
6272 if ( this.element.is( ":checked" ) ) {
6273 this.buttonElement
6274 .addClass( "ui-state-active" )
6275 .attr( "aria-pressed", "true" );
6276 } else {
6277 this.buttonElement
6278 .removeClass( "ui-state-active" )
6279 .attr( "aria-pressed", "false" );
6280 }
6281 }
6282 },
6283
6284 _resetButton: function() {
6285 if ( this.type === "input" ) {
6286 if ( this.options.label ) {
6287 this.element.val( this.options.label );
6288 }
6289 return;
6290 }
6291 var buttonElement = this.buttonElement.removeClass( typeClasses ),
6292 buttonText = $( "<span></span>", this.document[0] )
6293 .addClass( "ui-button-text" )
6294 .html( this.options.label )
6295 .appendTo( buttonElement.empty() )
6296 .text(),
6297 icons = this.options.icons,
6298 multipleIcons = icons.primary && icons.secondary,
6299 buttonClasses = [];
6300
6301 if ( icons.primary || icons.secondary ) {
6302 if ( this.options.text ) {
6303 buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
6304 }
6305
6306 if ( icons.primary ) {
6307 buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
6308 }
6309
6310 if ( icons.secondary ) {
6311 buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
6312 }
6313
6314 if ( !this.options.text ) {
6315 buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );
6316
6317 if ( !this.hasTitle ) {
6318 buttonElement.attr( "title", $.trim( buttonText ) );
6319 }
6320 }
6321 } else {
6322 buttonClasses.push( "ui-button-text-only" );
6323 }
6324 buttonElement.addClass( buttonClasses.join( " " ) );
6325 }
6326 });
6327
6328 $.widget( "ui.buttonset", {
6329 version: "1.9.0",
6330 options: {
6331 items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(button)"
6332 },
6333
6334 _create: function() {
6335 this.element.addClass( "ui-buttonset" );
6336 },
6337
6338 _init: function() {
6339 this.refresh();
6340 },
6341
6342 _setOption: function( key, value ) {
6343 if ( key === "disabled" ) {
6344 this.buttons.button( "option", key, value );
6345 }
6346
6347 this._super( key, value );
6348 },
6349
6350 refresh: function() {
6351 var rtl = this.element.css( "direction" ) === "rtl";
6352
6353 this.buttons = this.element.find( this.options.items )
6354 .filter( ":ui-button" )
6355 .button( "refresh" )
6356 .end()
6357 .not( ":ui-button" )
6358 .button()
6359 .end()
6360 .map(function() {
6361 return $( this ).button( "widget" )[ 0 ];
6362 })
6363 .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
6364 .filter( ":first" )
6365 .addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
6366 .end()
6367 .filter( ":last" )
6368 .addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
6369 .end()
6370 .end();
6371 },
6372
6373 _destroy: function() {
6374 this.element.removeClass( "ui-buttonset" );
6375 this.buttons
6376 .map(function() {
6377 return $( this ).button( "widget" )[ 0 ];
6378 })
6379 .removeClass( "ui-corner-left ui-corner-right" )
6380 .end()
6381 .button( "destroy" );
6382 }
6383 });
6384
6385 }( jQuery ) );
6386 (function( $, undefined ) {
6387
6388 $.extend($.ui, { datepicker: { version: "1.9.0" } });
6389
6390 var PROP_NAME = 'datepicker';
6391 var dpuuid = new Date().getTime();
6392 var instActive;
6393
6394 /* Date picker manager.
6395 Use the singleton instance of this class, $.datepicker, to interact with the date picker.
6396 Settings for (groups of) date pickers are maintained in an instance object,
6397 allowing multiple different settings on the same page. */
6398
6399 function Datepicker() {
6400 this.debug = false; // Change this to true to start debugging
6401 this._curInst = null; // The current instance in use
6402 this._keyEvent = false; // If the last event was a key event
6403 this._disabledInputs = []; // List of date picker inputs that have been disabled
6404 this._datepickerShowing = false; // True if the popup picker is showing , false if not
6405 this._inDialog = false; // True if showing within a "dialog", false if not
6406 this._mainDivId = 'ui-datepicker-div'; // The ID of the main datepicker division
6407 this._inlineClass = 'ui-datepicker-inline'; // The name of the inline marker class
6408 this._appendClass = 'ui-datepicker-append'; // The name of the append marker class
6409 this._triggerClass = 'ui-datepicker-trigger'; // The name of the trigger marker class
6410 this._dialogClass = 'ui-datepicker-dialog'; // The name of the dialog marker class
6411 this._disableClass = 'ui-datepicker-disabled'; // The name of the disabled covering marker class
6412 this._unselectableClass = 'ui-datepicker-unselectable'; // The name of the unselectable cell marker class
6413 this._currentClass = 'ui-datepicker-current-day'; // The name of the current day marker class
6414 this._dayOverClass = 'ui-datepicker-days-cell-over'; // The name of the day hover marker class
6415 this.regional = []; // Available regional settings, indexed by language code
6416 this.regional[''] = { // Default regional settings
6417 closeText: 'Done', // Display text for close link
6418 prevText: 'Prev', // Display text for previous month link
6419 nextText: 'Next', // Display text for next month link
6420 currentText: 'Today', // Display text for current month link
6421 monthNames: ['January','February','March','April','May','June',
6422 'July','August','September','October','November','December'], // Names of months for drop-down and formatting
6423 monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting
6424 dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting
6425 dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting
6426 dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday
6427 weekHeader: 'Wk', // Column header for week of the year
6428 dateFormat: 'mm/dd/yy', // See format options on parseDate
6429 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
6430 isRTL: false, // True if right-to-left language, false if left-to-right
6431 showMonthAfterYear: false, // True if the year select precedes month, false for month then year
6432 yearSuffix: '' // Additional text to append to the year in the month headers
6433 };
6434 this._defaults = { // Global defaults for all the date picker instances
6435 showOn: 'focus', // 'focus' for popup on focus,
6436 // 'button' for trigger button, or 'both' for either
6437 showAnim: 'fadeIn', // Name of jQuery animation for popup
6438 showOptions: {}, // Options for enhanced animations
6439 defaultDate: null, // Used when field is blank: actual date,
6440 // +/-number for offset from today, null for today
6441 appendText: '', // Display text following the input box, e.g. showing the format
6442 buttonText: '...', // Text for trigger button
6443 buttonImage: '', // URL for trigger button image
6444 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
6445 hideIfNoPrevNext: false, // True to hide next/previous month links
6446 // if not applicable, false to just disable them
6447 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
6448 gotoCurrent: false, // True if today link goes back to current selection instead
6449 changeMonth: false, // True if month can be selected directly, false if only prev/next
6450 changeYear: false, // True if year can be selected directly, false if only prev/next
6451 yearRange: 'c-10:c+10', // Range of years to display in drop-down,
6452 // either relative to today's year (-nn:+nn), relative to currently displayed year
6453 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
6454 showOtherMonths: false, // True to show dates in other months, false to leave blank
6455 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
6456 showWeek: false, // True to show week of the year, false to not show it
6457 calculateWeek: this.iso8601Week, // How to calculate the week of the year,
6458 // takes a Date and returns the number of the week for it
6459 shortYearCutoff: '+10', // Short year values < this are in the current century,
6460 // > this are in the previous century,
6461 // string value starting with '+' for current year + value
6462 minDate: null, // The earliest selectable date, or null for no limit
6463 maxDate: null, // The latest selectable date, or null for no limit
6464 duration: 'fast', // Duration of display/closure
6465 beforeShowDay: null, // Function that takes a date and returns an array with
6466 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '',
6467 // [2] = cell title (optional), e.g. $.datepicker.noWeekends
6468 beforeShow: null, // Function that takes an input field and
6469 // returns a set of custom settings for the date picker
6470 onSelect: null, // Define a callback function when a date is selected
6471 onChangeMonthYear: null, // Define a callback function when the month or year is changed
6472 onClose: null, // Define a callback function when the datepicker is closed
6473 numberOfMonths: 1, // Number of months to show at a time
6474 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
6475 stepMonths: 1, // Number of months to step back/forward
6476 stepBigMonths: 12, // Number of months to step back/forward for the big links
6477 altField: '', // Selector for an alternate field to store selected dates into
6478 altFormat: '', // The date format to use for the alternate field
6479 constrainInput: true, // The input is constrained by the current date format
6480 showButtonPanel: false, // True to show button panel, false to not show it
6481 autoSize: false, // True to size the input for the date format, false to leave as is
6482 disabled: false // The initial disabled state
6483 };
6484 $.extend(this._defaults, this.regional['']);
6485 this.dpDiv = bindHover($('<div id="' + this._mainDivId + '" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'));
6486 }
6487
6488 $.extend(Datepicker.prototype, {
6489 /* Class name added to elements to indicate already configured with a date picker. */
6490 markerClassName: 'hasDatepicker',
6491
6492 //Keep track of the maximum number of rows displayed (see #7043)
6493 maxRows: 4,
6494
6495 /* Debug logging (if enabled). */
6496 log: function () {
6497 if (this.debug)
6498 console.log.apply('', arguments);
6499 },
6500
6501 // TODO rename to "widget" when switching to widget factory
6502 _widgetDatepicker: function() {
6503 return this.dpDiv;
6504 },
6505
6506 /* Override the default settings for all instances of the date picker.
6507 @param settings object - the new settings to use as defaults (anonymous object)
6508 @return the manager object */
6509 setDefaults: function(settings) {
6510 extendRemove(this._defaults, settings || {});
6511 return this;
6512 },
6513
6514 /* Attach the date picker to a jQuery selection.
6515 @param target element - the target input field or division or span
6516 @param settings object - the new settings to use for this date picker instance (anonymous) */
6517 _attachDatepicker: function(target, settings) {
6518 // check for settings on the control itself - in namespace 'date:'
6519 var inlineSettings = null;
6520 for (var attrName in this._defaults) {
6521 var attrValue = target.getAttribute('date:' + attrName);
6522 if (attrValue) {
6523 inlineSettings = inlineSettings || {};
6524 try {
6525 inlineSettings[attrName] = eval(attrValue);
6526 } catch (err) {
6527 inlineSettings[attrName] = attrValue;
6528 }
6529 }
6530 }
6531 var nodeName = target.nodeName.toLowerCase();
6532 var inline = (nodeName == 'div' || nodeName == 'span');
6533 if (!target.id) {
6534 this.uuid += 1;
6535 target.id = 'dp' + this.uuid;
6536 }
6537 var inst = this._newInst($(target), inline);
6538 inst.settings = $.extend({}, settings || {}, inlineSettings || {});
6539 if (nodeName == 'input') {
6540 this._connectDatepicker(target, inst);
6541 } else if (inline) {
6542 this._inlineDatepicker(target, inst);
6543 }
6544 },
6545
6546 /* Create a new instance object. */
6547 _newInst: function(target, inline) {
6548 var id = target[0].id.replace(/([^A-Za-z0-9_-])/g, '\\\\$1'); // escape jQuery meta chars
6549 return {id: id, input: target, // associated target
6550 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
6551 drawMonth: 0, drawYear: 0, // month being drawn
6552 inline: inline, // is datepicker inline or not
6553 dpDiv: (!inline ? this.dpDiv : // presentation div
6554 bindHover($('<div class="' + this._inlineClass + ' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')))};
6555 },
6556
6557 /* Attach the date picker to an input field. */
6558 _connectDatepicker: function(target, inst) {
6559 var input = $(target);
6560 inst.append = $([]);
6561 inst.trigger = $([]);
6562 if (input.hasClass(this.markerClassName))
6563 return;
6564 this._attachments(input, inst);
6565 input.addClass(this.markerClassName).keydown(this._doKeyDown).
6566 keypress(this._doKeyPress).keyup(this._doKeyUp).
6567 bind("setData.datepicker", function(event, key, value) {
6568 inst.settings[key] = value;
6569 }).bind("getData.datepicker", function(event, key) {
6570 return this._get(inst, key);
6571 });
6572 this._autoSize(inst);
6573 $.data(target, PROP_NAME, inst);
6574 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
6575 if( inst.settings.disabled ) {
6576 this._disableDatepicker( target );
6577 }
6578 },
6579
6580 /* Make attachments based on settings. */
6581 _attachments: function(input, inst) {
6582 var appendText = this._get(inst, 'appendText');
6583 var isRTL = this._get(inst, 'isRTL');
6584 if (inst.append)
6585 inst.append.remove();
6586 if (appendText) {
6587 inst.append = $('<span class="' + this._appendClass + '">' + appendText + '</span>');
6588 input[isRTL ? 'before' : 'after'](inst.append);
6589 }
6590 input.unbind('focus', this._showDatepicker);
6591 if (inst.trigger)
6592 inst.trigger.remove();
6593 var showOn = this._get(inst, 'showOn');
6594 if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field
6595 input.focus(this._showDatepicker);
6596 if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked
6597 var buttonText = this._get(inst, 'buttonText');
6598 var buttonImage = this._get(inst, 'buttonImage');
6599 inst.trigger = $(this._get(inst, 'buttonImageOnly') ?
6600 $('<img/>').addClass(this._triggerClass).
6601 attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
6602 $('<button type="button"></button>').addClass(this._triggerClass).
6603 html(buttonImage == '' ? buttonText : $('<img/>').attr(
6604 { src:buttonImage, alt:buttonText, title:buttonText })));
6605 input[isRTL ? 'before' : 'after'](inst.trigger);
6606 inst.trigger.click(function() {
6607 if ($.datepicker._datepickerShowing && $.datepicker._lastInput == input[0])
6608 $.datepicker._hideDatepicker();
6609 else if ($.datepicker._datepickerShowing && $.datepicker._lastInput != input[0]) {
6610 $.datepicker._hideDatepicker();
6611 $.datepicker._showDatepicker(input[0]);
6612 } else
6613 $.datepicker._showDatepicker(input[0]);
6614 return false;
6615 });
6616 }
6617 },
6618
6619 /* Apply the maximum length for the date format. */
6620 _autoSize: function(inst) {
6621 if (this._get(inst, 'autoSize') && !inst.inline) {
6622 var date = new Date(2009, 12 - 1, 20); // Ensure double digits
6623 var dateFormat = this._get(inst, 'dateFormat');
6624 if (dateFormat.match(/[DM]/)) {
6625 var findMax = function(names) {
6626 var max = 0;
6627 var maxI = 0;
6628 for (var i = 0; i < names.length; i++) {
6629 if (names[i].length > max) {
6630 max = names[i].length;
6631 maxI = i;
6632 }
6633 }
6634 return maxI;
6635 };
6636 date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
6637 'monthNames' : 'monthNamesShort'))));
6638 date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
6639 'dayNames' : 'dayNamesShort'))) + 20 - date.getDay());
6640 }
6641 inst.input.attr('size', this._formatDate(inst, date).length);
6642 }
6643 },
6644
6645 /* Attach an inline date picker to a div. */
6646 _inlineDatepicker: function(target, inst) {
6647 var divSpan = $(target);
6648 if (divSpan.hasClass(this.markerClassName))
6649 return;
6650 divSpan.addClass(this.markerClassName).append(inst.dpDiv).
6651 bind("setData.datepicker", function(event, key, value){
6652 inst.settings[key] = value;
6653 }).bind("getData.datepicker", function(event, key){
6654 return this._get(inst, key);
6655 });
6656 $.data(target, PROP_NAME, inst);
6657 this._setDate(inst, this._getDefaultDate(inst), true);
6658 this._updateDatepicker(inst);
6659 this._updateAlternate(inst);
6660 //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
6661 if( inst.settings.disabled ) {
6662 this._disableDatepicker( target );
6663 }
6664 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
6665 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
6666 inst.dpDiv.css( "display", "block" );
6667 },
6668
6669 /* Pop-up the date picker in a "dialog" box.
6670 @param input element - ignored
6671 @param date string or Date - the initial date to display
6672 @param onSelect function - the function to call when a date is selected
6673 @param settings object - update the dialog date picker instance's settings (anonymous object)
6674 @param pos int[2] - coordinates for the dialog's position within the screen or
6675 event - with x/y coordinates or
6676 leave empty for default (screen centre)
6677 @return the manager object */
6678 _dialogDatepicker: function(input, date, onSelect, settings, pos) {
6679 var inst = this._dialogInst; // internal instance
6680 if (!inst) {
6681 this.uuid += 1;
6682 var id = 'dp' + this.uuid;
6683 this._dialogInput = $('<input type="text" id="' + id +
6684 '" style="position: absolute; top: -100px; width: 0px;"/>');
6685 this._dialogInput.keydown(this._doKeyDown);
6686 $('body').append(this._dialogInput);
6687 inst = this._dialogInst = this._newInst(this._dialogInput, false);
6688 inst.settings = {};
6689 $.data(this._dialogInput[0], PROP_NAME, inst);
6690 }
6691 extendRemove(inst.settings, settings || {});
6692 date = (date && date.constructor == Date ? this._formatDate(inst, date) : date);
6693 this._dialogInput.val(date);
6694
6695 this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
6696 if (!this._pos) {
6697 var browserWidth = document.documentElement.clientWidth;
6698 var browserHeight = document.documentElement.clientHeight;
6699 var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
6700 var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
6701 this._pos = // should use actual width/height below
6702 [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
6703 }
6704
6705 // move input on screen for focus, but hidden behind dialog
6706 this._dialogInput.css('left', (this._pos[0] + 20) + 'px').css('top', this._pos[1] + 'px');
6707 inst.settings.onSelect = onSelect;
6708 this._inDialog = true;
6709 this.dpDiv.addClass(this._dialogClass);
6710 this._showDatepicker(this._dialogInput[0]);
6711 if ($.blockUI)
6712 $.blockUI(this.dpDiv);
6713 $.data(this._dialogInput[0], PROP_NAME, inst);
6714 return this;
6715 },
6716
6717 /* Detach a datepicker from its control.
6718 @param target element - the target input field or division or span */
6719 _destroyDatepicker: function(target) {
6720 var $target = $(target);
6721 var inst = $.data(target, PROP_NAME);
6722 if (!$target.hasClass(this.markerClassName)) {
6723 return;
6724 }
6725 var nodeName = target.nodeName.toLowerCase();
6726 $.removeData(target, PROP_NAME);
6727 if (nodeName == 'input') {
6728 inst.append.remove();
6729 inst.trigger.remove();
6730 $target.removeClass(this.markerClassName).
6731 unbind('focus', this._showDatepicker).
6732 unbind('keydown', this._doKeyDown).
6733 unbind('keypress', this._doKeyPress).
6734 unbind('keyup', this._doKeyUp);
6735 } else if (nodeName == 'div' || nodeName == 'span')
6736 $target.removeClass(this.markerClassName).empty();
6737 },
6738
6739 /* Enable the date picker to a jQuery selection.
6740 @param target element - the target input field or division or span */
6741 _enableDatepicker: function(target) {
6742 var $target = $(target);
6743 var inst = $.data(target, PROP_NAME);
6744 if (!$target.hasClass(this.markerClassName)) {
6745 return;
6746 }
6747 var nodeName = target.nodeName.toLowerCase();
6748 if (nodeName == 'input') {
6749 target.disabled = false;
6750 inst.trigger.filter('button').
6751 each(function() { this.disabled = false; }).end().
6752 filter('img').css({opacity: '1.0', cursor: ''});
6753 }
6754 else if (nodeName == 'div' || nodeName == 'span') {
6755 var inline = $target.children('.' + this._inlineClass);
6756 inline.children().removeClass('ui-state-disabled');
6757 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
6758 prop("disabled", false);
6759 }
6760 this._disabledInputs = $.map(this._disabledInputs,
6761 function(value) { return (value == target ? null : value); }); // delete entry
6762 },
6763
6764 /* Disable the date picker to a jQuery selection.
6765 @param target element - the target input field or division or span */
6766 _disableDatepicker: function(target) {
6767 var $target = $(target);
6768 var inst = $.data(target, PROP_NAME);
6769 if (!$target.hasClass(this.markerClassName)) {
6770 return;
6771 }
6772 var nodeName = target.nodeName.toLowerCase();
6773 if (nodeName == 'input') {
6774 target.disabled = true;
6775 inst.trigger.filter('button').
6776 each(function() { this.disabled = true; }).end().
6777 filter('img').css({opacity: '0.5', cursor: 'default'});
6778 }
6779 else if (nodeName == 'div' || nodeName == 'span') {
6780 var inline = $target.children('.' + this._inlineClass);
6781 inline.children().addClass('ui-state-disabled');
6782 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
6783 prop("disabled", true);
6784 }
6785 this._disabledInputs = $.map(this._disabledInputs,
6786 function(value) { return (value == target ? null : value); }); // delete entry
6787 this._disabledInputs[this._disabledInputs.length] = target;
6788 },
6789
6790 /* Is the first field in a jQuery collection disabled as a datepicker?
6791 @param target element - the target input field or division or span
6792 @return boolean - true if disabled, false if enabled */
6793 _isDisabledDatepicker: function(target) {
6794 if (!target) {
6795 return false;
6796 }
6797 for (var i = 0; i < this._disabledInputs.length; i++) {
6798 if (this._disabledInputs[i] == target)
6799 return true;
6800 }
6801 return false;
6802 },
6803
6804 /* Retrieve the instance data for the target control.
6805 @param target element - the target input field or division or span
6806 @return object - the associated instance data
6807 @throws error if a jQuery problem getting data */
6808 _getInst: function(target) {
6809 try {
6810 return $.data(target, PROP_NAME);
6811 }
6812 catch (err) {
6813 throw 'Missing instance data for this datepicker';
6814 }
6815 },
6816
6817 /* Update or retrieve the settings for a date picker attached to an input field or division.
6818 @param target element - the target input field or division or span
6819 @param name object - the new settings to update or
6820 string - the name of the setting to change or retrieve,
6821 when retrieving also 'all' for all instance settings or
6822 'defaults' for all global defaults
6823 @param value any - the new value for the setting
6824 (omit if above is an object or to retrieve a value) */
6825 _optionDatepicker: function(target, name, value) {
6826 var inst = this._getInst(target);
6827 if (arguments.length == 2 && typeof name == 'string') {
6828 return (name == 'defaults' ? $.extend({}, $.datepicker._defaults) :
6829 (inst ? (name == 'all' ? $.extend({}, inst.settings) :
6830 this._get(inst, name)) : null));
6831 }
6832 var settings = name || {};
6833 if (typeof name == 'string') {
6834 settings = {};
6835 settings[name] = value;
6836 }
6837 if (inst) {
6838 if (this._curInst == inst) {
6839 this._hideDatepicker();
6840 }
6841 var date = this._getDateDatepicker(target, true);
6842 var minDate = this._getMinMaxDate(inst, 'min');
6843 var maxDate = this._getMinMaxDate(inst, 'max');
6844 extendRemove(inst.settings, settings);
6845 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
6846 if (minDate !== null && settings['dateFormat'] !== undefined && settings['minDate'] === undefined)
6847 inst.settings.minDate = this._formatDate(inst, minDate);
6848 if (maxDate !== null && settings['dateFormat'] !== undefined && settings['maxDate'] === undefined)
6849 inst.settings.maxDate = this._formatDate(inst, maxDate);
6850 this._attachments($(target), inst);
6851 this._autoSize(inst);
6852 this._setDate(inst, date);
6853 this._updateAlternate(inst);
6854 this._updateDatepicker(inst);
6855 }
6856 },
6857
6858 // change method deprecated
6859 _changeDatepicker: function(target, name, value) {
6860 this._optionDatepicker(target, name, value);
6861 },
6862
6863 /* Redraw the date picker attached to an input field or division.
6864 @param target element - the target input field or division or span */
6865 _refreshDatepicker: function(target) {
6866 var inst = this._getInst(target);
6867 if (inst) {
6868 this._updateDatepicker(inst);
6869 }
6870 },
6871
6872 /* Set the dates for a jQuery selection.
6873 @param target element - the target input field or division or span
6874 @param date Date - the new date */
6875 _setDateDatepicker: function(target, date) {
6876 var inst = this._getInst(target);
6877 if (inst) {
6878 this._setDate(inst, date);
6879 this._updateDatepicker(inst);
6880 this._updateAlternate(inst);
6881 }
6882 },
6883
6884 /* Get the date(s) for the first entry in a jQuery selection.
6885 @param target element - the target input field or division or span
6886 @param noDefault boolean - true if no default date is to be used
6887 @return Date - the current date */
6888 _getDateDatepicker: function(target, noDefault) {
6889 var inst = this._getInst(target);
6890 if (inst && !inst.inline)
6891 this._setDateFromField(inst, noDefault);
6892 return (inst ? this._getDate(inst) : null);
6893 },
6894
6895 /* Handle keystrokes. */
6896 _doKeyDown: function(event) {
6897 var inst = $.datepicker._getInst(event.target);
6898 var handled = true;
6899 var isRTL = inst.dpDiv.is('.ui-datepicker-rtl');
6900 inst._keyEvent = true;
6901 if ($.datepicker._datepickerShowing)
6902 switch (event.keyCode) {
6903 case 9: $.datepicker._hideDatepicker();
6904 handled = false;
6905 break; // hide on tab out
6906 case 13: var sel = $('td.' + $.datepicker._dayOverClass + ':not(.' +
6907 $.datepicker._currentClass + ')', inst.dpDiv);
6908 if (sel[0])
6909 $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
6910 var onSelect = $.datepicker._get(inst, 'onSelect');
6911 if (onSelect) {
6912 var dateStr = $.datepicker._formatDate(inst);
6913
6914 // trigger custom callback
6915 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
6916 }
6917 else
6918 $.datepicker._hideDatepicker();
6919 return false; // don't submit the form
6920 break; // select the value on enter
6921 case 27: $.datepicker._hideDatepicker();
6922 break; // hide on escape
6923 case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
6924 -$.datepicker._get(inst, 'stepBigMonths') :
6925 -$.datepicker._get(inst, 'stepMonths')), 'M');
6926 break; // previous month/year on page up/+ ctrl
6927 case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
6928 +$.datepicker._get(inst, 'stepBigMonths') :
6929 +$.datepicker._get(inst, 'stepMonths')), 'M');
6930 break; // next month/year on page down/+ ctrl
6931 case 35: if (event.ctrlKey || event.metaKey) $.datepicker._clearDate(event.target);
6932 handled = event.ctrlKey || event.metaKey;
6933 break; // clear on ctrl or command +end
6934 case 36: if (event.ctrlKey || event.metaKey) $.datepicker._gotoToday(event.target);
6935 handled = event.ctrlKey || event.metaKey;
6936 break; // current on ctrl or command +home
6937 case 37: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), 'D');
6938 handled = event.ctrlKey || event.metaKey;
6939 // -1 day on ctrl or command +left
6940 if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ?
6941 -$.datepicker._get(inst, 'stepBigMonths') :
6942 -$.datepicker._get(inst, 'stepMonths')), 'M');
6943 // next month/year on alt +left on Mac
6944 break;
6945 case 38: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, -7, 'D');
6946 handled = event.ctrlKey || event.metaKey;
6947 break; // -1 week on ctrl or command +up
6948 case 39: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), 'D');
6949 handled = event.ctrlKey || event.metaKey;
6950 // +1 day on ctrl or command +right
6951 if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ?
6952 +$.datepicker._get(inst, 'stepBigMonths') :
6953 +$.datepicker._get(inst, 'stepMonths')), 'M');
6954 // next month/year on alt +right
6955 break;
6956 case 40: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, +7, 'D');
6957 handled = event.ctrlKey || event.metaKey;
6958 break; // +1 week on ctrl or command +down
6959 default: handled = false;
6960 }
6961 else if (event.keyCode == 36 && event.ctrlKey) // display the date picker on ctrl+home
6962 $.datepicker._showDatepicker(this);
6963 else {
6964 handled = false;
6965 }
6966 if (handled) {
6967 event.preventDefault();
6968 event.stopPropagation();
6969 }
6970 },
6971
6972 /* Filter entered characters - based on date format. */
6973 _doKeyPress: function(event) {
6974 var inst = $.datepicker._getInst(event.target);
6975 if ($.datepicker._get(inst, 'constrainInput')) {
6976 var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat'));
6977 var chr = String.fromCharCode(event.charCode == undefined ? event.keyCode : event.charCode);
6978 return event.ctrlKey || event.metaKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1);
6979 }
6980 },
6981
6982 /* Synchronise manual entry and field/alternate field. */
6983 _doKeyUp: function(event) {
6984 var inst = $.datepicker._getInst(event.target);
6985 if (inst.input.val() != inst.lastVal) {
6986 try {
6987 var date = $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'),
6988 (inst.input ? inst.input.val() : null),
6989 $.datepicker._getFormatConfig(inst));
6990 if (date) { // only if valid
6991 $.datepicker._setDateFromField(inst);
6992 $.datepicker._updateAlternate(inst);
6993 $.datepicker._updateDatepicker(inst);
6994 }
6995 }
6996 catch (err) {
6997 $.datepicker.log(err);
6998 }
6999 }
7000 return true;
7001 },
7002
7003 /* Pop-up the date picker for a given input field.
7004 If false returned from beforeShow event handler do not show.
7005 @param input element - the input field attached to the date picker or
7006 event - if triggered by focus */
7007 _showDatepicker: function(input) {
7008 input = input.target || input;
7009 if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger
7010 input = $('input', input.parentNode)[0];
7011 if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here
7012 return;
7013 var inst = $.datepicker._getInst(input);
7014 if ($.datepicker._curInst && $.datepicker._curInst != inst) {
7015 $.datepicker._curInst.dpDiv.stop(true, true);
7016 if ( inst && $.datepicker._datepickerShowing ) {
7017 $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
7018 }
7019 }
7020 var beforeShow = $.datepicker._get(inst, 'beforeShow');
7021 var beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
7022 if(beforeShowSettings === false){
7023 //false
7024 return;
7025 }
7026 extendRemove(inst.settings, beforeShowSettings);
7027 inst.lastVal = null;
7028 $.datepicker._lastInput = input;
7029 $.datepicker._setDateFromField(inst);
7030 if ($.datepicker._inDialog) // hide cursor
7031 input.value = '';
7032 if (!$.datepicker._pos) { // position below input
7033 $.datepicker._pos = $.datepicker._findPos(input);
7034 $.datepicker._pos[1] += input.offsetHeight; // add the height
7035 }
7036 var isFixed = false;
7037 $(input).parents().each(function() {
7038 isFixed |= $(this).css('position') == 'fixed';
7039 return !isFixed;
7040 });
7041 var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
7042 $.datepicker._pos = null;
7043 //to avoid flashes on Firefox
7044 inst.dpDiv.empty();
7045 // determine sizing offscreen
7046 inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'});
7047 $.datepicker._updateDatepicker(inst);
7048 // fix width for dynamic number of date pickers
7049 // and adjust position before showing
7050 offset = $.datepicker._checkOffset(inst, offset, isFixed);
7051 inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
7052 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none',
7053 left: offset.left + 'px', top: offset.top + 'px'});
7054 if (!inst.inline) {
7055 var showAnim = $.datepicker._get(inst, 'showAnim');
7056 var duration = $.datepicker._get(inst, 'duration');
7057 var postProcess = function() {
7058 var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only
7059 if( !! cover.length ){
7060 var borders = $.datepicker._getBorders(inst.dpDiv);
7061 cover.css({left: -borders[0], top: -borders[1],
7062 width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()});
7063 }
7064 };
7065 inst.dpDiv.zIndex($(input).zIndex()+1);
7066 $.datepicker._datepickerShowing = true;
7067
7068 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
7069 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) )
7070 inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);
7071 else
7072 inst.dpDiv[showAnim || 'show']((showAnim ? duration : null), postProcess);
7073 if (!showAnim || !duration)
7074 postProcess();
7075 if (inst.input.is(':visible') && !inst.input.is(':disabled'))
7076 inst.input.focus();
7077 $.datepicker._curInst = inst;
7078 }
7079 },
7080
7081 /* Generate the date picker content. */
7082 _updateDatepicker: function(inst) {
7083 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
7084 var borders = $.datepicker._getBorders(inst.dpDiv);
7085 instActive = inst; // for delegate hover events
7086 inst.dpDiv.empty().append(this._generateHTML(inst));
7087 this._attachHandlers(inst);
7088 var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only
7089 if( !!cover.length ){ //avoid call to outerXXXX() when not in IE6
7090 cover.css({left: -borders[0], top: -borders[1], width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()})
7091 }
7092 inst.dpDiv.find('.' + this._dayOverClass + ' a').mouseover();
7093 var numMonths = this._getNumberOfMonths(inst);
7094 var cols = numMonths[1];
7095 var width = 17;
7096 inst.dpDiv.removeClass('ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4').width('');
7097 if (cols > 1)
7098 inst.dpDiv.addClass('ui-datepicker-multi-' + cols).css('width', (width * cols) + 'em');
7099 inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') +
7100 'Class']('ui-datepicker-multi');
7101 inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') +
7102 'Class']('ui-datepicker-rtl');
7103 if (inst == $.datepicker._curInst && $.datepicker._datepickerShowing && inst.input &&
7104 // #6694 - don't focus the input if it's already focused
7105 // this breaks the change event in IE
7106 inst.input.is(':visible') && !inst.input.is(':disabled') && inst.input[0] != document.activeElement)
7107 inst.input.focus();
7108 // deffered render of the years select (to avoid flashes on Firefox)
7109 if( inst.yearshtml ){
7110 var origyearshtml = inst.yearshtml;
7111 setTimeout(function(){
7112 //assure that inst.yearshtml didn't change.
7113 if( origyearshtml === inst.yearshtml && inst.yearshtml ){
7114 inst.dpDiv.find('select.ui-datepicker-year:first').replaceWith(inst.yearshtml);
7115 }
7116 origyearshtml = inst.yearshtml = null;
7117 }, 0);
7118 }
7119 },
7120
7121 /* Retrieve the size of left and top borders for an element.
7122 @param elem (jQuery object) the element of interest
7123 @return (number[2]) the left and top borders */
7124 _getBorders: function(elem) {
7125 var convert = function(value) {
7126 return {thin: 1, medium: 2, thick: 3}[value] || value;
7127 };
7128 return [parseFloat(convert(elem.css('border-left-width'))),
7129 parseFloat(convert(elem.css('border-top-width')))];
7130 },
7131
7132 /* Check positioning to remain on screen. */
7133 _checkOffset: function(inst, offset, isFixed) {
7134 var dpWidth = inst.dpDiv.outerWidth();
7135 var dpHeight = inst.dpDiv.outerHeight();
7136 var inputWidth = inst.input ? inst.input.outerWidth() : 0;
7137 var inputHeight = inst.input ? inst.input.outerHeight() : 0;
7138 var viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft());
7139 var viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
7140
7141 offset.left -= (this._get(inst, 'isRTL') ? (dpWidth - inputWidth) : 0);
7142 offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0;
7143 offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
7144
7145 // now check if datepicker is showing outside window viewport - move to a better place if so.
7146 offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
7147 Math.abs(offset.left + dpWidth - viewWidth) : 0);
7148 offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
7149 Math.abs(dpHeight + inputHeight) : 0);
7150
7151 return offset;
7152 },
7153
7154 /* Find an object's position on the screen. */
7155 _findPos: function(obj) {
7156 var inst = this._getInst(obj);
7157 var isRTL = this._get(inst, 'isRTL');
7158 while (obj && (obj.type == 'hidden' || obj.nodeType != 1 || $.expr.filters.hidden(obj))) {
7159 obj = obj[isRTL ? 'previousSibling' : 'nextSibling'];
7160 }
7161 var position = $(obj).offset();
7162 return [position.left, position.top];
7163 },
7164
7165 /* Hide the date picker from view.
7166 @param input element - the input field attached to the date picker */
7167 _hideDatepicker: function(input) {
7168 var inst = this._curInst;
7169 if (!inst || (input && inst != $.data(input, PROP_NAME)))
7170 return;
7171 if (this._datepickerShowing) {
7172 var showAnim = this._get(inst, 'showAnim');
7173 var duration = this._get(inst, 'duration');
7174 var postProcess = function() {
7175 $.datepicker._tidyDialog(inst);
7176 };
7177
7178 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
7179 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) )
7180 inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);
7181 else
7182 inst.dpDiv[(showAnim == 'slideDown' ? 'slideUp' :
7183 (showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))]((showAnim ? duration : null), postProcess);
7184 if (!showAnim)
7185 postProcess();
7186 this._datepickerShowing = false;
7187 var onClose = this._get(inst, 'onClose');
7188 if (onClose)
7189 onClose.apply((inst.input ? inst.input[0] : null),
7190 [(inst.input ? inst.input.val() : ''), inst]);
7191 this._lastInput = null;
7192 if (this._inDialog) {
7193 this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' });
7194 if ($.blockUI) {
7195 $.unblockUI();
7196 $('body').append(this.dpDiv);
7197 }
7198 }
7199 this._inDialog = false;
7200 }
7201 },
7202
7203 /* Tidy up after a dialog display. */
7204 _tidyDialog: function(inst) {
7205 inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker-calendar');
7206 },
7207
7208 /* Close date picker if clicked elsewhere. */
7209 _checkExternalClick: function(event) {
7210 if (!$.datepicker._curInst)
7211 return;
7212
7213 var $target = $(event.target),
7214 inst = $.datepicker._getInst($target[0]);
7215
7216 if ( ( ( $target[0].id != $.datepicker._mainDivId &&
7217 $target.parents('#' + $.datepicker._mainDivId).length == 0 &&
7218 !$target.hasClass($.datepicker.markerClassName) &&
7219 !$target.closest("." + $.datepicker._triggerClass).length &&
7220 $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
7221 ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst != inst ) )
7222 $.datepicker._hideDatepicker();
7223 },
7224
7225 /* Adjust one of the date sub-fields. */
7226 _adjustDate: function(id, offset, period) {
7227 var target = $(id);
7228 var inst = this._getInst(target[0]);
7229 if (this._isDisabledDatepicker(target[0])) {
7230 return;
7231 }
7232 this._adjustInstDate(inst, offset +
7233 (period == 'M' ? this._get(inst, 'showCurrentAtPos') : 0), // undo positioning
7234 period);
7235 this._updateDatepicker(inst);
7236 },
7237
7238 /* Action for current link. */
7239 _gotoToday: function(id) {
7240 var target = $(id);
7241 var inst = this._getInst(target[0]);
7242 if (this._get(inst, 'gotoCurrent') && inst.currentDay) {
7243 inst.selectedDay = inst.currentDay;
7244 inst.drawMonth = inst.selectedMonth = inst.currentMonth;
7245 inst.drawYear = inst.selectedYear = inst.currentYear;
7246 }
7247 else {
7248 var date = new Date();
7249 inst.selectedDay = date.getDate();
7250 inst.drawMonth = inst.selectedMonth = date.getMonth();
7251 inst.drawYear = inst.selectedYear = date.getFullYear();
7252 }
7253 this._notifyChange(inst);
7254 this._adjustDate(target);
7255 },
7256
7257 /* Action for selecting a new month/year. */
7258 _selectMonthYear: function(id, select, period) {
7259 var target = $(id);
7260 var inst = this._getInst(target[0]);
7261 inst['selected' + (period == 'M' ? 'Month' : 'Year')] =
7262 inst['draw' + (period == 'M' ? 'Month' : 'Year')] =
7263 parseInt(select.options[select.selectedIndex].value,10);
7264 this._notifyChange(inst);
7265 this._adjustDate(target);
7266 },
7267
7268 /* Action for selecting a day. */
7269 _selectDay: function(id, month, year, td) {
7270 var target = $(id);
7271 if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
7272 return;
7273 }
7274 var inst = this._getInst(target[0]);
7275 inst.selectedDay = inst.currentDay = $('a', td).html();
7276 inst.selectedMonth = inst.currentMonth = month;
7277 inst.selectedYear = inst.currentYear = year;
7278 this._selectDate(id, this._formatDate(inst,
7279 inst.currentDay, inst.currentMonth, inst.currentYear));
7280 },
7281
7282 /* Erase the input field and hide the date picker. */
7283 _clearDate: function(id) {
7284 var target = $(id);
7285 var inst = this._getInst(target[0]);
7286 this._selectDate(target, '');
7287 },
7288
7289 /* Update the input field with the selected date. */
7290 _selectDate: function(id, dateStr) {
7291 var target = $(id);
7292 var inst = this._getInst(target[0]);
7293 dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
7294 if (inst.input)
7295 inst.input.val(dateStr);
7296 this._updateAlternate(inst);
7297 var onSelect = this._get(inst, 'onSelect');
7298 if (onSelect)
7299 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
7300 else if (inst.input)
7301 inst.input.trigger('change'); // fire the change event
7302 if (inst.inline)
7303 this._updateDatepicker(inst);
7304 else {
7305 this._hideDatepicker();
7306 this._lastInput = inst.input[0];
7307 if (typeof(inst.input[0]) != 'object')
7308 inst.input.focus(); // restore focus
7309 this._lastInput = null;
7310 }
7311 },
7312
7313 /* Update any alternate field to synchronise with the main field. */
7314 _updateAlternate: function(inst) {
7315 var altField = this._get(inst, 'altField');
7316 if (altField) { // update alternate field too
7317 var altFormat = this._get(inst, 'altFormat') || this._get(inst, 'dateFormat');
7318 var date = this._getDate(inst);
7319 var dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
7320 $(altField).each(function() { $(this).val(dateStr); });
7321 }
7322 },
7323
7324 /* Set as beforeShowDay function to prevent selection of weekends.
7325 @param date Date - the date to customise
7326 @return [boolean, string] - is this date selectable?, what is its CSS class? */
7327 noWeekends: function(date) {
7328 var day = date.getDay();
7329 return [(day > 0 && day < 6), ''];
7330 },
7331
7332 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
7333 @param date Date - the date to get the week for
7334 @return number - the number of the week within the year that contains this date */
7335 iso8601Week: function(date) {
7336 var checkDate = new Date(date.getTime());
7337 // Find Thursday of this week starting on Monday
7338 checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
7339 var time = checkDate.getTime();
7340 checkDate.setMonth(0); // Compare with Jan 1
7341 checkDate.setDate(1);
7342 return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
7343 },
7344
7345 /* Parse a string value into a date object.
7346 See formatDate below for the possible formats.
7347
7348 @param format string - the expected format of the date
7349 @param value string - the date in the above format
7350 @param settings Object - attributes include:
7351 shortYearCutoff number - the cutoff year for determining the century (optional)
7352 dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
7353 dayNames string[7] - names of the days from Sunday (optional)
7354 monthNamesShort string[12] - abbreviated names of the months (optional)
7355 monthNames string[12] - names of the months (optional)
7356 @return Date - the extracted date value or null if value is blank */
7357 parseDate: function (format, value, settings) {
7358 if (format == null || value == null)
7359 throw 'Invalid arguments';
7360 value = (typeof value == 'object' ? value.toString() : value + '');
7361 if (value == '')
7362 return null;
7363 var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff;
7364 shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff :
7365 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
7366 var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
7367 var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
7368 var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
7369 var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
7370 var year = -1;
7371 var month = -1;
7372 var day = -1;
7373 var doy = -1;
7374 var literal = false;
7375 // Check whether a format character is doubled
7376 var lookAhead = function(match) {
7377 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
7378 if (matches)
7379 iFormat++;
7380 return matches;
7381 };
7382 // Extract a number from the string value
7383 var getNumber = function(match) {
7384 var isDoubled = lookAhead(match);
7385 var size = (match == '@' ? 14 : (match == '!' ? 20 :
7386 (match == 'y' && isDoubled ? 4 : (match == 'o' ? 3 : 2))));
7387 var digits = new RegExp('^\\d{1,' + size + '}');
7388 var num = value.substring(iValue).match(digits);
7389 if (!num)
7390 throw 'Missing number at position ' + iValue;
7391 iValue += num[0].length;
7392 return parseInt(num[0], 10);
7393 };
7394 // Extract a name from the string value and convert to an index
7395 var getName = function(match, shortNames, longNames) {
7396 var names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
7397 return [ [k, v] ];
7398 }).sort(function (a, b) {
7399 return -(a[1].length - b[1].length);
7400 });
7401 var index = -1;
7402 $.each(names, function (i, pair) {
7403 var name = pair[1];
7404 if (value.substr(iValue, name.length).toLowerCase() == name.toLowerCase()) {
7405 index = pair[0];
7406 iValue += name.length;
7407 return false;
7408 }
7409 });
7410 if (index != -1)
7411 return index + 1;
7412 else
7413 throw 'Unknown name at position ' + iValue;
7414 };
7415 // Confirm that a literal character matches the string value
7416 var checkLiteral = function() {
7417 if (value.charAt(iValue) != format.charAt(iFormat))
7418 throw 'Unexpected literal at position ' + iValue;
7419 iValue++;
7420 };
7421 var iValue = 0;
7422 for (var iFormat = 0; iFormat < format.length; iFormat++) {
7423 if (literal)
7424 if (format.charAt(iFormat) == "'" && !lookAhead("'"))
7425 literal = false;
7426 else
7427 checkLiteral();
7428 else
7429 switch (format.charAt(iFormat)) {
7430 case 'd':
7431 day = getNumber('d');
7432 break;
7433 case 'D':
7434 getName('D', dayNamesShort, dayNames);
7435 break;
7436 case 'o':
7437 doy = getNumber('o');
7438 break;
7439 case 'm':
7440 month = getNumber('m');
7441 break;
7442 case 'M':
7443 month = getName('M', monthNamesShort, monthNames);
7444 break;
7445 case 'y':
7446 year = getNumber('y');
7447 break;
7448 case '@':
7449 var date = new Date(getNumber('@'));
7450 year = date.getFullYear();
7451 month = date.getMonth() + 1;
7452 day = date.getDate();
7453 break;
7454 case '!':
7455 var date = new Date((getNumber('!') - this._ticksTo1970) / 10000);
7456 year = date.getFullYear();
7457 month = date.getMonth() + 1;
7458 day = date.getDate();
7459 break;
7460 case "'":
7461 if (lookAhead("'"))
7462 checkLiteral();
7463 else
7464 literal = true;
7465 break;
7466 default:
7467 checkLiteral();
7468 }
7469 }
7470 if (iValue < value.length){
7471 var extra = value.substr(iValue);
7472 if (!/^\s+/.test(extra)) {
7473 throw "Extra/unparsed characters found in date: " + extra;
7474 }
7475 }
7476 if (year == -1)
7477 year = new Date().getFullYear();
7478 else if (year < 100)
7479 year += new Date().getFullYear() - new Date().getFullYear() % 100 +
7480 (year <= shortYearCutoff ? 0 : -100);
7481 if (doy > -1) {
7482 month = 1;
7483 day = doy;
7484 do {
7485 var dim = this._getDaysInMonth(year, month - 1);
7486 if (day <= dim)
7487 break;
7488 month++;
7489 day -= dim;
7490 } while (true);
7491 }
7492 var date = this._daylightSavingAdjust(new Date(year, month - 1, day));
7493 if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day)
7494 throw 'Invalid date'; // E.g. 31/02/00
7495 return date;
7496 },
7497
7498 /* Standard date formats. */
7499 ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601)
7500 COOKIE: 'D, dd M yy',
7501 ISO_8601: 'yy-mm-dd',
7502 RFC_822: 'D, d M y',
7503 RFC_850: 'DD, dd-M-y',
7504 RFC_1036: 'D, d M y',
7505 RFC_1123: 'D, d M yy',
7506 RFC_2822: 'D, d M yy',
7507 RSS: 'D, d M y', // RFC 822
7508 TICKS: '!',
7509 TIMESTAMP: '@',
7510 W3C: 'yy-mm-dd', // ISO 8601
7511
7512 _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
7513 Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
7514
7515 /* Format a date object into a string value.
7516 The format can be combinations of the following:
7517 d - day of month (no leading zero)
7518 dd - day of month (two digit)
7519 o - day of year (no leading zeros)
7520 oo - day of year (three digit)
7521 D - day name short
7522 DD - day name long
7523 m - month of year (no leading zero)
7524 mm - month of year (two digit)
7525 M - month name short
7526 MM - month name long
7527 y - year (two digit)
7528 yy - year (four digit)
7529 @ - Unix timestamp (ms since 01/01/1970)
7530 ! - Windows ticks (100ns since 01/01/0001)
7531 '...' - literal text
7532 '' - single quote
7533
7534 @param format string - the desired format of the date
7535 @param date Date - the date value to format
7536 @param settings Object - attributes include:
7537 dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
7538 dayNames string[7] - names of the days from Sunday (optional)
7539 monthNamesShort string[12] - abbreviated names of the months (optional)
7540 monthNames string[12] - names of the months (optional)
7541 @return string - the date in the above format */
7542 formatDate: function (format, date, settings) {
7543 if (!date)
7544 return '';
7545 var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
7546 var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
7547 var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
7548 var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
7549 // Check whether a format character is doubled
7550 var lookAhead = function(match) {
7551 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
7552 if (matches)
7553 iFormat++;
7554 return matches;
7555 };
7556 // Format a number, with leading zero if necessary
7557 var formatNumber = function(match, value, len) {
7558 var num = '' + value;
7559 if (lookAhead(match))
7560 while (num.length < len)
7561 num = '0' + num;
7562 return num;
7563 };
7564 // Format a name, short or long as requested
7565 var formatName = function(match, value, shortNames, longNames) {
7566 return (lookAhead(match) ? longNames[value] : shortNames[value]);
7567 };
7568 var output = '';
7569 var literal = false;
7570 if (date)
7571 for (var iFormat = 0; iFormat < format.length; iFormat++) {
7572 if (literal)
7573 if (format.charAt(iFormat) == "'" && !lookAhead("'"))
7574 literal = false;
7575 else
7576 output += format.charAt(iFormat);
7577 else
7578 switch (format.charAt(iFormat)) {
7579 case 'd':
7580 output += formatNumber('d', date.getDate(), 2);
7581 break;
7582 case 'D':
7583 output += formatName('D', date.getDay(), dayNamesShort, dayNames);
7584 break;
7585 case 'o':
7586 output += formatNumber('o',
7587 Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
7588 break;
7589 case 'm':
7590 output += formatNumber('m', date.getMonth() + 1, 2);
7591 break;
7592 case 'M':
7593 output += formatName('M', date.getMonth(), monthNamesShort, monthNames);
7594 break;
7595 case 'y':
7596 output += (lookAhead('y') ? date.getFullYear() :
7597 (date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100);
7598 break;
7599 case '@':
7600 output += date.getTime();
7601 break;
7602 case '!':
7603 output += date.getTime() * 10000 + this._ticksTo1970;
7604 break;
7605 case "'":
7606 if (lookAhead("'"))
7607 output += "'";
7608 else
7609 literal = true;
7610 break;
7611 default:
7612 output += format.charAt(iFormat);
7613 }
7614 }
7615 return output;
7616 },
7617
7618 /* Extract all possible characters from the date format. */
7619 _possibleChars: function (format) {
7620 var chars = '';
7621 var literal = false;
7622 // Check whether a format character is doubled
7623 var lookAhead = function(match) {
7624 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
7625 if (matches)
7626 iFormat++;
7627 return matches;
7628 };
7629 for (var iFormat = 0; iFormat < format.length; iFormat++)
7630 if (literal)
7631 if (format.charAt(iFormat) == "'" && !lookAhead("'"))
7632 literal = false;
7633 else
7634 chars += format.charAt(iFormat);
7635 else
7636 switch (format.charAt(iFormat)) {
7637 case 'd': case 'm': case 'y': case '@':
7638 chars += '0123456789';
7639 break;
7640 case 'D': case 'M':
7641 return null; // Accept anything
7642 case "'":
7643 if (lookAhead("'"))
7644 chars += "'";
7645 else
7646 literal = true;
7647 break;
7648 default:
7649 chars += format.charAt(iFormat);
7650 }
7651 return chars;
7652 },
7653
7654 /* Get a setting value, defaulting if necessary. */
7655 _get: function(inst, name) {
7656 return inst.settings[name] !== undefined ?
7657 inst.settings[name] : this._defaults[name];
7658 },
7659
7660 /* Parse existing date and initialise date picker. */
7661 _setDateFromField: function(inst, noDefault) {
7662 if (inst.input.val() == inst.lastVal) {
7663 return;
7664 }
7665 var dateFormat = this._get(inst, 'dateFormat');
7666 var dates = inst.lastVal = inst.input ? inst.input.val() : null;
7667 var date, defaultDate;
7668 date = defaultDate = this._getDefaultDate(inst);
7669 var settings = this._getFormatConfig(inst);
7670 try {
7671 date = this.parseDate(dateFormat, dates, settings) || defaultDate;
7672 } catch (event) {
7673 this.log(event);
7674 dates = (noDefault ? '' : dates);
7675 }
7676 inst.selectedDay = date.getDate();
7677 inst.drawMonth = inst.selectedMonth = date.getMonth();
7678 inst.drawYear = inst.selectedYear = date.getFullYear();
7679 inst.currentDay = (dates ? date.getDate() : 0);
7680 inst.currentMonth = (dates ? date.getMonth() : 0);
7681 inst.currentYear = (dates ? date.getFullYear() : 0);
7682 this._adjustInstDate(inst);
7683 },
7684
7685 /* Retrieve the default date shown on opening. */
7686 _getDefaultDate: function(inst) {
7687 return this._restrictMinMax(inst,
7688 this._determineDate(inst, this._get(inst, 'defaultDate'), new Date()));
7689 },
7690
7691 /* A date may be specified as an exact value or a relative one. */
7692 _determineDate: function(inst, date, defaultDate) {
7693 var offsetNumeric = function(offset) {
7694 var date = new Date();
7695 date.setDate(date.getDate() + offset);
7696 return date;
7697 };
7698 var offsetString = function(offset) {
7699 try {
7700 return $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'),
7701 offset, $.datepicker._getFormatConfig(inst));
7702 }
7703 catch (e) {
7704 // Ignore
7705 }
7706 var date = (offset.toLowerCase().match(/^c/) ?
7707 $.datepicker._getDate(inst) : null) || new Date();
7708 var year = date.getFullYear();
7709 var month = date.getMonth();
7710 var day = date.getDate();
7711 var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g;
7712 var matches = pattern.exec(offset);
7713 while (matches) {
7714 switch (matches[2] || 'd') {
7715 case 'd' : case 'D' :
7716 day += parseInt(matches[1],10); break;
7717 case 'w' : case 'W' :
7718 day += parseInt(matches[1],10) * 7; break;
7719 case 'm' : case 'M' :
7720 month += parseInt(matches[1],10);
7721 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
7722 break;
7723 case 'y': case 'Y' :
7724 year += parseInt(matches[1],10);
7725 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
7726 break;
7727 }
7728 matches = pattern.exec(offset);
7729 }
7730 return new Date(year, month, day);
7731 };
7732 var newDate = (date == null || date === '' ? defaultDate : (typeof date == 'string' ? offsetString(date) :
7733 (typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
7734 newDate = (newDate && newDate.toString() == 'Invalid Date' ? defaultDate : newDate);
7735 if (newDate) {
7736 newDate.setHours(0);
7737 newDate.setMinutes(0);
7738 newDate.setSeconds(0);
7739 newDate.setMilliseconds(0);
7740 }
7741 return this._daylightSavingAdjust(newDate);
7742 },
7743
7744 /* Handle switch to/from daylight saving.
7745 Hours may be non-zero on daylight saving cut-over:
7746 > 12 when midnight changeover, but then cannot generate
7747 midnight datetime, so jump to 1AM, otherwise reset.
7748 @param date (Date) the date to check
7749 @return (Date) the corrected date */
7750 _daylightSavingAdjust: function(date) {
7751 if (!date) return null;
7752 date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
7753 return date;
7754 },
7755
7756 /* Set the date(s) directly. */
7757 _setDate: function(inst, date, noChange) {
7758 var clear = !date;
7759 var origMonth = inst.selectedMonth;
7760 var origYear = inst.selectedYear;
7761 var newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
7762 inst.selectedDay = inst.currentDay = newDate.getDate();
7763 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
7764 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
7765 if ((origMonth != inst.selectedMonth || origYear != inst.selectedYear) && !noChange)
7766 this._notifyChange(inst);
7767 this._adjustInstDate(inst);
7768 if (inst.input) {
7769 inst.input.val(clear ? '' : this._formatDate(inst));
7770 }
7771 },
7772
7773 /* Retrieve the date(s) directly. */
7774 _getDate: function(inst) {
7775 var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null :
7776 this._daylightSavingAdjust(new Date(
7777 inst.currentYear, inst.currentMonth, inst.currentDay)));
7778 return startDate;
7779 },
7780
7781 /* Attach the onxxx handlers. These are declared statically so
7782 * they work with static code transformers like Caja.
7783 */
7784 _attachHandlers: function(inst) {
7785 var stepMonths = this._get(inst, 'stepMonths');
7786 var id = '#' + inst.id.replace( /\\\\/g, "\\" );
7787 inst.dpDiv.find('[data-handler]').map(function () {
7788 var handler = {
7789 prev: function () {
7790 window['DP_jQuery_' + dpuuid].datepicker._adjustDate(id, -stepMonths, 'M');
7791 },
7792 next: function () {
7793 window['DP_jQuery_' + dpuuid].datepicker._adjustDate(id, +stepMonths, 'M');
7794 },
7795 hide: function () {
7796 window['DP_jQuery_' + dpuuid].datepicker._hideDatepicker();
7797 },
7798 today: function () {
7799 window['DP_jQuery_' + dpuuid].datepicker._gotoToday(id);
7800 },
7801 selectDay: function () {
7802 window['DP_jQuery_' + dpuuid].datepicker._selectDay(id, +this.getAttribute('data-month'), +this.getAttribute('data-year'), this);
7803 return false;
7804 },
7805 selectMonth: function () {
7806 window['DP_jQuery_' + dpuuid].datepicker._selectMonthYear(id, this, 'M');
7807 return false;
7808 },
7809 selectYear: function () {
7810 window['DP_jQuery_' + dpuuid].datepicker._selectMonthYear(id, this, 'Y');
7811 return false;
7812 }
7813 };
7814 $(this).bind(this.getAttribute('data-event'), handler[this.getAttribute('data-handler')]);
7815 });
7816 },
7817
7818 /* Generate the HTML for the current state of the date picker. */
7819 _generateHTML: function(inst) {
7820 var today = new Date();
7821 today = this._daylightSavingAdjust(
7822 new Date(today.getFullYear(), today.getMonth(), today.getDate())); // clear time
7823 var isRTL = this._get(inst, 'isRTL');
7824 var showButtonPanel = this._get(inst, 'showButtonPanel');
7825 var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext');
7826 var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat');
7827 var numMonths = this._getNumberOfMonths(inst);
7828 var showCurrentAtPos = this._get(inst, 'showCurrentAtPos');
7829 var stepMonths = this._get(inst, 'stepMonths');
7830 var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1);
7831 var currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
7832 new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
7833 var minDate = this._getMinMaxDate(inst, 'min');
7834 var maxDate = this._getMinMaxDate(inst, 'max');
7835 var drawMonth = inst.drawMonth - showCurrentAtPos;
7836 var drawYear = inst.drawYear;
7837 if (drawMonth < 0) {
7838 drawMonth += 12;
7839 drawYear--;
7840 }
7841 if (maxDate) {
7842 var maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
7843 maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
7844 maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
7845 while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
7846 drawMonth--;
7847 if (drawMonth < 0) {
7848 drawMonth = 11;
7849 drawYear--;
7850 }
7851 }
7852 }
7853 inst.drawMonth = drawMonth;
7854 inst.drawYear = drawYear;
7855 var prevText = this._get(inst, 'prevText');
7856 prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
7857 this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
7858 this._getFormatConfig(inst)));
7859 var prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
7860 '<a class="ui-datepicker-prev ui-corner-all" data-handler="prev" data-event="click"' +
7861 ' title="' + prevText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'e' : 'w') + '">' + prevText + '</span></a>' :
7862 (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>'));
7863 var nextText = this._get(inst, 'nextText');
7864 nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
7865 this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
7866 this._getFormatConfig(inst)));
7867 var next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
7868 '<a class="ui-datepicker-next ui-corner-all" data-handler="next" data-event="click"' +
7869 ' title="' + nextText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'w' : 'e') + '">' + nextText + '</span></a>' :
7870 (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>'));
7871 var currentText = this._get(inst, 'currentText');
7872 var gotoDate = (this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today);
7873 currentText = (!navigationAsDateFormat ? currentText :
7874 this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
7875 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">' +
7876 this._get(inst, 'closeText') + '</button>' : '');
7877 var buttonPanel = (showButtonPanel) ? '<div class="ui-datepicker-buttonpane ui-widget-content">' + (isRTL ? controls : '') +
7878 (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"' +
7879 '>' + currentText + '</button>' : '') + (isRTL ? '' : controls) + '</div>' : '';
7880 var firstDay = parseInt(this._get(inst, 'firstDay'),10);
7881 firstDay = (isNaN(firstDay) ? 0 : firstDay);
7882 var showWeek = this._get(inst, 'showWeek');
7883 var dayNames = this._get(inst, 'dayNames');
7884 var dayNamesShort = this._get(inst, 'dayNamesShort');
7885 var dayNamesMin = this._get(inst, 'dayNamesMin');
7886 var monthNames = this._get(inst, 'monthNames');
7887 var monthNamesShort = this._get(inst, 'monthNamesShort');
7888 var beforeShowDay = this._get(inst, 'beforeShowDay');
7889 var showOtherMonths = this._get(inst, 'showOtherMonths');
7890 var selectOtherMonths = this._get(inst, 'selectOtherMonths');
7891 var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week;
7892 var defaultDate = this._getDefaultDate(inst);
7893 var html = '';
7894 for (var row = 0; row < numMonths[0]; row++) {
7895 var group = '';
7896 this.maxRows = 4;
7897 for (var col = 0; col < numMonths[1]; col++) {
7898 var selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
7899 var cornerClass = ' ui-corner-all';
7900 var calender = '';
7901 if (isMultiMonth) {
7902 calender += '<div class="ui-datepicker-group';
7903 if (numMonths[1] > 1)
7904 switch (col) {
7905 case 0: calender += ' ui-datepicker-group-first';
7906 cornerClass = ' ui-corner-' + (isRTL ? 'right' : 'left'); break;
7907 case numMonths[1]-1: calender += ' ui-datepicker-group-last';
7908 cornerClass = ' ui-corner-' + (isRTL ? 'left' : 'right'); break;
7909 default: calender += ' ui-datepicker-group-middle'; cornerClass = ''; break;
7910 }
7911 calender += '">';
7912 }
7913 calender += '<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix' + cornerClass + '">' +
7914 (/all|left/.test(cornerClass) && row == 0 ? (isRTL ? next : prev) : '') +
7915 (/all|right/.test(cornerClass) && row == 0 ? (isRTL ? prev : next) : '') +
7916 this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
7917 row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
7918 '</div><table class="ui-datepicker-calendar"><thead>' +
7919 '<tr>';
7920 var thead = (showWeek ? '<th class="ui-datepicker-week-col">' + this._get(inst, 'weekHeader') + '</th>' : '');
7921 for (var dow = 0; dow < 7; dow++) { // days of the week
7922 var day = (dow + firstDay) % 7;
7923 thead += '<th' + ((dow + firstDay + 6) % 7 >= 5 ? ' class="ui-datepicker-week-end"' : '') + '>' +
7924 '<span title="' + dayNames[day] + '">' + dayNamesMin[day] + '</span></th>';
7925 }
7926 calender += thead + '</tr></thead><tbody>';
7927 var daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
7928 if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth)
7929 inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
7930 var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
7931 var curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
7932 var numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
7933 this.maxRows = numRows;
7934 var printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
7935 for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows
7936 calender += '<tr>';
7937 var tbody = (!showWeek ? '' : '<td class="ui-datepicker-week-col">' +
7938 this._get(inst, 'calculateWeek')(printDate) + '</td>');
7939 for (var dow = 0; dow < 7; dow++) { // create date picker days
7940 var daySettings = (beforeShowDay ?
7941 beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']);
7942 var otherMonth = (printDate.getMonth() != drawMonth);
7943 var unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
7944 (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
7945 tbody += '<td class="' +
7946 ((dow + firstDay + 6) % 7 >= 5 ? ' ui-datepicker-week-end' : '') + // highlight weekends
7947 (otherMonth ? ' ui-datepicker-other-month' : '') + // highlight days from other months
7948 ((printDate.getTime() == selectedDate.getTime() && drawMonth == inst.selectedMonth && inst._keyEvent) || // user pressed key
7949 (defaultDate.getTime() == printDate.getTime() && defaultDate.getTime() == selectedDate.getTime()) ?
7950 // or defaultDate is current printedDate and defaultDate is selectedDate
7951 ' ' + this._dayOverClass : '') + // highlight selected day
7952 (unselectable ? ' ' + this._unselectableClass + ' ui-state-disabled': '') + // highlight unselectable days
7953 (otherMonth && !showOtherMonths ? '' : ' ' + daySettings[1] + // highlight custom dates
7954 (printDate.getTime() == currentDate.getTime() ? ' ' + this._currentClass : '') + // highlight selected day
7955 (printDate.getTime() == today.getTime() ? ' ui-datepicker-today' : '')) + '"' + // highlight today (if different)
7956 ((!otherMonth || showOtherMonths) && daySettings[2] ? ' title="' + daySettings[2] + '"' : '') + // cell title
7957 (unselectable ? '' : ' data-handler="selectDay" data-event="click" data-month="' + printDate.getMonth() + '" data-year="' + printDate.getFullYear() + '"') + '>' + // actions
7958 (otherMonth && !showOtherMonths ? '&#xa0;' : // display for other months
7959 (unselectable ? '<span class="ui-state-default">' + printDate.getDate() + '</span>' : '<a class="ui-state-default' +
7960 (printDate.getTime() == today.getTime() ? ' ui-state-highlight' : '') +
7961 (printDate.getTime() == currentDate.getTime() ? ' ui-state-active' : '') + // highlight selected day
7962 (otherMonth ? ' ui-priority-secondary' : '') + // distinguish dates from other months
7963 '" href="#">' + printDate.getDate() + '</a>')) + '</td>'; // display selectable date
7964 printDate.setDate(printDate.getDate() + 1);
7965 printDate = this._daylightSavingAdjust(printDate);
7966 }
7967 calender += tbody + '</tr>';
7968 }
7969 drawMonth++;
7970 if (drawMonth > 11) {
7971 drawMonth = 0;
7972 drawYear++;
7973 }
7974 calender += '</tbody></table>' + (isMultiMonth ? '</div>' +
7975 ((numMonths[0] > 0 && col == numMonths[1]-1) ? '<div class="ui-datepicker-row-break"></div>' : '') : '');
7976 group += calender;
7977 }
7978 html += group;
7979 }
7980 html += buttonPanel + ($.browser.msie && parseInt($.browser.version,10) < 7 && !inst.inline ?
7981 '<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>' : '');
7982 inst._keyEvent = false;
7983 return html;
7984 },
7985
7986 /* Generate the month and year header. */
7987 _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
7988 secondary, monthNames, monthNamesShort) {
7989 var changeMonth = this._get(inst, 'changeMonth');
7990 var changeYear = this._get(inst, 'changeYear');
7991 var showMonthAfterYear = this._get(inst, 'showMonthAfterYear');
7992 var html = '<div class="ui-datepicker-title">';
7993 var monthHtml = '';
7994 // month selection
7995 if (secondary || !changeMonth)
7996 monthHtml += '<span class="ui-datepicker-month">' + monthNames[drawMonth] + '</span>';
7997 else {
7998 var inMinYear = (minDate && minDate.getFullYear() == drawYear);
7999 var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear);
8000 monthHtml += '<select class="ui-datepicker-month" data-handler="selectMonth" data-event="change">';
8001 for (var month = 0; month < 12; month++) {
8002 if ((!inMinYear || month >= minDate.getMonth()) &&
8003 (!inMaxYear || month <= maxDate.getMonth()))
8004 monthHtml += '<option value="' + month + '"' +
8005 (month == drawMonth ? ' selected="selected"' : '') +
8006 '>' + monthNamesShort[month] + '</option>';
8007 }
8008 monthHtml += '</select>';
8009 }
8010 if (!showMonthAfterYear)
8011 html += monthHtml + (secondary || !(changeMonth && changeYear) ? '&#xa0;' : '');
8012 // year selection
8013 if ( !inst.yearshtml ) {
8014 inst.yearshtml = '';
8015 if (secondary || !changeYear)
8016 html += '<span class="ui-datepicker-year">' + drawYear + '</span>';
8017 else {
8018 // determine range of years to display
8019 var years = this._get(inst, 'yearRange').split(':');
8020 var thisYear = new Date().getFullYear();
8021 var determineYear = function(value) {
8022 var year = (value.match(/c[+-].*/) ? drawYear + parseInt(value.substring(1), 10) :
8023 (value.match(/[+-].*/) ? thisYear + parseInt(value, 10) :
8024 parseInt(value, 10)));
8025 return (isNaN(year) ? thisYear : year);
8026 };
8027 var year = determineYear(years[0]);
8028 var endYear = Math.max(year, determineYear(years[1] || ''));
8029 year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
8030 endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
8031 inst.yearshtml += '<select class="ui-datepicker-year" data-handler="selectYear" data-event="change">';
8032 for (; year <= endYear; year++) {
8033 inst.yearshtml += '<option value="' + year + '"' +
8034 (year == drawYear ? ' selected="selected"' : '') +
8035 '>' + year + '</option>';
8036 }
8037 inst.yearshtml += '</select>';
8038
8039 html += inst.yearshtml;
8040 inst.yearshtml = null;
8041 }
8042 }
8043 html += this._get(inst, 'yearSuffix');
8044 if (showMonthAfterYear)
8045 html += (secondary || !(changeMonth && changeYear) ? '&#xa0;' : '') + monthHtml;
8046 html += '</div>'; // Close datepicker_header
8047 return html;
8048 },
8049
8050 /* Adjust one of the date sub-fields. */
8051 _adjustInstDate: function(inst, offset, period) {
8052 var year = inst.drawYear + (period == 'Y' ? offset : 0);
8053 var month = inst.drawMonth + (period == 'M' ? offset : 0);
8054 var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) +
8055 (period == 'D' ? offset : 0);
8056 var date = this._restrictMinMax(inst,
8057 this._daylightSavingAdjust(new Date(year, month, day)));
8058 inst.selectedDay = date.getDate();
8059 inst.drawMonth = inst.selectedMonth = date.getMonth();
8060 inst.drawYear = inst.selectedYear = date.getFullYear();
8061 if (period == 'M' || period == 'Y')
8062 this._notifyChange(inst);
8063 },
8064
8065 /* Ensure a date is within any min/max bounds. */
8066 _restrictMinMax: function(inst, date) {
8067 var minDate = this._getMinMaxDate(inst, 'min');
8068 var maxDate = this._getMinMaxDate(inst, 'max');
8069 var newDate = (minDate && date < minDate ? minDate : date);
8070 newDate = (maxDate && newDate > maxDate ? maxDate : newDate);
8071 return newDate;
8072 },
8073
8074 /* Notify change of month/year. */
8075 _notifyChange: function(inst) {
8076 var onChange = this._get(inst, 'onChangeMonthYear');
8077 if (onChange)
8078 onChange.apply((inst.input ? inst.input[0] : null),
8079 [inst.selectedYear, inst.selectedMonth + 1, inst]);
8080 },
8081
8082 /* Determine the number of months to show. */
8083 _getNumberOfMonths: function(inst) {
8084 var numMonths = this._get(inst, 'numberOfMonths');
8085 return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths));
8086 },
8087
8088 /* Determine the current maximum date - ensure no time components are set. */
8089 _getMinMaxDate: function(inst, minMax) {
8090 return this._determineDate(inst, this._get(inst, minMax + 'Date'), null);
8091 },
8092
8093 /* Find the number of days in a given month. */
8094 _getDaysInMonth: function(year, month) {
8095 return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
8096 },
8097
8098 /* Find the day of the week of the first of a month. */
8099 _getFirstDayOfMonth: function(year, month) {
8100 return new Date(year, month, 1).getDay();
8101 },
8102
8103 /* Determines if we should allow a "next/prev" month display change. */
8104 _canAdjustMonth: function(inst, offset, curYear, curMonth) {
8105 var numMonths = this._getNumberOfMonths(inst);
8106 var date = this._daylightSavingAdjust(new Date(curYear,
8107 curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
8108 if (offset < 0)
8109 date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
8110 return this._isInRange(inst, date);
8111 },
8112
8113 /* Is the given date in the accepted range? */
8114 _isInRange: function(inst, date) {
8115 var minDate = this._getMinMaxDate(inst, 'min');
8116 var maxDate = this._getMinMaxDate(inst, 'max');
8117 return ((!minDate || date.getTime() >= minDate.getTime()) &&
8118 (!maxDate || date.getTime() <= maxDate.getTime()));
8119 },
8120
8121 /* Provide the configuration settings for formatting/parsing. */
8122 _getFormatConfig: function(inst) {
8123 var shortYearCutoff = this._get(inst, 'shortYearCutoff');
8124 shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff :
8125 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
8126 return {shortYearCutoff: shortYearCutoff,
8127 dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'),
8128 monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')};
8129 },
8130
8131 /* Format the given date for display. */
8132 _formatDate: function(inst, day, month, year) {
8133 if (!day) {
8134 inst.currentDay = inst.selectedDay;
8135 inst.currentMonth = inst.selectedMonth;
8136 inst.currentYear = inst.selectedYear;
8137 }
8138 var date = (day ? (typeof day == 'object' ? day :
8139 this._daylightSavingAdjust(new Date(year, month, day))) :
8140 this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
8141 return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst));
8142 }
8143 });
8144
8145 /*
8146 * Bind hover events for datepicker elements.
8147 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
8148 * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
8149 */
8150 function bindHover(dpDiv) {
8151 var selector = 'button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a';
8152 return dpDiv.delegate(selector, 'mouseout', function() {
8153 $(this).removeClass('ui-state-hover');
8154 if (this.className.indexOf('ui-datepicker-prev') != -1) $(this).removeClass('ui-datepicker-prev-hover');
8155 if (this.className.indexOf('ui-datepicker-next') != -1) $(this).removeClass('ui-datepicker-next-hover');
8156 })
8157 .delegate(selector, 'mouseover', function(){
8158 if (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) {
8159 $(this).parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover');
8160 $(this).addClass('ui-state-hover');
8161 if (this.className.indexOf('ui-datepicker-prev') != -1) $(this).addClass('ui-datepicker-prev-hover');
8162 if (this.className.indexOf('ui-datepicker-next') != -1) $(this).addClass('ui-datepicker-next-hover');
8163 }
8164 });
8165 }
8166
8167 /* jQuery extend now ignores nulls! */
8168 function extendRemove(target, props) {
8169 $.extend(target, props);
8170 for (var name in props)
8171 if (props[name] == null || props[name] == undefined)
8172 target[name] = props[name];
8173 return target;
8174 };
8175
8176 /* Invoke the datepicker functionality.
8177 @param options string - a command, optionally followed by additional parameters or
8178 Object - settings for attaching new datepicker functionality
8179 @return jQuery object */
8180 $.fn.datepicker = function(options){
8181
8182 /* Verify an empty collection wasn't passed - Fixes #6976 */
8183 if ( !this.length ) {
8184 return this;
8185 }
8186
8187 /* Initialise the date picker. */
8188 if (!$.datepicker.initialized) {
8189 $(document).mousedown($.datepicker._checkExternalClick).
8190 find(document.body).append($.datepicker.dpDiv);
8191 $.datepicker.initialized = true;
8192 }
8193
8194 var otherArgs = Array.prototype.slice.call(arguments, 1);
8195 if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate' || options == 'widget'))
8196 return $.datepicker['_' + options + 'Datepicker'].
8197 apply($.datepicker, [this[0]].concat(otherArgs));
8198 if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string')
8199 return $.datepicker['_' + options + 'Datepicker'].
8200 apply($.datepicker, [this[0]].concat(otherArgs));
8201 return this.each(function() {
8202 typeof options == 'string' ?
8203 $.datepicker['_' + options + 'Datepicker'].
8204 apply($.datepicker, [this].concat(otherArgs)) :
8205 $.datepicker._attachDatepicker(this, options);
8206 });
8207 };
8208
8209 $.datepicker = new Datepicker(); // singleton instance
8210 $.datepicker.initialized = false;
8211 $.datepicker.uuid = new Date().getTime();
8212 $.datepicker.version = "1.9.0";
8213
8214 // Workaround for #4055
8215 // Add another global to avoid noConflict issues with inline event handlers
8216 window['DP_jQuery_' + dpuuid] = $;
8217
8218 })(jQuery);
8219 (function( $, undefined ) {
8220
8221 var uiDialogClasses = "ui-dialog ui-widget ui-widget-content ui-corner-all ",
8222 sizeRelatedOptions = {
8223 buttons: true,
8224 height: true,
8225 maxHeight: true,
8226 maxWidth: true,
8227 minHeight: true,
8228 minWidth: true,
8229 width: true
8230 },
8231 resizableRelatedOptions = {
8232 maxHeight: true,
8233 maxWidth: true,
8234 minHeight: true,
8235 minWidth: true
8236 };
8237
8238 $.widget("ui.dialog", {
8239 version: "1.9.0",
8240 options: {
8241 autoOpen: true,
8242 buttons: {},
8243 closeOnEscape: true,
8244 closeText: "close",
8245 dialogClass: "",
8246 draggable: true,
8247 hide: null,
8248 height: "auto",
8249 maxHeight: false,
8250 maxWidth: false,
8251 minHeight: 150,
8252 minWidth: 150,
8253 modal: false,
8254 position: {
8255 my: "center",
8256 at: "center",
8257 of: window,
8258 collision: "fit",
8259 // ensure that the titlebar is never outside the document
8260 using: function( pos ) {
8261 var topOffset = $( this ).css( pos ).offset().top;
8262 if ( topOffset < 0 ) {
8263 $( this ).css( "top", pos.top - topOffset );
8264 }
8265 }
8266 },
8267 resizable: true,
8268 show: null,
8269 stack: true,
8270 title: "",
8271 width: 300,
8272 zIndex: 1000
8273 },
8274
8275 _create: function() {
8276 this.originalTitle = this.element.attr( "title" );
8277 // #5742 - .attr() might return a DOMElement
8278 if ( typeof this.originalTitle !== "string" ) {
8279 this.originalTitle = "";
8280 }
8281 this.oldPosition = {
8282 parent: this.element.parent(),
8283 index: this.element.parent().children().index( this.element )
8284 };
8285 this.options.title = this.options.title || this.originalTitle;
8286 var that = this,
8287 options = this.options,
8288
8289 title = options.title || "&#160;",
8290
8291 uiDialog = ( this.uiDialog = $( "<div>" ) )
8292 .addClass( uiDialogClasses + options.dialogClass )
8293 .css({
8294 display: "none",
8295 outline: 0, // TODO: move to stylesheet
8296 zIndex: options.zIndex
8297 })
8298 // setting tabIndex makes the div focusable
8299 .attr( "tabIndex", -1)
8300 .keydown(function( event ) {
8301 if ( options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
8302 event.keyCode === $.ui.keyCode.ESCAPE ) {
8303 that.close( event );
8304 event.preventDefault();
8305 }
8306 })
8307 .mousedown(function( event ) {
8308 that.moveToTop( false, event );
8309 })
8310 .appendTo( "body" ),
8311
8312 uiDialogContent = this.element
8313 .show()
8314 .removeAttr( "title" )
8315 .addClass( "ui-dialog-content ui-widget-content" )
8316 .appendTo( uiDialog ),
8317
8318 uiDialogTitlebar = ( this.uiDialogTitlebar = $( "<div>" ) )
8319 .addClass( "ui-dialog-titlebar ui-widget-header " +
8320 "ui-corner-all ui-helper-clearfix" )
8321 .prependTo( uiDialog ),
8322
8323 uiDialogTitlebarClose = $( "<a href='#'></a>" )
8324 .addClass( "ui-dialog-titlebar-close ui-corner-all" )
8325 .attr( "role", "button" )
8326 .click(function( event ) {
8327 event.preventDefault();
8328 that.close( event );
8329 })
8330 .appendTo( uiDialogTitlebar ),
8331
8332 uiDialogTitlebarCloseText = ( this.uiDialogTitlebarCloseText = $( "<span>" ) )
8333 .addClass( "ui-icon ui-icon-closethick" )
8334 .text( options.closeText )
8335 .appendTo( uiDialogTitlebarClose ),
8336
8337 uiDialogTitle = $( "<span>" )
8338 .uniqueId()
8339 .addClass( "ui-dialog-title" )
8340 .html( title )
8341 .prependTo( uiDialogTitlebar ),
8342
8343 uiDialogButtonPane = ( this.uiDialogButtonPane = $( "<div>" ) )
8344 .addClass( "ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" ),
8345
8346 uiButtonSet = ( this.uiButtonSet = $( "<div>" ) )
8347 .addClass( "ui-dialog-buttonset" )
8348 .appendTo( uiDialogButtonPane );
8349
8350 uiDialog.attr({
8351 role: "dialog",
8352 "aria-labelledby": uiDialogTitle.attr( "id" )
8353 });
8354
8355 uiDialogTitlebar.find( "*" ).add( uiDialogTitlebar ).disableSelection();
8356 this._hoverable( uiDialogTitlebarClose );
8357 this._focusable( uiDialogTitlebarClose );
8358
8359 if ( options.draggable && $.fn.draggable ) {
8360 this._makeDraggable();
8361 }
8362 if ( options.resizable && $.fn.resizable ) {
8363 this._makeResizable();
8364 }
8365
8366 this._createButtons( options.buttons );
8367 this._isOpen = false;
8368
8369 if ( $.fn.bgiframe ) {
8370 uiDialog.bgiframe();
8371 }
8372
8373 // prevent tabbing out of modal dialogs
8374 this._on( uiDialog, { keydown: function( event ) {
8375 if ( !options.modal || event.keyCode !== $.ui.keyCode.TAB ) {
8376 return;
8377 }
8378
8379 var tabbables = $( ":tabbable", uiDialog ),
8380 first = tabbables.filter( ":first" ),
8381 last = tabbables.filter( ":last" );
8382
8383 if ( event.target === last[0] && !event.shiftKey ) {
8384 first.focus( 1 );
8385 return false;
8386 } else if ( event.target === first[0] && event.shiftKey ) {
8387 last.focus( 1 );
8388 return false;
8389 }
8390 }});
8391 },
8392
8393 _init: function() {
8394 if ( this.options.autoOpen ) {
8395 this.open();
8396 }
8397 },
8398
8399 _destroy: function() {
8400 var next,
8401 oldPosition = this.oldPosition;
8402
8403 if ( this.overlay ) {
8404 this.overlay.destroy();
8405 }
8406 this.uiDialog.hide();
8407 this.element
8408 .removeClass( "ui-dialog-content ui-widget-content" )
8409 .hide()
8410 .appendTo( "body" );
8411 this.uiDialog.remove();
8412
8413 if ( this.originalTitle ) {
8414 this.element.attr( "title", this.originalTitle );
8415 }
8416
8417 next = oldPosition.parent.children().eq( oldPosition.index );
8418 // Don't try to place the dialog next to itself (#8613)
8419 if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
8420 next.before( this.element );
8421 } else {
8422 oldPosition.parent.append( this.element );
8423 }
8424 },
8425
8426 widget: function() {
8427 return this.uiDialog;
8428 },
8429
8430 close: function( event ) {
8431 var that = this,
8432 maxZ, thisZ;
8433
8434 if ( !this._isOpen ) {
8435 return;
8436 }
8437
8438 if ( false === this._trigger( "beforeClose", event ) ) {
8439 return;
8440 }
8441
8442 this._isOpen = false;
8443
8444 if ( this.overlay ) {
8445 this.overlay.destroy();
8446 }
8447
8448 if ( this.options.hide ) {
8449 this.uiDialog.hide( this.options.hide, function() {
8450 that._trigger( "close", event );
8451 });
8452 } else {
8453 this.uiDialog.hide();
8454 this._trigger( "close", event );
8455 }
8456
8457 $.ui.dialog.overlay.resize();
8458
8459 // adjust the maxZ to allow other modal dialogs to continue to work (see #4309)
8460 if ( this.options.modal ) {
8461 maxZ = 0;
8462 $( ".ui-dialog" ).each(function() {
8463 if ( this !== that.uiDialog[0] ) {
8464 thisZ = $( this ).css( "z-index" );
8465 if ( !isNaN( thisZ ) ) {
8466 maxZ = Math.max( maxZ, thisZ );
8467 }
8468 }
8469 });
8470 $.ui.dialog.maxZ = maxZ;
8471 }
8472
8473 return this;
8474 },
8475
8476 isOpen: function() {
8477 return this._isOpen;
8478 },
8479
8480 // the force parameter allows us to move modal dialogs to their correct
8481 // position on open
8482 moveToTop: function( force, event ) {
8483 var options = this.options,
8484 saveScroll;
8485
8486 if ( ( options.modal && !force ) ||
8487 ( !options.stack && !options.modal ) ) {
8488 return this._trigger( "focus", event );
8489 }
8490
8491 if ( options.zIndex > $.ui.dialog.maxZ ) {
8492 $.ui.dialog.maxZ = options.zIndex;
8493 }
8494 if ( this.overlay ) {
8495 $.ui.dialog.maxZ += 1;
8496 $.ui.dialog.overlay.maxZ = $.ui.dialog.maxZ;
8497 this.overlay.$el.css( "z-index", $.ui.dialog.overlay.maxZ );
8498 }
8499
8500 // Save and then restore scroll
8501 // Opera 9.5+ resets when parent z-index is changed.
8502 // http://bugs.jqueryui.com/ticket/3193
8503 saveScroll = {
8504 scrollTop: this.element.scrollTop(),
8505 scrollLeft: this.element.scrollLeft()
8506 };
8507 $.ui.dialog.maxZ += 1;
8508 this.uiDialog.css( "z-index", $.ui.dialog.maxZ );
8509 this.element.attr( saveScroll );
8510 this._trigger( "focus", event );
8511
8512 return this;
8513 },
8514
8515 open: function() {
8516 if ( this._isOpen ) {
8517 return;
8518 }
8519
8520 var hasFocus,
8521 options = this.options,
8522 uiDialog = this.uiDialog;
8523
8524 this._size();
8525 this._position( options.position );
8526 uiDialog.show( options.show );
8527 this.overlay = options.modal ? new $.ui.dialog.overlay( this ) : null;
8528 this.moveToTop( true );
8529
8530 // set focus to the first tabbable element in the content area or the first button
8531 // if there are no tabbable elements, set focus on the dialog itself
8532 hasFocus = this.element.find( ":tabbable" );
8533 if ( !hasFocus.length ) {
8534 hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
8535 if ( !hasFocus.length ) {
8536 hasFocus = uiDialog;
8537 }
8538 }
8539 hasFocus.eq( 0 ).focus();
8540
8541 this._isOpen = true;
8542 this._trigger( "open" );
8543
8544 return this;
8545 },
8546
8547 _createButtons: function( buttons ) {
8548 var uiDialogButtonPane, uiButtonSet,
8549 that = this,
8550 hasButtons = false;
8551
8552 // if we already have a button pane, remove it
8553 this.uiDialogButtonPane.remove();
8554 this.uiButtonSet.empty();
8555
8556 if ( typeof buttons === "object" && buttons !== null ) {
8557 $.each( buttons, function() {
8558 return !(hasButtons = true);
8559 });
8560 }
8561 if ( hasButtons ) {
8562 $.each( buttons, function( name, props ) {
8563 props = $.isFunction( props ) ?
8564 { click: props, text: name } :
8565 props;
8566 var button = $( "<button type='button'>" )
8567 .attr( props, true )
8568 .unbind( "click" )
8569 .click(function() {
8570 props.click.apply( that.element[0], arguments );
8571 })
8572 .appendTo( that.uiButtonSet );
8573 if ( $.fn.button ) {
8574 button.button();
8575 }
8576 });
8577 this.uiDialog.addClass( "ui-dialog-buttons" );
8578 this.uiDialogButtonPane.appendTo( this.uiDialog );
8579 } else {
8580 this.uiDialog.removeClass( "ui-dialog-buttons" );
8581 }
8582 },
8583
8584 _makeDraggable: function() {
8585 var that = this,
8586 options = this.options;
8587
8588 function filteredUi( ui ) {
8589 return {
8590 position: ui.position,
8591 offset: ui.offset
8592 };
8593 }
8594
8595 this.uiDialog.draggable({
8596 cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
8597 handle: ".ui-dialog-titlebar",
8598 containment: "document",
8599 start: function( event, ui ) {
8600 $( this )
8601 .addClass( "ui-dialog-dragging" );
8602 that._trigger( "dragStart", event, filteredUi( ui ) );
8603 },
8604 drag: function( event, ui ) {
8605 that._trigger( "drag", event, filteredUi( ui ) );
8606 },
8607 stop: function( event, ui ) {
8608 options.position = [
8609 ui.position.left - that.document.scrollLeft(),
8610 ui.position.top - that.document.scrollTop()
8611 ];
8612 $( this )
8613 .removeClass( "ui-dialog-dragging" );
8614 that._trigger( "dragStop", event, filteredUi( ui ) );
8615 $.ui.dialog.overlay.resize();
8616 }
8617 });
8618 },
8619
8620 _makeResizable: function( handles ) {
8621 handles = (handles === undefined ? this.options.resizable : handles);
8622 var that = this,
8623 options = this.options,
8624 // .ui-resizable has position: relative defined in the stylesheet
8625 // but dialogs have to use absolute or fixed positioning
8626 position = this.uiDialog.css( "position" ),
8627 resizeHandles = typeof handles === 'string' ?
8628 handles :
8629 "n,e,s,w,se,sw,ne,nw";
8630
8631 function filteredUi( ui ) {
8632 return {
8633 originalPosition: ui.originalPosition,
8634 originalSize: ui.originalSize,
8635 position: ui.position,
8636 size: ui.size
8637 };
8638 }
8639
8640 this.uiDialog.resizable({
8641 cancel: ".ui-dialog-content",
8642 containment: "document",
8643 alsoResize: this.element,
8644 maxWidth: options.maxWidth,
8645 maxHeight: options.maxHeight,
8646 minWidth: options.minWidth,
8647 minHeight: this._minHeight(),
8648 handles: resizeHandles,
8649 start: function( event, ui ) {
8650 $( this ).addClass( "ui-dialog-resizing" );
8651 that._trigger( "resizeStart", event, filteredUi( ui ) );
8652 },
8653 resize: function( event, ui ) {
8654 that._trigger( "resize", event, filteredUi( ui ) );
8655 },
8656 stop: function( event, ui ) {
8657 $( this ).removeClass( "ui-dialog-resizing" );
8658 options.height = $( this ).height();
8659 options.width = $( this ).width();
8660 that._trigger( "resizeStop", event, filteredUi( ui ) );
8661 $.ui.dialog.overlay.resize();
8662 }
8663 })
8664 .css( "position", position )
8665 .find( ".ui-resizable-se" )
8666 .addClass( "ui-icon ui-icon-grip-diagonal-se" );
8667 },
8668
8669 _minHeight: function() {
8670 var options = this.options;
8671
8672 if ( options.height === "auto" ) {
8673 return options.minHeight;
8674 } else {
8675 return Math.min( options.minHeight, options.height );
8676 }
8677 },
8678
8679 _position: function( position ) {
8680 var myAt = [],
8681 offset = [ 0, 0 ],
8682 isVisible;
8683
8684 if ( position ) {
8685 // deep extending converts arrays to objects in jQuery <= 1.3.2 :-(
8686 // if (typeof position == 'string' || $.isArray(position)) {
8687 // myAt = $.isArray(position) ? position : position.split(' ');
8688
8689 if ( typeof position === "string" || (typeof position === "object" && "0" in position ) ) {
8690 myAt = position.split ? position.split( " " ) : [ position[ 0 ], position[ 1 ] ];
8691 if ( myAt.length === 1 ) {
8692 myAt[ 1 ] = myAt[ 0 ];
8693 }
8694
8695 $.each( [ "left", "top" ], function( i, offsetPosition ) {
8696 if ( +myAt[ i ] === myAt[ i ] ) {
8697 offset[ i ] = myAt[ i ];
8698 myAt[ i ] = offsetPosition;
8699 }
8700 });
8701
8702 position = {
8703 my: myAt.join( " " ),
8704 at: myAt.join( " " ),
8705 offset: offset.join( " " )
8706 };
8707 }
8708
8709 position = $.extend( {}, $.ui.dialog.prototype.options.position, position );
8710 } else {
8711 position = $.ui.dialog.prototype.options.position;
8712 }
8713
8714 // need to show the dialog to get the actual offset in the position plugin
8715 isVisible = this.uiDialog.is( ":visible" );
8716 if ( !isVisible ) {
8717 this.uiDialog.show();
8718 }
8719 this.uiDialog.position( position );
8720 if ( !isVisible ) {
8721 this.uiDialog.hide();
8722 }
8723 },
8724
8725 _setOptions: function( options ) {
8726 var that = this,
8727 resizableOptions = {},
8728 resize = false;
8729
8730 $.each( options, function( key, value ) {
8731 that._setOption( key, value );
8732
8733 if ( key in sizeRelatedOptions ) {
8734 resize = true;
8735 }
8736 if ( key in resizableRelatedOptions ) {
8737 resizableOptions[ key ] = value;
8738 }
8739 });
8740
8741 if ( resize ) {
8742 this._size();
8743 }
8744 if ( this.uiDialog.is( ":data(resizable)" ) ) {
8745 this.uiDialog.resizable( "option", resizableOptions );
8746 }
8747 },
8748
8749 _setOption: function( key, value ) {
8750 var isDraggable, isResizable,
8751 uiDialog = this.uiDialog;
8752
8753 switch ( key ) {
8754 case "buttons":
8755 this._createButtons( value );
8756 break;
8757 case "closeText":
8758 // ensure that we always pass a string
8759 this.uiDialogTitlebarCloseText.text( "" + value );
8760 break;
8761 case "dialogClass":
8762 uiDialog
8763 .removeClass( this.options.dialogClass )
8764 .addClass( uiDialogClasses + value );
8765 break;
8766 case "disabled":
8767 if ( value ) {
8768 uiDialog.addClass( "ui-dialog-disabled" );
8769 } else {
8770 uiDialog.removeClass( "ui-dialog-disabled" );
8771 }
8772 break;
8773 case "draggable":
8774 isDraggable = uiDialog.is( ":data(draggable)" );
8775 if ( isDraggable && !value ) {
8776 uiDialog.draggable( "destroy" );
8777 }
8778
8779 if ( !isDraggable && value ) {
8780 this._makeDraggable();
8781 }
8782 break;
8783 case "position":
8784 this._position( value );
8785 break;
8786 case "resizable":
8787 // currently resizable, becoming non-resizable
8788 isResizable = uiDialog.is( ":data(resizable)" );
8789 if ( isResizable && !value ) {
8790 uiDialog.resizable( "destroy" );
8791 }
8792
8793 // currently resizable, changing handles
8794 if ( isResizable && typeof value === "string" ) {
8795 uiDialog.resizable( "option", "handles", value );
8796 }
8797
8798 // currently non-resizable, becoming resizable
8799 if ( !isResizable && value !== false ) {
8800 this._makeResizable( value );
8801 }
8802 break;
8803 case "title":
8804 // convert whatever was passed in o a string, for html() to not throw up
8805 $( ".ui-dialog-title", this.uiDialogTitlebar )
8806 .html( "" + ( value || "&#160;" ) );
8807 break;
8808 }
8809
8810 this._super( key, value );
8811 },
8812
8813 _size: function() {
8814 /* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
8815 * divs will both have width and height set, so we need to reset them
8816 */
8817 var nonContentHeight, minContentHeight, autoHeight,
8818 options = this.options,
8819 isVisible = this.uiDialog.is( ":visible" );
8820
8821 // reset content sizing
8822 this.element.show().css({
8823 width: "auto",
8824 minHeight: 0,
8825 height: 0
8826 });
8827
8828 if ( options.minWidth > options.width ) {
8829 options.width = options.minWidth;
8830 }
8831
8832 // reset wrapper sizing
8833 // determine the height of all the non-content elements
8834 nonContentHeight = this.uiDialog.css({
8835 height: "auto",
8836 width: options.width
8837 })
8838 .outerHeight();
8839 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
8840
8841 if ( options.height === "auto" ) {
8842 // only needed for IE6 support
8843 if ( $.support.minHeight ) {
8844 this.element.css({
8845 minHeight: minContentHeight,
8846 height: "auto"
8847 });
8848 } else {
8849 this.uiDialog.show();
8850 autoHeight = this.element.css( "height", "auto" ).height();
8851 if ( !isVisible ) {
8852 this.uiDialog.hide();
8853 }
8854 this.element.height( Math.max( autoHeight, minContentHeight ) );
8855 }
8856 } else {
8857 this.element.height( Math.max( options.height - nonContentHeight, 0 ) );
8858 }
8859
8860 if (this.uiDialog.is( ":data(resizable)" ) ) {
8861 this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
8862 }
8863 }
8864 });
8865
8866 $.extend($.ui.dialog, {
8867 uuid: 0,
8868 maxZ: 0,
8869
8870 getTitleId: function($el) {
8871 var id = $el.attr( "id" );
8872 if ( !id ) {
8873 this.uuid += 1;
8874 id = this.uuid;
8875 }
8876 return "ui-dialog-title-" + id;
8877 },
8878
8879 overlay: function( dialog ) {
8880 this.$el = $.ui.dialog.overlay.create( dialog );
8881 }
8882 });
8883
8884 $.extend( $.ui.dialog.overlay, {
8885 instances: [],
8886 // reuse old instances due to IE memory leak with alpha transparency (see #5185)
8887 oldInstances: [],
8888 maxZ: 0,
8889 events: $.map(
8890 "focus,mousedown,mouseup,keydown,keypress,click".split( "," ),
8891 function( event ) {
8892 return event + ".dialog-overlay";
8893 }
8894 ).join( " " ),
8895 create: function( dialog ) {
8896 if ( this.instances.length === 0 ) {
8897 // prevent use of anchors and inputs
8898 // we use a setTimeout in case the overlay is created from an
8899 // event that we're going to be cancelling (see #2804)
8900 setTimeout(function() {
8901 // handle $(el).dialog().dialog('close') (see #4065)
8902 if ( $.ui.dialog.overlay.instances.length ) {
8903 $( document ).bind( $.ui.dialog.overlay.events, function( event ) {
8904 // stop events if the z-index of the target is < the z-index of the overlay
8905 // we cannot return true when we don't want to cancel the event (#3523)
8906 if ( $( event.target ).zIndex() < $.ui.dialog.overlay.maxZ ) {
8907 return false;
8908 }
8909 });
8910 }
8911 }, 1 );
8912
8913 // handle window resize
8914 $( window ).bind( "resize.dialog-overlay", $.ui.dialog.overlay.resize );
8915 }
8916
8917 var $el = ( this.oldInstances.pop() || $( "<div>" ).addClass( "ui-widget-overlay" ) );
8918
8919 // allow closing by pressing the escape key
8920 $( document ).bind( "keydown.dialog-overlay", function( event ) {
8921 var instances = $.ui.dialog.overlay.instances;
8922 // only react to the event if we're the top overlay
8923 if ( instances.length !== 0 && instances[ instances.length - 1 ] === $el &&
8924 dialog.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
8925 event.keyCode === $.ui.keyCode.ESCAPE ) {
8926
8927 dialog.close( event );
8928 event.preventDefault();
8929 }
8930 });
8931
8932 $el.appendTo( document.body ).css({
8933 width: this.width(),
8934 height: this.height()
8935 });
8936
8937 if ( $.fn.bgiframe ) {
8938 $el.bgiframe();
8939 }
8940
8941 this.instances.push( $el );
8942 return $el;
8943 },
8944
8945 destroy: function( $el ) {
8946 var indexOf = $.inArray( $el, this.instances ),
8947 maxZ = 0;
8948
8949 if ( indexOf !== -1 ) {
8950 this.oldInstances.push( this.instances.splice( indexOf, 1 )[ 0 ] );
8951 }
8952
8953 if ( this.instances.length === 0 ) {
8954 $( [ document, window ] ).unbind( ".dialog-overlay" );
8955 }
8956
8957 $el.height( 0 ).width( 0 ).remove();
8958
8959 // adjust the maxZ to allow other modal dialogs to continue to work (see #4309)
8960 $.each( this.instances, function() {
8961 maxZ = Math.max( maxZ, this.css( "z-index" ) );
8962 });
8963 this.maxZ = maxZ;
8964 },
8965
8966 height: function() {
8967 var scrollHeight,
8968 offsetHeight;
8969 // handle IE
8970 if ( $.browser.msie ) {
8971 scrollHeight = Math.max(
8972 document.documentElement.scrollHeight,
8973 document.body.scrollHeight
8974 );
8975 offsetHeight = Math.max(
8976 document.documentElement.offsetHeight,
8977 document.body.offsetHeight
8978 );
8979
8980 if ( scrollHeight < offsetHeight ) {
8981 return $( window ).height() + "px";
8982 } else {
8983 return scrollHeight + "px";
8984 }
8985 // handle "good" browsers
8986 } else {
8987 return $( document ).height() + "px";
8988 }
8989 },
8990
8991 width: function() {
8992 var scrollWidth,
8993 offsetWidth;
8994 // handle IE
8995 if ( $.browser.msie ) {
8996 scrollWidth = Math.max(
8997 document.documentElement.scrollWidth,
8998 document.body.scrollWidth
8999 );
9000 offsetWidth = Math.max(
9001 document.documentElement.offsetWidth,
9002 document.body.offsetWidth
9003 );
9004
9005 if ( scrollWidth < offsetWidth ) {
9006 return $( window ).width() + "px";
9007 } else {
9008 return scrollWidth + "px";
9009 }
9010 // handle "good" browsers
9011 } else {
9012 return $( document ).width() + "px";
9013 }
9014 },
9015
9016 resize: function() {
9017 /* If the dialog is draggable and the user drags it past the
9018 * right edge of the window, the document becomes wider so we
9019 * need to stretch the overlay. If the user then drags the
9020 * dialog back to the left, the document will become narrower,
9021 * so we need to shrink the overlay to the appropriate size.
9022 * This is handled by shrinking the overlay before setting it
9023 * to the full document size.
9024 */
9025 var $overlays = $( [] );
9026 $.each( $.ui.dialog.overlay.instances, function() {
9027 $overlays = $overlays.add( this );
9028 });
9029
9030 $overlays.css({
9031 width: 0,
9032 height: 0
9033 }).css({
9034 width: $.ui.dialog.overlay.width(),
9035 height: $.ui.dialog.overlay.height()
9036 });
9037 }
9038 });
9039
9040 $.extend( $.ui.dialog.overlay.prototype, {
9041 destroy: function() {
9042 $.ui.dialog.overlay.destroy( this.$el );
9043 }
9044 });
9045
9046 }( jQuery ) );
9047 (function( $, undefined ) {
9048
9049 var mouseHandled = false;
9050
9051 $.widget( "ui.menu", {
9052 version: "1.9.0",
9053 defaultElement: "<ul>",
9054 delay: 300,
9055 options: {
9056 icons: {
9057 submenu: "ui-icon-carat-1-e"
9058 },
9059 menus: "ul",
9060 position: {
9061 my: "left top",
9062 at: "right top"
9063 },
9064 role: "menu",
9065
9066 // callbacks
9067 blur: null,
9068 focus: null,
9069 select: null
9070 },
9071
9072 _create: function() {
9073 this.activeMenu = this.element;
9074 this.element
9075 .uniqueId()
9076 .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
9077 .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
9078 .attr({
9079 role: this.options.role,
9080 tabIndex: 0
9081 })
9082 // need to catch all clicks on disabled menu
9083 // not possible through _on
9084 .bind( "click" + this.eventNamespace, $.proxy(function( event ) {
9085 if ( this.options.disabled ) {
9086 event.preventDefault();
9087 }
9088 }, this ));
9089
9090 if ( this.options.disabled ) {
9091 this.element
9092 .addClass( "ui-state-disabled" )
9093 .attr( "aria-disabled", "true" );
9094 }
9095
9096 this._on({
9097 // Prevent focus from sticking to links inside menu after clicking
9098 // them (focus should always stay on UL during navigation).
9099 "mousedown .ui-menu-item > a": function( event ) {
9100 event.preventDefault();
9101 },
9102 "click .ui-state-disabled > a": function( event ) {
9103 event.preventDefault();
9104 },
9105 "click .ui-menu-item:has(a)": function( event ) {
9106 var target = $( event.target ).closest( ".ui-menu-item" );
9107 if ( !mouseHandled && target.not( ".ui-state-disabled" ).length ) {
9108 mouseHandled = true;
9109
9110 this.select( event );
9111 // Open submenu on click
9112 if ( target.has( ".ui-menu" ).length ) {
9113 this.expand( event );
9114 } else if ( !this.element.is( ":focus" ) ) {
9115 // Redirect focus to the menu
9116 this.element.trigger( "focus", [ true ] );
9117
9118 // If the active item is on the top level, let it stay active.
9119 // Otherwise, blur the active item since it is no longer visible.
9120 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
9121 clearTimeout( this.timer );
9122 }
9123 }
9124 }
9125 },
9126 "mouseenter .ui-menu-item": function( event ) {
9127 var target = $( event.currentTarget );
9128 // Remove ui-state-active class from siblings of the newly focused menu item
9129 // to avoid a jump caused by adjacent elements both having a class with a border
9130 target.siblings().children( ".ui-state-active" ).removeClass( "ui-state-active" );
9131 this.focus( event, target );
9132 },
9133 mouseleave: "collapseAll",
9134 "mouseleave .ui-menu": "collapseAll",
9135 focus: function( event, keepActiveItem ) {
9136 // If there's already an active item, keep it active
9137 // If not, activate the first item
9138 var item = this.active || this.element.children( ".ui-menu-item" ).eq( 0 );
9139
9140 if ( !keepActiveItem ) {
9141 this.focus( event, item );
9142 }
9143 },
9144 blur: function( event ) {
9145 this._delay(function() {
9146 if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
9147 this.collapseAll( event );
9148 }
9149 });
9150 },
9151 keydown: "_keydown"
9152 });
9153
9154 this.refresh();
9155
9156 // Clicks outside of a menu collapse any open menus
9157 this._on( this.document, {
9158 click: function( event ) {
9159 if ( !$( event.target ).closest( ".ui-menu" ).length ) {
9160 this.collapseAll( event );
9161 }
9162
9163 // Reset the mouseHandled flag
9164 mouseHandled = false;
9165 }
9166 });
9167 },
9168
9169 _destroy: function() {
9170 // Destroy (sub)menus
9171 this.element
9172 .removeAttr( "aria-activedescendant" )
9173 .find( ".ui-menu" ).andSelf()
9174 .removeClass( "ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons" )
9175 .removeAttr( "role" )
9176 .removeAttr( "tabIndex" )
9177 .removeAttr( "aria-labelledby" )
9178 .removeAttr( "aria-expanded" )
9179 .removeAttr( "aria-hidden" )
9180 .removeAttr( "aria-disabled" )
9181 .removeUniqueId()
9182 .show();
9183
9184 // Destroy menu items
9185 this.element.find( ".ui-menu-item" )
9186 .removeClass( "ui-menu-item" )
9187 .removeAttr( "role" )
9188 .removeAttr( "aria-disabled" )
9189 .children( "a" )
9190 .removeUniqueId()
9191 .removeClass( "ui-corner-all ui-state-hover" )
9192 .removeAttr( "tabIndex" )
9193 .removeAttr( "role" )
9194 .removeAttr( "aria-haspopup" )
9195 .children().each( function() {
9196 var elem = $( this );
9197 if ( elem.data( "ui-menu-submenu-carat" ) ) {
9198 elem.remove();
9199 }
9200 });
9201
9202 // Destroy menu dividers
9203 this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
9204 },
9205
9206 _keydown: function( event ) {
9207 var match, prev, character, skip, regex,
9208 preventDefault = true;
9209
9210 function escape( value ) {
9211 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
9212 }
9213
9214 switch ( event.keyCode ) {
9215 case $.ui.keyCode.PAGE_UP:
9216 this.previousPage( event );
9217 break;
9218 case $.ui.keyCode.PAGE_DOWN:
9219 this.nextPage( event );
9220 break;
9221 case $.ui.keyCode.HOME:
9222 this._move( "first", "first", event );
9223 break;
9224 case $.ui.keyCode.END:
9225 this._move( "last", "last", event );
9226 break;
9227 case $.ui.keyCode.UP:
9228 this.previous( event );
9229 break;
9230 case $.ui.keyCode.DOWN:
9231 this.next( event );
9232 break;
9233 case $.ui.keyCode.LEFT:
9234 this.collapse( event );
9235 break;
9236 case $.ui.keyCode.RIGHT:
9237 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
9238 this.expand( event );
9239 }
9240 break;
9241 case $.ui.keyCode.ENTER:
9242 case $.ui.keyCode.SPACE:
9243 this._activate( event );
9244 break;
9245 case $.ui.keyCode.ESCAPE:
9246 this.collapse( event );
9247 break;
9248 default:
9249 preventDefault = false;
9250 prev = this.previousFilter || "";
9251 character = String.fromCharCode( event.keyCode );
9252 skip = false;
9253
9254 clearTimeout( this.filterTimer );
9255
9256 if ( character === prev ) {
9257 skip = true;
9258 } else {
9259 character = prev + character;
9260 }
9261
9262 regex = new RegExp( "^" + escape( character ), "i" );
9263 match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
9264 return regex.test( $( this ).children( "a" ).text() );
9265 });
9266 match = skip && match.index( this.active.next() ) !== -1 ?
9267 this.active.nextAll( ".ui-menu-item" ) :
9268 match;
9269
9270 // If no matches on the current filter, reset to the last character pressed
9271 // to move down the menu to the first item that starts with that character
9272 if ( !match.length ) {
9273 character = String.fromCharCode( event.keyCode );
9274 regex = new RegExp( "^" + escape( character ), "i" );
9275 match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
9276 return regex.test( $( this ).children( "a" ).text() );
9277 });
9278 }
9279
9280 if ( match.length ) {
9281 this.focus( event, match );
9282 if ( match.length > 1 ) {
9283 this.previousFilter = character;
9284 this.filterTimer = this._delay(function() {
9285 delete this.previousFilter;
9286 }, 1000 );
9287 } else {
9288 delete this.previousFilter;
9289 }
9290 } else {
9291 delete this.previousFilter;
9292 }
9293 }
9294
9295 if ( preventDefault ) {
9296 event.preventDefault();
9297 }
9298 },
9299
9300 _activate: function( event ) {
9301 if ( !this.active.is( ".ui-state-disabled" ) ) {
9302 if ( this.active.children( "a[aria-haspopup='true']" ).length ) {
9303 this.expand( event );
9304 } else {
9305 this.select( event );
9306 }
9307 }
9308 },
9309
9310 refresh: function() {
9311 // Initialize nested menus
9312 var menus,
9313 icon = this.options.icons.submenu,
9314 submenus = this.element.find( this.options.menus + ":not(.ui-menu)" )
9315 .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
9316 .hide()
9317 .attr({
9318 role: this.options.role,
9319 "aria-hidden": "true",
9320 "aria-expanded": "false"
9321 });
9322
9323 // Don't refresh list items that are already adapted
9324 menus = submenus.add( this.element );
9325
9326 menus.children( ":not(.ui-menu-item):has(a)" )
9327 .addClass( "ui-menu-item" )
9328 .attr( "role", "presentation" )
9329 .children( "a" )
9330 .uniqueId()
9331 .addClass( "ui-corner-all" )
9332 .attr({
9333 tabIndex: -1,
9334 role: this._itemRole()
9335 });
9336
9337 // Initialize unlinked menu-items containing spaces and/or dashes only as dividers
9338 menus.children( ":not(.ui-menu-item)" ).each(function() {
9339 var item = $( this );
9340 // hyphen, em dash, en dash
9341 if ( !/[^\-—–\s]/.test( item.text() ) ) {
9342 item.addClass( "ui-widget-content ui-menu-divider" );
9343 }
9344 });
9345
9346 // Add aria-disabled attribute to any disabled menu item
9347 menus.children( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
9348
9349 submenus.each(function() {
9350 var menu = $( this ),
9351 item = menu.prev( "a" ),
9352 submenuCarat = $( "<span>" )
9353 .addClass( "ui-menu-icon ui-icon " + icon )
9354 .data( "ui-menu-submenu-carat", true );
9355
9356 item
9357 .attr( "aria-haspopup", "true" )
9358 .prepend( submenuCarat );
9359 menu.attr( "aria-labelledby", item.attr( "id" ) );
9360 });
9361
9362 // If the active item has been removed, blur the menu
9363 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
9364 this.blur();
9365 }
9366 },
9367
9368 _itemRole: function() {
9369 return {
9370 menu: "menuitem",
9371 listbox: "option"
9372 }[ this.options.role ];
9373 },
9374
9375 focus: function( event, item ) {
9376 var nested, focused;
9377 this.blur( event, event && event.type === "focus" );
9378
9379 this._scrollIntoView( item );
9380
9381 this.active = item.first();
9382 focused = this.active.children( "a" ).addClass( "ui-state-focus" );
9383 // Only update aria-activedescendant if there's a role
9384 // otherwise we assume focus is managed elsewhere
9385 if ( this.options.role ) {
9386 this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
9387 }
9388
9389 // Highlight active parent menu item, if any
9390 this.active
9391 .parent()
9392 .closest( ".ui-menu-item" )
9393 .children( "a:first" )
9394 .addClass( "ui-state-active" );
9395
9396 if ( event && event.type === "keydown" ) {
9397 this._close();
9398 } else {
9399 this.timer = this._delay(function() {
9400 this._close();
9401 }, this.delay );
9402 }
9403
9404 nested = item.children( ".ui-menu" );
9405 if ( nested.length && ( /^mouse/.test( event.type ) ) ) {
9406 this._startOpening(nested);
9407 }
9408 this.activeMenu = item.parent();
9409
9410 this._trigger( "focus", event, { item: item } );
9411 },
9412
9413 _scrollIntoView: function( item ) {
9414 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
9415 if ( this._hasScroll() ) {
9416 borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
9417 paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
9418 offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
9419 scroll = this.activeMenu.scrollTop();
9420 elementHeight = this.activeMenu.height();
9421 itemHeight = item.height();
9422
9423 if ( offset < 0 ) {
9424 this.activeMenu.scrollTop( scroll + offset );
9425 } else if ( offset + itemHeight > elementHeight ) {
9426 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
9427 }
9428 }
9429 },
9430
9431 blur: function( event, fromFocus ) {
9432 if ( !fromFocus ) {
9433 clearTimeout( this.timer );
9434 }
9435
9436 if ( !this.active ) {
9437 return;
9438 }
9439
9440 this.active.children( "a" ).removeClass( "ui-state-focus" );
9441 this.active = null;
9442
9443 this._trigger( "blur", event, { item: this.active } );
9444 },
9445
9446 _startOpening: function( submenu ) {
9447 clearTimeout( this.timer );
9448
9449 // Don't open if already open fixes a Firefox bug that caused a .5 pixel
9450 // shift in the submenu position when mousing over the carat icon
9451 if ( submenu.attr( "aria-hidden" ) !== "true" ) {
9452 return;
9453 }
9454
9455 this.timer = this._delay(function() {
9456 this._close();
9457 this._open( submenu );
9458 }, this.delay );
9459 },
9460
9461 _open: function( submenu ) {
9462 var position = $.extend({
9463 of: this.active
9464 }, this.options.position );
9465
9466 clearTimeout( this.timer );
9467 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
9468 .hide()
9469 .attr( "aria-hidden", "true" );
9470
9471 submenu
9472 .show()
9473 .removeAttr( "aria-hidden" )
9474 .attr( "aria-expanded", "true" )
9475 .position( position );
9476 },
9477
9478 collapseAll: function( event, all ) {
9479 clearTimeout( this.timer );
9480 this.timer = this._delay(function() {
9481 // If we were passed an event, look for the submenu that contains the event
9482 var currentMenu = all ? this.element :
9483 $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
9484
9485 // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
9486 if ( !currentMenu.length ) {
9487 currentMenu = this.element;
9488 }
9489
9490 this._close( currentMenu );
9491
9492 this.blur( event );
9493 this.activeMenu = currentMenu;
9494 }, this.delay );
9495 },
9496
9497 // With no arguments, closes the currently active menu - if nothing is active
9498 // it closes all menus. If passed an argument, it will search for menus BELOW
9499 _close: function( startMenu ) {
9500 if ( !startMenu ) {
9501 startMenu = this.active ? this.active.parent() : this.element;
9502 }
9503
9504 startMenu
9505 .find( ".ui-menu" )
9506 .hide()
9507 .attr( "aria-hidden", "true" )
9508 .attr( "aria-expanded", "false" )
9509 .end()
9510 .find( "a.ui-state-active" )
9511 .removeClass( "ui-state-active" );
9512 },
9513
9514 collapse: function( event ) {
9515 var newItem = this.active &&
9516 this.active.parent().closest( ".ui-menu-item", this.element );
9517 if ( newItem && newItem.length ) {
9518 this._close();
9519 this.focus( event, newItem );
9520 }
9521 },
9522
9523 expand: function( event ) {
9524 var newItem = this.active &&
9525 this.active
9526 .children( ".ui-menu " )
9527 .children( ".ui-menu-item" )
9528 .first();
9529
9530 if ( newItem && newItem.length ) {
9531 this._open( newItem.parent() );
9532
9533 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
9534 this._delay(function() {
9535 this.focus( event, newItem );
9536 });
9537 }
9538 },
9539
9540 next: function( event ) {
9541 this._move( "next", "first", event );
9542 },
9543
9544 previous: function( event ) {
9545 this._move( "prev", "last", event );
9546 },
9547
9548 isFirstItem: function() {
9549 return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
9550 },
9551
9552 isLastItem: function() {
9553 return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
9554 },
9555
9556 _move: function( direction, filter, event ) {
9557 var next;
9558 if ( this.active ) {
9559 if ( direction === "first" || direction === "last" ) {
9560 next = this.active
9561 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
9562 .eq( -1 );
9563 } else {
9564 next = this.active
9565 [ direction + "All" ]( ".ui-menu-item" )
9566 .eq( 0 );
9567 }
9568 }
9569 if ( !next || !next.length || !this.active ) {
9570 next = this.activeMenu.children( ".ui-menu-item" )[ filter ]();
9571 }
9572
9573 this.focus( event, next );
9574 },
9575
9576 nextPage: function( event ) {
9577 var item, base, height;
9578
9579 if ( !this.active ) {
9580 this.next( event );
9581 return;
9582 }
9583 if ( this.isLastItem() ) {
9584 return;
9585 }
9586 if ( this._hasScroll() ) {
9587 base = this.active.offset().top;
9588 height = this.element.height();
9589 this.active.nextAll( ".ui-menu-item" ).each(function() {
9590 item = $( this );
9591 return item.offset().top - base - height < 0;
9592 });
9593
9594 this.focus( event, item );
9595 } else {
9596 this.focus( event, this.activeMenu.children( ".ui-menu-item" )
9597 [ !this.active ? "first" : "last" ]() );
9598 }
9599 },
9600
9601 previousPage: function( event ) {
9602 var item, base, height;
9603 if ( !this.active ) {
9604 this.next( event );
9605 return;
9606 }
9607 if ( this.isFirstItem() ) {
9608 return;
9609 }
9610 if ( this._hasScroll() ) {
9611 base = this.active.offset().top;
9612 height = this.element.height();
9613 this.active.prevAll( ".ui-menu-item" ).each(function() {
9614 item = $( this );
9615 return item.offset().top - base + height > 0;
9616 });
9617
9618 this.focus( event, item );
9619 } else {
9620 this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
9621 }
9622 },
9623
9624 _hasScroll: function() {
9625 return this.element.outerHeight() < this.element.prop( "scrollHeight" );
9626 },
9627
9628 select: function( event ) {
9629 // TODO: It should never be possible to not have an active item at this
9630 // point, but the tests don't trigger mouseenter before click.
9631 this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
9632 var ui = { item: this.active };
9633 if ( !this.active.has( ".ui-menu" ).length ) {
9634 this.collapseAll( event, true );
9635 }
9636 this._trigger( "select", event, ui );
9637 }
9638 });
9639
9640 }( jQuery ));
9641 (function( $, undefined ) {
9642
9643 $.widget( "ui.progressbar", {
9644 version: "1.9.0",
9645 options: {
9646 value: 0,
9647 max: 100
9648 },
9649
9650 min: 0,
9651
9652 _create: function() {
9653 this.element
9654 .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
9655 .attr({
9656 role: "progressbar",
9657 "aria-valuemin": this.min,
9658 "aria-valuemax": this.options.max,
9659 "aria-valuenow": this._value()
9660 });
9661
9662 this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
9663 .appendTo( this.element );
9664
9665 this.oldValue = this._value();
9666 this._refreshValue();
9667 },
9668
9669 _destroy: function() {
9670 this.element
9671 .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
9672 .removeAttr( "role" )
9673 .removeAttr( "aria-valuemin" )
9674 .removeAttr( "aria-valuemax" )
9675 .removeAttr( "aria-valuenow" );
9676
9677 this.valueDiv.remove();
9678 },
9679
9680 value: function( newValue ) {
9681 if ( newValue === undefined ) {
9682 return this._value();
9683 }
9684
9685 this._setOption( "value", newValue );
9686 return this;
9687 },
9688
9689 _setOption: function( key, value ) {
9690 if ( key === "value" ) {
9691 this.options.value = value;
9692 this._refreshValue();
9693 if ( this._value() === this.options.max ) {
9694 this._trigger( "complete" );
9695 }
9696 }
9697
9698 this._super( key, value );
9699 },
9700
9701 _value: function() {
9702 var val = this.options.value;
9703 // normalize invalid value
9704 if ( typeof val !== "number" ) {
9705 val = 0;
9706 }
9707 return Math.min( this.options.max, Math.max( this.min, val ) );
9708 },
9709
9710 _percentage: function() {
9711 return 100 * this._value() / this.options.max;
9712 },
9713
9714 _refreshValue: function() {
9715 var value = this.value(),
9716 percentage = this._percentage();
9717
9718 if ( this.oldValue !== value ) {
9719 this.oldValue = value;
9720 this._trigger( "change" );
9721 }
9722
9723 this.valueDiv
9724 .toggle( value > this.min )
9725 .toggleClass( "ui-corner-right", value === this.options.max )
9726 .width( percentage.toFixed(0) + "%" );
9727 this.element.attr( "aria-valuenow", value );
9728 }
9729 });
9730
9731 })( jQuery );
9732 (function( $, undefined ) {
9733
9734 // number of pages in a slider
9735 // (how many times can you page up/down to go through the whole range)
9736 var numPages = 5;
9737
9738 $.widget( "ui.slider", $.ui.mouse, {
9739 version: "1.9.0",
9740 widgetEventPrefix: "slide",
9741
9742 options: {
9743 animate: false,
9744 distance: 0,
9745 max: 100,
9746 min: 0,
9747 orientation: "horizontal",
9748 range: false,
9749 step: 1,
9750 value: 0,
9751 values: null
9752 },
9753
9754 _create: function() {
9755 var i,
9756 o = this.options,
9757 existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
9758 handle = "<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",
9759 handleCount = ( o.values && o.values.length ) || 1,
9760 handles = [];
9761
9762 this._keySliding = false;
9763 this._mouseSliding = false;
9764 this._animateOff = true;
9765 this._handleIndex = null;
9766 this._detectOrientation();
9767 this._mouseInit();
9768
9769 this.element
9770 .addClass( "ui-slider" +
9771 " ui-slider-" + this.orientation +
9772 " ui-widget" +
9773 " ui-widget-content" +
9774 " ui-corner-all" +
9775 ( o.disabled ? " ui-slider-disabled ui-disabled" : "" ) );
9776
9777 this.range = $([]);
9778
9779 if ( o.range ) {
9780 if ( o.range === true ) {
9781 if ( !o.values ) {
9782 o.values = [ this._valueMin(), this._valueMin() ];
9783 }
9784 if ( o.values.length && o.values.length !== 2 ) {
9785 o.values = [ o.values[0], o.values[0] ];
9786 }
9787 }
9788
9789 this.range = $( "<div></div>" )
9790 .appendTo( this.element )
9791 .addClass( "ui-slider-range" +
9792 // note: this isn't the most fittingly semantic framework class for this element,
9793 // but worked best visually with a variety of themes
9794 " ui-widget-header" +
9795 ( ( o.range === "min" || o.range === "max" ) ? " ui-slider-range-" + o.range : "" ) );
9796 }
9797
9798 for ( i = existingHandles.length; i < handleCount; i++ ) {
9799 handles.push( handle );
9800 }
9801
9802 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
9803
9804 this.handle = this.handles.eq( 0 );
9805
9806 this.handles.add( this.range ).filter( "a" )
9807 .click(function( event ) {
9808 event.preventDefault();
9809 })
9810 .mouseenter(function() {
9811 if ( !o.disabled ) {
9812 $( this ).addClass( "ui-state-hover" );
9813 }
9814 })
9815 .mouseleave(function() {
9816 $( this ).removeClass( "ui-state-hover" );
9817 })
9818 .focus(function() {
9819 if ( !o.disabled ) {
9820 $( ".ui-slider .ui-state-focus" ).removeClass( "ui-state-focus" );
9821 $( this ).addClass( "ui-state-focus" );
9822 } else {
9823 $( this ).blur();
9824 }
9825 })
9826 .blur(function() {
9827 $( this ).removeClass( "ui-state-focus" );
9828 });
9829
9830 this.handles.each(function( i ) {
9831 $( this ).data( "ui-slider-handle-index", i );
9832 });
9833
9834 this._on( this.handles, {
9835 keydown: function( event ) {
9836 var allowed, curVal, newVal, step,
9837 index = $( event.target ).data( "ui-slider-handle-index" );
9838
9839 switch ( event.keyCode ) {
9840 case $.ui.keyCode.HOME:
9841 case $.ui.keyCode.END:
9842 case $.ui.keyCode.PAGE_UP:
9843 case $.ui.keyCode.PAGE_DOWN:
9844 case $.ui.keyCode.UP:
9845 case $.ui.keyCode.RIGHT:
9846 case $.ui.keyCode.DOWN:
9847 case $.ui.keyCode.LEFT:
9848 event.preventDefault();
9849 if ( !this._keySliding ) {
9850 this._keySliding = true;
9851 $( event.target ).addClass( "ui-state-active" );
9852 allowed = this._start( event, index );
9853 if ( allowed === false ) {
9854 return;
9855 }
9856 }
9857 break;
9858 }
9859
9860 step = this.options.step;
9861 if ( this.options.values && this.options.values.length ) {
9862 curVal = newVal = this.values( index );
9863 } else {
9864 curVal = newVal = this.value();
9865 }
9866
9867 switch ( event.keyCode ) {
9868 case $.ui.keyCode.HOME:
9869 newVal = this._valueMin();
9870 break;
9871 case $.ui.keyCode.END:
9872 newVal = this._valueMax();
9873 break;
9874 case $.ui.keyCode.PAGE_UP:
9875 newVal = this._trimAlignValue( curVal + ( (this._valueMax() - this._valueMin()) / numPages ) );
9876 break;
9877 case $.ui.keyCode.PAGE_DOWN:
9878 newVal = this._trimAlignValue( curVal - ( (this._valueMax() - this._valueMin()) / numPages ) );
9879 break;
9880 case $.ui.keyCode.UP:
9881 case $.ui.keyCode.RIGHT:
9882 if ( curVal === this._valueMax() ) {
9883 return;
9884 }
9885 newVal = this._trimAlignValue( curVal + step );
9886 break;
9887 case $.ui.keyCode.DOWN:
9888 case $.ui.keyCode.LEFT:
9889 if ( curVal === this._valueMin() ) {
9890 return;
9891 }
9892 newVal = this._trimAlignValue( curVal - step );
9893 break;
9894 }
9895
9896 this._slide( event, index, newVal );
9897 },
9898 keyup: function( event ) {
9899 var index = $( event.target ).data( "ui-slider-handle-index" );
9900
9901 if ( this._keySliding ) {
9902 this._keySliding = false;
9903 this._stop( event, index );
9904 this._change( event, index );
9905 $( event.target ).removeClass( "ui-state-active" );
9906 }
9907 }
9908 });
9909
9910 this._refreshValue();
9911
9912 this._animateOff = false;
9913 },
9914
9915 _destroy: function() {
9916 this.handles.remove();
9917 this.range.remove();
9918
9919 this.element
9920 .removeClass( "ui-slider" +
9921 " ui-slider-horizontal" +
9922 " ui-slider-vertical" +
9923 " ui-slider-disabled" +
9924 " ui-widget" +
9925 " ui-widget-content" +
9926 " ui-corner-all" );
9927
9928 this._mouseDestroy();
9929 },
9930
9931 _mouseCapture: function( event ) {
9932 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
9933 that = this,
9934 o = this.options;
9935
9936 if ( o.disabled ) {
9937 return false;
9938 }
9939
9940 this.elementSize = {
9941 width: this.element.outerWidth(),
9942 height: this.element.outerHeight()
9943 };
9944 this.elementOffset = this.element.offset();
9945
9946 position = { x: event.pageX, y: event.pageY };
9947 normValue = this._normValueFromMouse( position );
9948 distance = this._valueMax() - this._valueMin() + 1;
9949 this.handles.each(function( i ) {
9950 var thisDistance = Math.abs( normValue - that.values(i) );
9951 if ( distance > thisDistance ) {
9952 distance = thisDistance;
9953 closestHandle = $( this );
9954 index = i;
9955 }
9956 });
9957
9958 // workaround for bug #3736 (if both handles of a range are at 0,
9959 // the first is always used as the one with least distance,
9960 // and moving it is obviously prevented by preventing negative ranges)
9961 if( o.range === true && this.values(1) === o.min ) {
9962 index += 1;
9963 closestHandle = $( this.handles[index] );
9964 }
9965
9966 allowed = this._start( event, index );
9967 if ( allowed === false ) {
9968 return false;
9969 }
9970 this._mouseSliding = true;
9971
9972 this._handleIndex = index;
9973
9974 closestHandle
9975 .addClass( "ui-state-active" )
9976 .focus();
9977
9978 offset = closestHandle.offset();
9979 mouseOverHandle = !$( event.target ).parents().andSelf().is( ".ui-slider-handle" );
9980 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
9981 left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
9982 top: event.pageY - offset.top -
9983 ( closestHandle.height() / 2 ) -
9984 ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
9985 ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
9986 ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
9987 };
9988
9989 if ( !this.handles.hasClass( "ui-state-hover" ) ) {
9990 this._slide( event, index, normValue );
9991 }
9992 this._animateOff = true;
9993 return true;
9994 },
9995
9996 _mouseStart: function( event ) {
9997 return true;
9998 },
9999
10000 _mouseDrag: function( event ) {
10001 var position = { x: event.pageX, y: event.pageY },
10002 normValue = this._normValueFromMouse( position );
10003
10004 this._slide( event, this._handleIndex, normValue );
10005
10006 return false;
10007 },
10008
10009 _mouseStop: function( event ) {
10010 this.handles.removeClass( "ui-state-active" );
10011 this._mouseSliding = false;
10012
10013 this._stop( event, this._handleIndex );
10014 this._change( event, this._handleIndex );
10015
10016 this._handleIndex = null;
10017 this._clickOffset = null;
10018 this._animateOff = false;
10019
10020 return false;
10021 },
10022
10023 _detectOrientation: function() {
10024 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
10025 },
10026
10027 _normValueFromMouse: function( position ) {
10028 var pixelTotal,
10029 pixelMouse,
10030 percentMouse,
10031 valueTotal,
10032 valueMouse;
10033
10034 if ( this.orientation === "horizontal" ) {
10035 pixelTotal = this.elementSize.width;
10036 pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
10037 } else {
10038 pixelTotal = this.elementSize.height;
10039 pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
10040 }
10041
10042 percentMouse = ( pixelMouse / pixelTotal );
10043 if ( percentMouse > 1 ) {
10044 percentMouse = 1;
10045 }
10046 if ( percentMouse < 0 ) {
10047 percentMouse = 0;
10048 }
10049 if ( this.orientation === "vertical" ) {
10050 percentMouse = 1 - percentMouse;
10051 }
10052
10053 valueTotal = this._valueMax() - this._valueMin();
10054 valueMouse = this._valueMin() + percentMouse * valueTotal;
10055
10056 return this._trimAlignValue( valueMouse );
10057 },
10058
10059 _start: function( event, index ) {
10060 var uiHash = {
10061 handle: this.handles[ index ],
10062 value: this.value()
10063 };
10064 if ( this.options.values && this.options.values.length ) {
10065 uiHash.value = this.values( index );
10066 uiHash.values = this.values();
10067 }
10068 return this._trigger( "start", event, uiHash );
10069 },
10070
10071 _slide: function( event, index, newVal ) {
10072 var otherVal,
10073 newValues,
10074 allowed;
10075
10076 if ( this.options.values && this.options.values.length ) {
10077 otherVal = this.values( index ? 0 : 1 );
10078
10079 if ( ( this.options.values.length === 2 && this.options.range === true ) &&
10080 ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
10081 ) {
10082 newVal = otherVal;
10083 }
10084
10085 if ( newVal !== this.values( index ) ) {
10086 newValues = this.values();
10087 newValues[ index ] = newVal;
10088 // A slide can be canceled by returning false from the slide callback
10089 allowed = this._trigger( "slide", event, {
10090 handle: this.handles[ index ],
10091 value: newVal,
10092 values: newValues
10093 } );
10094 otherVal = this.values( index ? 0 : 1 );
10095 if ( allowed !== false ) {
10096 this.values( index, newVal, true );
10097 }
10098 }
10099 } else {
10100 if ( newVal !== this.value() ) {
10101 // A slide can be canceled by returning false from the slide callback
10102 allowed = this._trigger( "slide", event, {
10103 handle: this.handles[ index ],
10104 value: newVal
10105 } );
10106 if ( allowed !== false ) {
10107 this.value( newVal );
10108 }
10109 }
10110 }
10111 },
10112
10113 _stop: function( event, index ) {
10114 var uiHash = {
10115 handle: this.handles[ index ],
10116 value: this.value()
10117 };
10118 if ( this.options.values && this.options.values.length ) {
10119 uiHash.value = this.values( index );
10120 uiHash.values = this.values();
10121 }
10122
10123 this._trigger( "stop", event, uiHash );
10124 },
10125
10126 _change: function( event, index ) {
10127 if ( !this._keySliding && !this._mouseSliding ) {
10128 var uiHash = {
10129 handle: this.handles[ index ],
10130 value: this.value()
10131 };
10132 if ( this.options.values && this.options.values.length ) {
10133 uiHash.value = this.values( index );
10134 uiHash.values = this.values();
10135 }
10136
10137 this._trigger( "change", event, uiHash );
10138 }
10139 },
10140
10141 value: function( newValue ) {
10142 if ( arguments.length ) {
10143 this.options.value = this._trimAlignValue( newValue );
10144 this._refreshValue();
10145 this._change( null, 0 );
10146 return;
10147 }
10148
10149 return this._value();
10150 },
10151
10152 values: function( index, newValue ) {
10153 var vals,
10154 newValues,
10155 i;
10156
10157 if ( arguments.length > 1 ) {
10158 this.options.values[ index ] = this._trimAlignValue( newValue );
10159 this._refreshValue();
10160 this._change( null, index );
10161 return;
10162 }
10163
10164 if ( arguments.length ) {
10165 if ( $.isArray( arguments[ 0 ] ) ) {
10166 vals = this.options.values;
10167 newValues = arguments[ 0 ];
10168 for ( i = 0; i < vals.length; i += 1 ) {
10169 vals[ i ] = this._trimAlignValue( newValues[ i ] );
10170 this._change( null, i );
10171 }
10172 this._refreshValue();
10173 } else {
10174 if ( this.options.values && this.options.values.length ) {
10175 return this._values( index );
10176 } else {
10177 return this.value();
10178 }
10179 }
10180 } else {
10181 return this._values();
10182 }
10183 },
10184
10185 _setOption: function( key, value ) {
10186 var i,
10187 valsLength = 0;
10188
10189 if ( $.isArray( this.options.values ) ) {
10190 valsLength = this.options.values.length;
10191 }
10192
10193 $.Widget.prototype._setOption.apply( this, arguments );
10194
10195 switch ( key ) {
10196 case "disabled":
10197 if ( value ) {
10198 this.handles.filter( ".ui-state-focus" ).blur();
10199 this.handles.removeClass( "ui-state-hover" );
10200 this.handles.prop( "disabled", true );
10201 this.element.addClass( "ui-disabled" );
10202 } else {
10203 this.handles.prop( "disabled", false );
10204 this.element.removeClass( "ui-disabled" );
10205 }
10206 break;
10207 case "orientation":
10208 this._detectOrientation();
10209 this.element
10210 .removeClass( "ui-slider-horizontal ui-slider-vertical" )
10211 .addClass( "ui-slider-" + this.orientation );
10212 this._refreshValue();
10213 break;
10214 case "value":
10215 this._animateOff = true;
10216 this._refreshValue();
10217 this._change( null, 0 );
10218 this._animateOff = false;
10219 break;
10220 case "values":
10221 this._animateOff = true;
10222 this._refreshValue();
10223 for ( i = 0; i < valsLength; i += 1 ) {
10224 this._change( null, i );
10225 }
10226 this._animateOff = false;
10227 break;
10228 }
10229 },
10230
10231 //internal value getter
10232 // _value() returns value trimmed by min and max, aligned by step
10233 _value: function() {
10234 var val = this.options.value;
10235 val = this._trimAlignValue( val );
10236
10237 return val;
10238 },
10239
10240 //internal values getter
10241 // _values() returns array of values trimmed by min and max, aligned by step
10242 // _values( index ) returns single value trimmed by min and max, aligned by step
10243 _values: function( index ) {
10244 var val,
10245 vals,
10246 i;
10247
10248 if ( arguments.length ) {
10249 val = this.options.values[ index ];
10250 val = this._trimAlignValue( val );
10251
10252 return val;
10253 } else {
10254 // .slice() creates a copy of the array
10255 // this copy gets trimmed by min and max and then returned
10256 vals = this.options.values.slice();
10257 for ( i = 0; i < vals.length; i+= 1) {
10258 vals[ i ] = this._trimAlignValue( vals[ i ] );
10259 }
10260
10261 return vals;
10262 }
10263 },
10264
10265 // returns the step-aligned value that val is closest to, between (inclusive) min and max
10266 _trimAlignValue: function( val ) {
10267 if ( val <= this._valueMin() ) {
10268 return this._valueMin();
10269 }
10270 if ( val >= this._valueMax() ) {
10271 return this._valueMax();
10272 }
10273 var step = ( this.options.step > 0 ) ? this.options.step : 1,
10274 valModStep = (val - this._valueMin()) % step,
10275 alignValue = val - valModStep;
10276
10277 if ( Math.abs(valModStep) * 2 >= step ) {
10278 alignValue += ( valModStep > 0 ) ? step : ( -step );
10279 }
10280
10281 // Since JavaScript has problems with large floats, round
10282 // the final value to 5 digits after the decimal point (see #4124)
10283 return parseFloat( alignValue.toFixed(5) );
10284 },
10285
10286 _valueMin: function() {
10287 return this.options.min;
10288 },
10289
10290 _valueMax: function() {
10291 return this.options.max;
10292 },
10293
10294 _refreshValue: function() {
10295 var lastValPercent, valPercent, value, valueMin, valueMax,
10296 oRange = this.options.range,
10297 o = this.options,
10298 that = this,
10299 animate = ( !this._animateOff ) ? o.animate : false,
10300 _set = {};
10301
10302 if ( this.options.values && this.options.values.length ) {
10303 this.handles.each(function( i, j ) {
10304 valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
10305 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
10306 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
10307 if ( that.options.range === true ) {
10308 if ( that.orientation === "horizontal" ) {
10309 if ( i === 0 ) {
10310 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
10311 }
10312 if ( i === 1 ) {
10313 that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
10314 }
10315 } else {
10316 if ( i === 0 ) {
10317 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
10318 }
10319 if ( i === 1 ) {
10320 that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
10321 }
10322 }
10323 }
10324 lastValPercent = valPercent;
10325 });
10326 } else {
10327 value = this.value();
10328 valueMin = this._valueMin();
10329 valueMax = this._valueMax();
10330 valPercent = ( valueMax !== valueMin ) ?
10331 ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
10332 0;
10333 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
10334 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
10335
10336 if ( oRange === "min" && this.orientation === "horizontal" ) {
10337 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
10338 }
10339 if ( oRange === "max" && this.orientation === "horizontal" ) {
10340 this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
10341 }
10342 if ( oRange === "min" && this.orientation === "vertical" ) {
10343 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
10344 }
10345 if ( oRange === "max" && this.orientation === "vertical" ) {
10346 this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
10347 }
10348 }
10349 }
10350
10351 });
10352
10353 }(jQuery));
10354 (function( $ ) {
10355
10356 function modifier( fn ) {
10357 return function() {
10358 var previous = this.element.val();
10359 fn.apply( this, arguments );
10360 this._refresh();
10361 if ( previous !== this.element.val() ) {
10362 this._trigger( "change" );
10363 }
10364 };
10365 }
10366
10367 $.widget( "ui.spinner", {
10368 version: "1.9.0",
10369 defaultElement: "<input>",
10370 widgetEventPrefix: "spin",
10371 options: {
10372 culture: null,
10373 icons: {
10374 down: "ui-icon-triangle-1-s",
10375 up: "ui-icon-triangle-1-n"
10376 },
10377 incremental: true,
10378 max: null,
10379 min: null,
10380 numberFormat: null,
10381 page: 10,
10382 step: 1,
10383
10384 change: null,
10385 spin: null,
10386 start: null,
10387 stop: null
10388 },
10389
10390 _create: function() {
10391 // handle string values that need to be parsed
10392 this._setOption( "max", this.options.max );
10393 this._setOption( "min", this.options.min );
10394 this._setOption( "step", this.options.step );
10395
10396 // format the value, but don't constrain
10397 this._value( this.element.val(), true );
10398
10399 this._draw();
10400 this._on( this._events );
10401 this._refresh();
10402
10403 // turning off autocomplete prevents the browser from remembering the
10404 // value when navigating through history, so we re-enable autocomplete
10405 // if the page is unloaded before the widget is destroyed. #7790
10406 this._on( this.window, {
10407 beforeunload: function() {
10408 this.element.removeAttr( "autocomplete" );
10409 }
10410 });
10411 },
10412
10413 _getCreateOptions: function() {
10414 var options = {},
10415 element = this.element;
10416
10417 $.each( [ "min", "max", "step" ], function( i, option ) {
10418 var value = element.attr( option );
10419 if ( value !== undefined && value.length ) {
10420 options[ option ] = value;
10421 }
10422 });
10423
10424 return options;
10425 },
10426
10427 _events: {
10428 keydown: function( event ) {
10429 if ( this._start( event ) && this._keydown( event ) ) {
10430 event.preventDefault();
10431 }
10432 },
10433 keyup: "_stop",
10434 focus: function() {
10435 this.uiSpinner.addClass( "ui-state-active" );
10436 this.previous = this.element.val();
10437 },
10438 blur: function( event ) {
10439 if ( this.cancelBlur ) {
10440 delete this.cancelBlur;
10441 return;
10442 }
10443
10444 this._refresh();
10445 this.uiSpinner.removeClass( "ui-state-active" );
10446 if ( this.previous !== this.element.val() ) {
10447 this._trigger( "change", event );
10448 }
10449 },
10450 mousewheel: function( event, delta ) {
10451 if ( !delta ) {
10452 return;
10453 }
10454 if ( !this.spinning && !this._start( event ) ) {
10455 return false;
10456 }
10457
10458 this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
10459 clearTimeout( this.mousewheelTimer );
10460 this.mousewheelTimer = this._delay(function() {
10461 if ( this.spinning ) {
10462 this._stop( event );
10463 }
10464 }, 100 );
10465 event.preventDefault();
10466 },
10467 "mousedown .ui-spinner-button": function( event ) {
10468 var previous;
10469
10470 // We never want the buttons to have focus; whenever the user is
10471 // interacting with the spinner, the focus should be on the input.
10472 // If the input is focused then this.previous is properly set from
10473 // when the input first received focus. If the input is not focused
10474 // then we need to set this.previous based on the value before spinning.
10475 previous = this.element[0] === this.document[0].activeElement ?
10476 this.previous : this.element.val();
10477 function checkFocus() {
10478 var isActive = this.element[0] === this.document[0].activeElement;
10479 if ( !isActive ) {
10480 this.element.focus();
10481 this.previous = previous;
10482 // support: IE
10483 // IE sets focus asynchronously, so we need to check if focus
10484 // moved off of the input because the user clicked on the button.
10485 this._delay(function() {
10486 this.previous = previous;
10487 });
10488 }
10489 }
10490
10491 // ensure focus is on (or stays on) the text field
10492 event.preventDefault();
10493 checkFocus.call( this );
10494
10495 // support: IE
10496 // IE doesn't prevent moving focus even with event.preventDefault()
10497 // so we set a flag to know when we should ignore the blur event
10498 // and check (again) if focus moved off of the input.
10499 this.cancelBlur = true;
10500 this._delay(function() {
10501 delete this.cancelBlur;
10502 checkFocus.call( this );
10503 });
10504
10505 if ( this._start( event ) === false ) {
10506 return;
10507 }
10508
10509 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
10510 },
10511 "mouseup .ui-spinner-button": "_stop",
10512 "mouseenter .ui-spinner-button": function( event ) {
10513 // button will add ui-state-active if mouse was down while mouseleave and kept down
10514 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
10515 return;
10516 }
10517
10518 if ( this._start( event ) === false ) {
10519 return false;
10520 }
10521 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
10522 },
10523 // TODO: do we really want to consider this a stop?
10524 // shouldn't we just stop the repeater and wait until mouseup before
10525 // we trigger the stop event?
10526 "mouseleave .ui-spinner-button": "_stop"
10527 },
10528
10529 _draw: function() {
10530 var uiSpinner = this.uiSpinner = this.element
10531 .addClass( "ui-spinner-input" )
10532 .attr( "autocomplete", "off" )
10533 .wrap( this._uiSpinnerHtml() )
10534 .parent()
10535 // add buttons
10536 .append( this._buttonHtml() );
10537 this._hoverable( uiSpinner );
10538
10539 this.element.attr( "role", "spinbutton" );
10540
10541 // button bindings
10542 this.buttons = uiSpinner.find( ".ui-spinner-button" )
10543 .attr( "tabIndex", -1 )
10544 .button()
10545 .removeClass( "ui-corner-all" );
10546
10547 // IE 6 doesn't understand height: 50% for the buttons
10548 // unless the wrapper has an explicit height
10549 if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&
10550 uiSpinner.height() > 0 ) {
10551 uiSpinner.height( uiSpinner.height() );
10552 }
10553
10554 // disable spinner if element was already disabled
10555 if ( this.options.disabled ) {
10556 this.disable();
10557 }
10558 },
10559
10560 _keydown: function( event ) {
10561 var options = this.options,
10562 keyCode = $.ui.keyCode;
10563
10564 switch ( event.keyCode ) {
10565 case keyCode.UP:
10566 this._repeat( null, 1, event );
10567 return true;
10568 case keyCode.DOWN:
10569 this._repeat( null, -1, event );
10570 return true;
10571 case keyCode.PAGE_UP:
10572 this._repeat( null, options.page, event );
10573 return true;
10574 case keyCode.PAGE_DOWN:
10575 this._repeat( null, -options.page, event );
10576 return true;
10577 }
10578
10579 return false;
10580 },
10581
10582 _uiSpinnerHtml: function() {
10583 return "<span class='ui-spinner ui-state-default ui-widget ui-widget-content ui-corner-all'></span>";
10584 },
10585
10586 _buttonHtml: function() {
10587 return "" +
10588 "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" +
10589 "<span class='ui-icon " + this.options.icons.up + "'>&#9650;</span>" +
10590 "</a>" +
10591 "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" +
10592 "<span class='ui-icon " + this.options.icons.down + "'>&#9660;</span>" +
10593 "</a>";
10594 },
10595
10596 _start: function( event ) {
10597 if ( !this.spinning && this._trigger( "start", event ) === false ) {
10598 return false;
10599 }
10600
10601 if ( !this.counter ) {
10602 this.counter = 1;
10603 }
10604 this.spinning = true;
10605 return true;
10606 },
10607
10608 _repeat: function( i, steps, event ) {
10609 i = i || 500;
10610
10611 clearTimeout( this.timer );
10612 this.timer = this._delay(function() {
10613 this._repeat( 40, steps, event );
10614 }, i );
10615
10616 this._spin( steps * this.options.step, event );
10617 },
10618
10619 _spin: function( step, event ) {
10620 var value = this.value() || 0;
10621
10622 if ( !this.counter ) {
10623 this.counter = 1;
10624 }
10625
10626 value = this._adjustValue( value + step * this._increment( this.counter ) );
10627
10628 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) {
10629 this._value( value );
10630 this.counter++;
10631 }
10632 },
10633
10634 _increment: function( i ) {
10635 var incremental = this.options.incremental;
10636
10637 if ( incremental ) {
10638 return $.isFunction( incremental ) ?
10639 incremental( i ) :
10640 Math.floor( i*i*i/50000 - i*i/500 + 17*i/200 + 1 );
10641 }
10642
10643 return 1;
10644 },
10645
10646 _precision: function() {
10647 var precision = this._precisionOf( this.options.step );
10648 if ( this.options.min !== null ) {
10649 precision = Math.max( precision, this._precisionOf( this.options.min ) );
10650 }
10651 return precision;
10652 },
10653
10654 _precisionOf: function( num ) {
10655 var str = num.toString(),
10656 decimal = str.indexOf( "." );
10657 return decimal === -1 ? 0 : str.length - decimal - 1;
10658 },
10659
10660 _adjustValue: function( value ) {
10661 var base, aboveMin,
10662 options = this.options;
10663
10664 // make sure we're at a valid step
10665 // - find out where we are relative to the base (min or 0)
10666 base = options.min !== null ? options.min : 0;
10667 aboveMin = value - base;
10668 // - round to the nearest step
10669 aboveMin = Math.round(aboveMin / options.step) * options.step;
10670 // - rounding is based on 0, so adjust back to our base
10671 value = base + aboveMin;
10672
10673 // fix precision from bad JS floating point math
10674 value = parseFloat( value.toFixed( this._precision() ) );
10675
10676 // clamp the value
10677 if ( options.max !== null && value > options.max) {
10678 return options.max;
10679 }
10680 if ( options.min !== null && value < options.min ) {
10681 return options.min;
10682 }
10683
10684 return value;
10685 },
10686
10687 _stop: function( event ) {
10688 if ( !this.spinning ) {
10689 return;
10690 }
10691
10692 clearTimeout( this.timer );
10693 clearTimeout( this.mousewheelTimer );
10694 this.counter = 0;
10695 this.spinning = false;
10696 this._trigger( "stop", event );
10697 },
10698
10699 _setOption: function( key, value ) {
10700 if ( key === "culture" || key === "numberFormat" ) {
10701 var prevValue = this._parse( this.element.val() );
10702 this.options[ key ] = value;
10703 this.element.val( this._format( prevValue ) );
10704 return;
10705 }
10706
10707 if ( key === "max" || key === "min" || key === "step" ) {
10708 if ( typeof value === "string" ) {
10709 value = this._parse( value );
10710 }
10711 }
10712
10713 this._super( key, value );
10714
10715 if ( key === "disabled" ) {
10716 if ( value ) {
10717 this.element.prop( "disabled", true );
10718 this.buttons.button( "disable" );
10719 } else {
10720 this.element.prop( "disabled", false );
10721 this.buttons.button( "enable" );
10722 }
10723 }
10724 },
10725
10726 _setOptions: modifier(function( options ) {
10727 this._super( options );
10728 this._value( this.element.val() );
10729 }),
10730
10731 _parse: function( val ) {
10732 if ( typeof val === "string" && val !== "" ) {
10733 val = window.Globalize && this.options.numberFormat ?
10734 Globalize.parseFloat( val, 10, this.options.culture ) : +val;
10735 }
10736 return val === "" || isNaN( val ) ? null : val;
10737 },
10738
10739 _format: function( value ) {
10740 if ( value === "" ) {
10741 return "";
10742 }
10743 return window.Globalize && this.options.numberFormat ?
10744 Globalize.format( value, this.options.numberFormat, this.options.culture ) :
10745 value;
10746 },
10747
10748 _refresh: function() {
10749 this.element.attr({
10750 "aria-valuemin": this.options.min,
10751 "aria-valuemax": this.options.max,
10752 // TODO: what should we do with values that can't be parsed?
10753 "aria-valuenow": this._parse( this.element.val() )
10754 });
10755 },
10756
10757 // update the value without triggering change
10758 _value: function( value, allowAny ) {
10759 var parsed;
10760 if ( value !== "" ) {
10761 parsed = this._parse( value );
10762 if ( parsed !== null ) {
10763 if ( !allowAny ) {
10764 parsed = this._adjustValue( parsed );
10765 }
10766 value = this._format( parsed );
10767 }
10768 }
10769 this.element.val( value );
10770 this._refresh();
10771 },
10772
10773 _destroy: function() {
10774 this.element
10775 .removeClass( "ui-spinner-input" )
10776 .prop( "disabled", false )
10777 .removeAttr( "autocomplete" )
10778 .removeAttr( "role" )
10779 .removeAttr( "aria-valuemin" )
10780 .removeAttr( "aria-valuemax" )
10781 .removeAttr( "aria-valuenow" );
10782 this.uiSpinner.replaceWith( this.element );
10783 },
10784
10785 stepUp: modifier(function( steps ) {
10786 this._stepUp( steps );
10787 }),
10788 _stepUp: function( steps ) {
10789 this._spin( (steps || 1) * this.options.step );
10790 },
10791
10792 stepDown: modifier(function( steps ) {
10793 this._stepDown( steps );
10794 }),
10795 _stepDown: function( steps ) {
10796 this._spin( (steps || 1) * -this.options.step );
10797 },
10798
10799 pageUp: modifier(function( pages ) {
10800 this._stepUp( (pages || 1) * this.options.page );
10801 }),
10802
10803 pageDown: modifier(function( pages ) {
10804 this._stepDown( (pages || 1) * this.options.page );
10805 }),
10806
10807 value: function( newVal ) {
10808 if ( !arguments.length ) {
10809 return this._parse( this.element.val() );
10810 }
10811 modifier( this._value ).call( this, newVal );
10812 },
10813
10814 widget: function() {
10815 return this.uiSpinner;
10816 }
10817 });
10818
10819 }( jQuery ) );
10820 (function( $, undefined ) {
10821
10822 var tabId = 0,
10823 rhash = /#.*$/;
10824
10825 function getNextTabId() {
10826 return ++tabId;
10827 }
10828
10829 function isLocal( anchor ) {
10830 // clone the node to work around IE 6 not normalizing the href property
10831 // if it's manually set, i.e., a.href = "#foo" kills the normalization
10832 anchor = anchor.cloneNode( false );
10833 return anchor.hash.length > 1 &&
10834 anchor.href.replace( rhash, "" ) === location.href.replace( rhash, "" );
10835 }
10836
10837 $.widget( "ui.tabs", {
10838 version: "1.9.0",
10839 delay: 300,
10840 options: {
10841 active: null,
10842 collapsible: false,
10843 event: "click",
10844 heightStyle: "content",
10845 hide: null,
10846 show: null,
10847
10848 // callbacks
10849 activate: null,
10850 beforeActivate: null,
10851 beforeLoad: null,
10852 load: null
10853 },
10854
10855 _create: function() {
10856 var panel,
10857 that = this,
10858 options = this.options,
10859 active = options.active;
10860
10861 this.running = false;
10862
10863 this.element
10864 .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" )
10865 .toggleClass( "ui-tabs-collapsible", options.collapsible )
10866 // Prevent users from focusing disabled tabs via click
10867 .delegate( ".ui-tabs-nav > li", "mousedown" + this.eventNamespace, function( event ) {
10868 if ( $( this ).is( ".ui-state-disabled" ) ) {
10869 event.preventDefault();
10870 }
10871 })
10872 // support: IE <9
10873 // Preventing the default action in mousedown doesn't prevent IE
10874 // from focusing the element, so if the anchor gets focused, blur.
10875 // We don't have to worry about focusing the previously focused
10876 // element since clicking on a non-focusable element should focus
10877 // the body anyway.
10878 .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() {
10879 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
10880 this.blur();
10881 }
10882 });
10883
10884 this._processTabs();
10885
10886 if ( active === null ) {
10887 // check the fragment identifier in the URL
10888 if ( location.hash ) {
10889 this.anchors.each(function( i, anchor ) {
10890 if ( anchor.hash === location.hash ) {
10891 active = i;
10892 return false;
10893 }
10894 });
10895 }
10896
10897 // check for a tab marked active via a class
10898 if ( active === null ) {
10899 active = this.tabs.filter( ".ui-tabs-active" ).index();
10900 }
10901
10902 // no active tab, set to false
10903 if ( active === null || active === -1 ) {
10904 active = this.tabs.length ? 0 : false;
10905 }
10906 }
10907
10908 // handle numbers: negative, out of range
10909 if ( active !== false ) {
10910 active = this.tabs.index( this.tabs.eq( active ) );
10911 if ( active === -1 ) {
10912 active = options.collapsible ? false : 0;
10913 }
10914 }
10915 options.active = active;
10916
10917 // don't allow collapsible: false and active: false
10918 if ( !options.collapsible && options.active === false && this.anchors.length ) {
10919 options.active = 0;
10920 }
10921
10922 // Take disabling tabs via class attribute from HTML
10923 // into account and update option properly.
10924 if ( $.isArray( options.disabled ) ) {
10925 options.disabled = $.unique( options.disabled.concat(
10926 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
10927 return that.tabs.index( li );
10928 })
10929 ) ).sort();
10930 }
10931
10932 // check for length avoids error when initializing empty list
10933 if ( this.options.active !== false && this.anchors.length ) {
10934 this.active = this._findActive( this.options.active );
10935 } else {
10936 this.active = $();
10937 }
10938
10939 this._refresh();
10940
10941 if ( this.active.length ) {
10942 this.load( options.active );
10943 }
10944 },
10945
10946 _getCreateEventData: function() {
10947 return {
10948 tab: this.active,
10949 panel: !this.active.length ? $() : this._getPanelForTab( this.active )
10950 };
10951 },
10952
10953 _tabKeydown: function( event ) {
10954 var focusedTab = $( this.document[0].activeElement ).closest( "li" ),
10955 selectedIndex = this.tabs.index( focusedTab ),
10956 goingForward = true;
10957
10958 if ( this._handlePageNav( event ) ) {
10959 return;
10960 }
10961
10962 switch ( event.keyCode ) {
10963 case $.ui.keyCode.RIGHT:
10964 case $.ui.keyCode.DOWN:
10965 selectedIndex++;
10966 break;
10967 case $.ui.keyCode.UP:
10968 case $.ui.keyCode.LEFT:
10969 goingForward = false;
10970 selectedIndex--;
10971 break;
10972 case $.ui.keyCode.END:
10973 selectedIndex = this.anchors.length - 1;
10974 break;
10975 case $.ui.keyCode.HOME:
10976 selectedIndex = 0;
10977 break;
10978 case $.ui.keyCode.SPACE:
10979 // Activate only, no collapsing
10980 event.preventDefault();
10981 clearTimeout( this.activating );
10982 this._activate( selectedIndex );
10983 return;
10984 case $.ui.keyCode.ENTER:
10985 // Toggle (cancel delayed activation, allow collapsing)
10986 event.preventDefault();
10987 clearTimeout( this.activating );
10988 // Determine if we should collapse or activate
10989 this._activate( selectedIndex === this.options.active ? false : selectedIndex );
10990 return;
10991 default:
10992 return;
10993 }
10994
10995 // Focus the appropriate tab, based on which key was pressed
10996 event.preventDefault();
10997 clearTimeout( this.activating );
10998 selectedIndex = this._focusNextTab( selectedIndex, goingForward );
10999
11000 // Navigating with control key will prevent automatic activation
11001 if ( !event.ctrlKey ) {
11002 // Update aria-selected immediately so that AT think the tab is already selected.
11003 // Otherwise AT may confuse the user by stating that they need to activate the tab,
11004 // but the tab will already be activated by the time the announcement finishes.
11005 focusedTab.attr( "aria-selected", "false" );
11006 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
11007
11008 this.activating = this._delay(function() {
11009 this.option( "active", selectedIndex );
11010 }, this.delay );
11011 }
11012 },
11013
11014 _panelKeydown: function( event ) {
11015 if ( this._handlePageNav( event ) ) {
11016 return;
11017 }
11018
11019 // Ctrl+up moves focus to the current tab
11020 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
11021 event.preventDefault();
11022 this.active.focus();
11023 }
11024 },
11025
11026 // Alt+page up/down moves focus to the previous/next tab (and activates)
11027 _handlePageNav: function( event ) {
11028 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
11029 this._activate( this._focusNextTab( this.options.active - 1, false ) );
11030 return true;
11031 }
11032 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
11033 this._activate( this._focusNextTab( this.options.active + 1, true ) );
11034 return true;
11035 }
11036 },
11037
11038 _findNextTab: function( index, goingForward ) {
11039 var lastTabIndex = this.tabs.length - 1;
11040
11041 function constrain() {
11042 if ( index > lastTabIndex ) {
11043 index = 0;
11044 }
11045 if ( index < 0 ) {
11046 index = lastTabIndex;
11047 }
11048 return index;
11049 }
11050
11051 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
11052 index = goingForward ? index + 1 : index - 1;
11053 }
11054
11055 return index;
11056 },
11057
11058 _focusNextTab: function( index, goingForward ) {
11059 index = this._findNextTab( index, goingForward );
11060 this.tabs.eq( index ).focus();
11061 return index;
11062 },
11063
11064 _setOption: function( key, value ) {
11065 if ( key === "active" ) {
11066 // _activate() will handle invalid values and update this.options
11067 this._activate( value );
11068 return;
11069 }
11070
11071 if ( key === "disabled" ) {
11072 // don't use the widget factory's disabled handling
11073 this._setupDisabled( value );
11074 return;
11075 }
11076
11077 this._super( key, value);
11078
11079 if ( key === "collapsible" ) {
11080 this.element.toggleClass( "ui-tabs-collapsible", value );
11081 // Setting collapsible: false while collapsed; open first panel
11082 if ( !value && this.options.active === false ) {
11083 this._activate( 0 );
11084 }
11085 }
11086
11087 if ( key === "event" ) {
11088 this._setupEvents( value );
11089 }
11090
11091 if ( key === "heightStyle" ) {
11092 this._setupHeightStyle( value );
11093 }
11094 },
11095
11096 _tabId: function( tab ) {
11097 return tab.attr( "aria-controls" ) || "ui-tabs-" + getNextTabId();
11098 },
11099
11100 _sanitizeSelector: function( hash ) {
11101 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
11102 },
11103
11104 refresh: function() {
11105 var next,
11106 options = this.options,
11107 lis = this.tablist.children( ":has(a[href])" );
11108
11109 // get disabled tabs from class attribute from HTML
11110 // this will get converted to a boolean if needed in _refresh()
11111 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
11112 return lis.index( tab );
11113 });
11114
11115 this._processTabs();
11116
11117 // was collapsed or no tabs
11118 if ( options.active === false || !this.anchors.length ) {
11119 options.active = false;
11120 this.active = $();
11121 // was active, but active tab is gone
11122 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
11123 // all remaining tabs are disabled
11124 if ( this.tabs.length === options.disabled.length ) {
11125 options.active = false;
11126 this.active = $();
11127 // activate previous tab
11128 } else {
11129 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
11130 }
11131 // was active, active tab still exists
11132 } else {
11133 // make sure active index is correct
11134 options.active = this.tabs.index( this.active );
11135 }
11136
11137 this._refresh();
11138 },
11139
11140 _refresh: function() {
11141 this._setupDisabled( this.options.disabled );
11142 this._setupEvents( this.options.event );
11143 this._setupHeightStyle( this.options.heightStyle );
11144
11145 this.tabs.not( this.active ).attr({
11146 "aria-selected": "false",
11147 tabIndex: -1
11148 });
11149 this.panels.not( this._getPanelForTab( this.active ) )
11150 .hide()
11151 .attr({
11152 "aria-expanded": "false",
11153 "aria-hidden": "true"
11154 });
11155
11156 // Make sure one tab is in the tab order
11157 if ( !this.active.length ) {
11158 this.tabs.eq( 0 ).attr( "tabIndex", 0 );
11159 } else {
11160 this.active
11161 .addClass( "ui-tabs-active ui-state-active" )
11162 .attr({
11163 "aria-selected": "true",
11164 tabIndex: 0
11165 });
11166 this._getPanelForTab( this.active )
11167 .show()
11168 .attr({
11169 "aria-expanded": "true",
11170 "aria-hidden": "false"
11171 });
11172 }
11173 },
11174
11175 _processTabs: function() {
11176 var that = this;
11177
11178 this.tablist = this._getList()
11179 .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
11180 .attr( "role", "tablist" );
11181
11182 this.tabs = this.tablist.find( "> li:has(a[href])" )
11183 .addClass( "ui-state-default ui-corner-top" )
11184 .attr({
11185 role: "tab",
11186 tabIndex: -1
11187 });
11188
11189 this.anchors = this.tabs.map(function() {
11190 return $( "a", this )[ 0 ];
11191 })
11192 .addClass( "ui-tabs-anchor" )
11193 .attr({
11194 role: "presentation",
11195 tabIndex: -1
11196 });
11197
11198 this.panels = $();
11199
11200 this.anchors.each(function( i, anchor ) {
11201 var selector, panel, panelId,
11202 anchorId = $( anchor ).uniqueId().attr( "id" ),
11203 tab = $( anchor ).closest( "li" ),
11204 originalAriaControls = tab.attr( "aria-controls" );
11205
11206 // inline tab
11207 if ( isLocal( anchor ) ) {
11208 selector = anchor.hash;
11209 panel = that.element.find( that._sanitizeSelector( selector ) );
11210 // remote tab
11211 } else {
11212 panelId = that._tabId( tab );
11213 selector = "#" + panelId;
11214 panel = that.element.find( selector );
11215 if ( !panel.length ) {
11216 panel = that._createPanel( panelId );
11217 panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
11218 }
11219 panel.attr( "aria-live", "polite" );
11220 }
11221
11222 if ( panel.length) {
11223 that.panels = that.panels.add( panel );
11224 }
11225 if ( originalAriaControls ) {
11226 tab.data( "ui-tabs-aria-controls", originalAriaControls );
11227 }
11228 tab.attr({
11229 "aria-controls": selector.substring( 1 ),
11230 "aria-labelledby": anchorId
11231 });
11232 panel.attr( "aria-labelledby", anchorId );
11233 });
11234
11235 this.panels
11236 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
11237 .attr( "role", "tabpanel" );
11238 },
11239
11240 // allow overriding how to find the list for rare usage scenarios (#7715)
11241 _getList: function() {
11242 return this.element.find( "ol,ul" ).eq( 0 );
11243 },
11244
11245 _createPanel: function( id ) {
11246 return $( "<div>" )
11247 .attr( "id", id )
11248 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
11249 .data( "ui-tabs-destroy", true );
11250 },
11251
11252 _setupDisabled: function( disabled ) {
11253 if ( $.isArray( disabled ) ) {
11254 if ( !disabled.length ) {
11255 disabled = false;
11256 } else if ( disabled.length === this.anchors.length ) {
11257 disabled = true;
11258 }
11259 }
11260
11261 // disable tabs
11262 for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {
11263 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
11264 $( li )
11265 .addClass( "ui-state-disabled" )
11266 .attr( "aria-disabled", "true" );
11267 } else {
11268 $( li )
11269 .removeClass( "ui-state-disabled" )
11270 .removeAttr( "aria-disabled" );
11271 }
11272 }
11273
11274 this.options.disabled = disabled;
11275 },
11276
11277 _setupEvents: function( event ) {
11278 var events = {
11279 click: function( event ) {
11280 event.preventDefault();
11281 }
11282 };
11283 if ( event ) {
11284 $.each( event.split(" "), function( index, eventName ) {
11285 events[ eventName ] = "_eventHandler";
11286 });
11287 }
11288
11289 this._off( this.anchors.add( this.tabs ).add( this.panels ) );
11290 this._on( this.anchors, events );
11291 this._on( this.tabs, { keydown: "_tabKeydown" } );
11292 this._on( this.panels, { keydown: "_panelKeydown" } );
11293
11294 this._focusable( this.tabs );
11295 this._hoverable( this.tabs );
11296 },
11297
11298 _setupHeightStyle: function( heightStyle ) {
11299 var maxHeight, overflow,
11300 parent = this.element.parent();
11301
11302 if ( heightStyle === "fill" ) {
11303 // IE 6 treats height like minHeight, so we need to turn off overflow
11304 // in order to get a reliable height
11305 // we use the minHeight support test because we assume that only
11306 // browsers that don't support minHeight will treat height as minHeight
11307 if ( !$.support.minHeight ) {
11308 overflow = parent.css( "overflow" );
11309 parent.css( "overflow", "hidden");
11310 }
11311 maxHeight = parent.height();
11312 this.element.siblings( ":visible" ).each(function() {
11313 var elem = $( this ),
11314 position = elem.css( "position" );
11315
11316 if ( position === "absolute" || position === "fixed" ) {
11317 return;
11318 }
11319 maxHeight -= elem.outerHeight( true );
11320 });
11321 if ( overflow ) {
11322 parent.css( "overflow", overflow );
11323 }
11324
11325 this.element.children().not( this.panels ).each(function() {
11326 maxHeight -= $( this ).outerHeight( true );
11327 });
11328
11329 this.panels.each(function() {
11330 $( this ).height( Math.max( 0, maxHeight -
11331 $( this ).innerHeight() + $( this ).height() ) );
11332 })
11333 .css( "overflow", "auto" );
11334 } else if ( heightStyle === "auto" ) {
11335 maxHeight = 0;
11336 this.panels.each(function() {
11337 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
11338 }).height( maxHeight );
11339 }
11340 },
11341
11342 _eventHandler: function( event ) {
11343 var options = this.options,
11344 active = this.active,
11345 anchor = $( event.currentTarget ),
11346 tab = anchor.closest( "li" ),
11347 clickedIsActive = tab[ 0 ] === active[ 0 ],
11348 collapsing = clickedIsActive && options.collapsible,
11349 toShow = collapsing ? $() : this._getPanelForTab( tab ),
11350 toHide = !active.length ? $() : this._getPanelForTab( active ),
11351 eventData = {
11352 oldTab: active,
11353 oldPanel: toHide,
11354 newTab: collapsing ? $() : tab,
11355 newPanel: toShow
11356 };
11357
11358 event.preventDefault();
11359
11360 if ( tab.hasClass( "ui-state-disabled" ) ||
11361 // tab is already loading
11362 tab.hasClass( "ui-tabs-loading" ) ||
11363 // can't switch durning an animation
11364 this.running ||
11365 // click on active header, but not collapsible
11366 ( clickedIsActive && !options.collapsible ) ||
11367 // allow canceling activation
11368 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
11369 return;
11370 }
11371
11372 options.active = collapsing ? false : this.tabs.index( tab );
11373
11374 this.active = clickedIsActive ? $() : tab;
11375 if ( this.xhr ) {
11376 this.xhr.abort();
11377 }
11378
11379 if ( !toHide.length && !toShow.length ) {
11380 $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
11381 }
11382
11383 if ( toShow.length ) {
11384 this.load( this.tabs.index( tab ), event );
11385 }
11386 this._toggle( event, eventData );
11387 },
11388
11389 // handles show/hide for selecting tabs
11390 _toggle: function( event, eventData ) {
11391 var that = this,
11392 toShow = eventData.newPanel,
11393 toHide = eventData.oldPanel;
11394
11395 this.running = true;
11396
11397 function complete() {
11398 that.running = false;
11399 that._trigger( "activate", event, eventData );
11400 }
11401
11402 function show() {
11403 eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
11404
11405 if ( toShow.length && that.options.show ) {
11406 that._show( toShow, that.options.show, complete );
11407 } else {
11408 toShow.show();
11409 complete();
11410 }
11411 }
11412
11413 // start out by hiding, then showing, then completing
11414 if ( toHide.length && this.options.hide ) {
11415 this._hide( toHide, this.options.hide, function() {
11416 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
11417 show();
11418 });
11419 } else {
11420 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
11421 toHide.hide();
11422 show();
11423 }
11424
11425 toHide.attr({
11426 "aria-expanded": "false",
11427 "aria-hidden": "true"
11428 });
11429 eventData.oldTab.attr( "aria-selected", "false" );
11430 // If we're switching tabs, remove the old tab from the tab order.
11431 // If we're opening from collapsed state, remove the previous tab from the tab order.
11432 // If we're collapsing, then keep the collapsing tab in the tab order.
11433 if ( toShow.length && toHide.length ) {
11434 eventData.oldTab.attr( "tabIndex", -1 );
11435 } else if ( toShow.length ) {
11436 this.tabs.filter(function() {
11437 return $( this ).attr( "tabIndex" ) === 0;
11438 })
11439 .attr( "tabIndex", -1 );
11440 }
11441
11442 toShow.attr({
11443 "aria-expanded": "true",
11444 "aria-hidden": "false"
11445 });
11446 eventData.newTab.attr({
11447 "aria-selected": "true",
11448 tabIndex: 0
11449 });
11450 },
11451
11452 _activate: function( index ) {
11453 var anchor,
11454 active = this._findActive( index );
11455
11456 // trying to activate the already active panel
11457 if ( active[ 0 ] === this.active[ 0 ] ) {
11458 return;
11459 }
11460
11461 // trying to collapse, simulate a click on the current active header
11462 if ( !active.length ) {
11463 active = this.active;
11464 }
11465
11466 anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
11467 this._eventHandler({
11468 target: anchor,
11469 currentTarget: anchor,
11470 preventDefault: $.noop
11471 });
11472 },
11473
11474 _findActive: function( index ) {
11475 return index === false ? $() : this.tabs.eq( index );
11476 },
11477
11478 _getIndex: function( index ) {
11479 // meta-function to give users option to provide a href string instead of a numerical index.
11480 if ( typeof index === "string" ) {
11481 index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) );
11482 }
11483
11484 return index;
11485 },
11486
11487 _destroy: function() {
11488 if ( this.xhr ) {
11489 this.xhr.abort();
11490 }
11491
11492 this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" );
11493
11494 this.tablist
11495 .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
11496 .removeAttr( "role" );
11497
11498 this.anchors
11499 .removeClass( "ui-tabs-anchor" )
11500 .removeAttr( "role" )
11501 .removeAttr( "tabIndex" )
11502 .removeData( "href.tabs" )
11503 .removeData( "load.tabs" )
11504 .removeUniqueId();
11505
11506 this.tabs.add( this.panels ).each(function() {
11507 if ( $.data( this, "ui-tabs-destroy" ) ) {
11508 $( this ).remove();
11509 } else {
11510 $( this )
11511 .removeClass( "ui-state-default ui-state-active ui-state-disabled " +
11512 "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" )
11513 .removeAttr( "tabIndex" )
11514 .removeAttr( "aria-live" )
11515 .removeAttr( "aria-busy" )
11516 .removeAttr( "aria-selected" )
11517 .removeAttr( "aria-labelledby" )
11518 .removeAttr( "aria-hidden" )
11519 .removeAttr( "aria-expanded" )
11520 .removeAttr( "role" );
11521 }
11522 });
11523
11524 this.tabs.each(function() {
11525 var li = $( this ),
11526 prev = li.data( "ui-tabs-aria-controls" );
11527 if ( prev ) {
11528 li.attr( "aria-controls", prev );
11529 } else {
11530 li.removeAttr( "aria-controls" );
11531 }
11532 });
11533
11534 if ( this.options.heightStyle !== "content" ) {
11535 this.panels.css( "height", "" );
11536 }
11537 },
11538
11539 enable: function( index ) {
11540 var disabled = this.options.disabled;
11541 if ( disabled === false ) {
11542 return;
11543 }
11544
11545 if ( index === undefined ) {
11546 disabled = false;
11547 } else {
11548 index = this._getIndex( index );
11549 if ( $.isArray( disabled ) ) {
11550 disabled = $.map( disabled, function( num ) {
11551 return num !== index ? num : null;
11552 });
11553 } else {
11554 disabled = $.map( this.tabs, function( li, num ) {
11555 return num !== index ? num : null;
11556 });
11557 }
11558 }
11559 this._setupDisabled( disabled );
11560 },
11561
11562 disable: function( index ) {
11563 var disabled = this.options.disabled;
11564 if ( disabled === true ) {
11565 return;
11566 }
11567
11568 if ( index === undefined ) {
11569 disabled = true;
11570 } else {
11571 index = this._getIndex( index );
11572 if ( $.inArray( index, disabled ) !== -1 ) {
11573 return;
11574 }
11575 if ( $.isArray( disabled ) ) {
11576 disabled = $.merge( [ index ], disabled ).sort();
11577 } else {
11578 disabled = [ index ];
11579 }
11580 }
11581 this._setupDisabled( disabled );
11582 },
11583
11584 load: function( index, event ) {
11585 index = this._getIndex( index );
11586 var that = this,
11587 tab = this.tabs.eq( index ),
11588 anchor = tab.find( ".ui-tabs-anchor" ),
11589 panel = this._getPanelForTab( tab ),
11590 eventData = {
11591 tab: tab,
11592 panel: panel
11593 };
11594
11595 // not remote
11596 if ( isLocal( anchor[ 0 ] ) ) {
11597 return;
11598 }
11599
11600 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
11601
11602 // support: jQuery <1.8
11603 // jQuery <1.8 returns false if the request is canceled in beforeSend,
11604 // but as of 1.8, $.ajax() always returns a jqXHR object.
11605 if ( this.xhr && this.xhr.statusText !== "canceled" ) {
11606 tab.addClass( "ui-tabs-loading" );
11607 panel.attr( "aria-busy", "true" );
11608
11609 this.xhr
11610 .success(function( response ) {
11611 // support: jQuery <1.8
11612 // http://bugs.jquery.com/ticket/11778
11613 setTimeout(function() {
11614 panel.html( response );
11615 that._trigger( "load", event, eventData );
11616 }, 1 );
11617 })
11618 .complete(function( jqXHR, status ) {
11619 // support: jQuery <1.8
11620 // http://bugs.jquery.com/ticket/11778
11621 setTimeout(function() {
11622 if ( status === "abort" ) {
11623 that.panels.stop( false, true );
11624 }
11625
11626 tab.removeClass( "ui-tabs-loading" );
11627 panel.removeAttr( "aria-busy" );
11628
11629 if ( jqXHR === that.xhr ) {
11630 delete that.xhr;
11631 }
11632 }, 1 );
11633 });
11634 }
11635 },
11636
11637 // TODO: Remove this function in 1.10 when ajaxOptions is removed
11638 _ajaxSettings: function( anchor, event, eventData ) {
11639 var that = this;
11640 return {
11641 url: anchor.attr( "href" ),
11642 beforeSend: function( jqXHR, settings ) {
11643 return that._trigger( "beforeLoad", event,
11644 $.extend( { jqXHR : jqXHR, ajaxSettings: settings }, eventData ) );
11645 }
11646 };
11647 },
11648
11649 _getPanelForTab: function( tab ) {
11650 var id = $( tab ).attr( "aria-controls" );
11651 return this.element.find( this._sanitizeSelector( "#" + id ) );
11652 }
11653 });
11654
11655 // DEPRECATED
11656 if ( $.uiBackCompat !== false ) {
11657
11658 // helper method for a lot of the back compat extensions
11659 $.ui.tabs.prototype._ui = function( tab, panel ) {
11660 return {
11661 tab: tab,
11662 panel: panel,
11663 index: this.anchors.index( tab )
11664 };
11665 };
11666
11667 // url method
11668 $.widget( "ui.tabs", $.ui.tabs, {
11669 url: function( index, url ) {
11670 this.anchors.eq( index ).attr( "href", url );
11671 }
11672 });
11673
11674 // TODO: Remove _ajaxSettings() method when removing this extension
11675 // ajaxOptions and cache options
11676 $.widget( "ui.tabs", $.ui.tabs, {
11677 options: {
11678 ajaxOptions: null,
11679 cache: false
11680 },
11681
11682 _create: function() {
11683 this._super();
11684
11685 var that = this;
11686
11687 this._on({ tabsbeforeload: function( event, ui ) {
11688 // tab is already cached
11689 if ( $.data( ui.tab[ 0 ], "cache.tabs" ) ) {
11690 event.preventDefault();
11691 return;
11692 }
11693
11694 ui.jqXHR.success(function() {
11695 if ( that.options.cache ) {
11696 $.data( ui.tab[ 0 ], "cache.tabs", true );
11697 }
11698 });
11699 }});
11700 },
11701
11702 _ajaxSettings: function( anchor, event, ui ) {
11703 var ajaxOptions = this.options.ajaxOptions;
11704 return $.extend( {}, ajaxOptions, {
11705 error: function( xhr, s, e ) {
11706 try {
11707 // Passing index avoid a race condition when this method is
11708 // called after the user has selected another tab.
11709 // Pass the anchor that initiated this request allows
11710 // loadError to manipulate the tab content panel via $(a.hash)
11711 ajaxOptions.error(
11712 xhr, s, ui.tab.closest( "li" ).index(), ui.tab[ 0 ] );
11713 }
11714 catch ( e ) {}
11715 }
11716 }, this._superApply( arguments ) );
11717 },
11718
11719 _setOption: function( key, value ) {
11720 // reset cache if switching from cached to not cached
11721 if ( key === "cache" && value === false ) {
11722 this.anchors.removeData( "cache.tabs" );
11723 }
11724 this._super( key, value );
11725 },
11726
11727 _destroy: function() {
11728 this.anchors.removeData( "cache.tabs" );
11729 this._super();
11730 },
11731
11732 url: function( index, url ){
11733 this.anchors.eq( index ).removeData( "cache.tabs" );
11734 this._superApply( arguments );
11735 }
11736 });
11737
11738 // abort method
11739 $.widget( "ui.tabs", $.ui.tabs, {
11740 abort: function() {
11741 if ( this.xhr ) {
11742 this.xhr.abort();
11743 }
11744 }
11745 });
11746
11747 // spinner
11748 $.widget( "ui.tabs", $.ui.tabs, {
11749 options: {
11750 spinner: "<em>Loading&#8230;</em>"
11751 },
11752 _create: function() {
11753 this._super();
11754 this._on({
11755 tabsbeforeload: function( event, ui ) {
11756 // Don't react to nested tabs or tabs that don't use a spinner
11757 if ( event.target !== this.element[ 0 ] ||
11758 !this.options.spinner ) {
11759 return;
11760 }
11761
11762 var span = ui.tab.find( "span" ),
11763 html = span.html();
11764 span.html( this.options.spinner );
11765 ui.jqXHR.complete(function() {
11766 span.html( html );
11767 });
11768 }
11769 });
11770 }
11771 });
11772
11773 // enable/disable events
11774 $.widget( "ui.tabs", $.ui.tabs, {
11775 options: {
11776 enable: null,
11777 disable: null
11778 },
11779
11780 enable: function( index ) {
11781 var options = this.options,
11782 trigger;
11783
11784 if ( index && options.disabled === true ||
11785 ( $.isArray( options.disabled ) && $.inArray( index, options.disabled ) !== -1 ) ) {
11786 trigger = true;
11787 }
11788
11789 this._superApply( arguments );
11790
11791 if ( trigger ) {
11792 this._trigger( "enable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
11793 }
11794 },
11795
11796 disable: function( index ) {
11797 var options = this.options,
11798 trigger;
11799
11800 if ( index && options.disabled === false ||
11801 ( $.isArray( options.disabled ) && $.inArray( index, options.disabled ) === -1 ) ) {
11802 trigger = true;
11803 }
11804
11805 this._superApply( arguments );
11806
11807 if ( trigger ) {
11808 this._trigger( "disable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
11809 }
11810 }
11811 });
11812
11813 // add/remove methods and events
11814 $.widget( "ui.tabs", $.ui.tabs, {
11815 options: {
11816 add: null,
11817 remove: null,
11818 tabTemplate: "<li><a href='#{href}'><span>#{label}</span></a></li>"
11819 },
11820
11821 add: function( url, label, index ) {
11822 if ( index === undefined ) {
11823 index = this.anchors.length;
11824 }
11825
11826 var doInsertAfter, panel,
11827 options = this.options,
11828 li = $( options.tabTemplate
11829 .replace( /#\{href\}/g, url )
11830 .replace( /#\{label\}/g, label ) ),
11831 id = !url.indexOf( "#" ) ?
11832 url.replace( "#", "" ) :
11833 this._tabId( li );
11834
11835 li.addClass( "ui-state-default ui-corner-top" ).data( "ui-tabs-destroy", true );
11836 li.attr( "aria-controls", id );
11837
11838 doInsertAfter = index >= this.tabs.length;
11839
11840 // try to find an existing element before creating a new one
11841 panel = this.element.find( "#" + id );
11842 if ( !panel.length ) {
11843 panel = this._createPanel( id );
11844 if ( doInsertAfter ) {
11845 if ( index > 0 ) {
11846 panel.insertAfter( this.panels.eq( -1 ) );
11847 } else {
11848 panel.appendTo( this.element );
11849 }
11850 } else {
11851 panel.insertBefore( this.panels[ index ] );
11852 }
11853 }
11854 panel.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ).hide();
11855
11856 if ( doInsertAfter ) {
11857 li.appendTo( this.tablist );
11858 } else {
11859 li.insertBefore( this.tabs[ index ] );
11860 }
11861
11862 options.disabled = $.map( options.disabled, function( n ) {
11863 return n >= index ? ++n : n;
11864 });
11865
11866 this.refresh();
11867 if ( this.tabs.length === 1 && options.active === false ) {
11868 this.option( "active", 0 );
11869 }
11870
11871 this._trigger( "add", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
11872 return this;
11873 },
11874
11875 remove: function( index ) {
11876 index = this._getIndex( index );
11877 var options = this.options,
11878 tab = this.tabs.eq( index ).remove(),
11879 panel = this._getPanelForTab( tab ).remove();
11880
11881 // If selected tab was removed focus tab to the right or
11882 // in case the last tab was removed the tab to the left.
11883 // We check for more than 2 tabs, because if there are only 2,
11884 // then when we remove this tab, there will only be one tab left
11885 // so we don't need to detect which tab to activate.
11886 if ( tab.hasClass( "ui-tabs-active" ) && this.anchors.length > 2 ) {
11887 this._activate( index + ( index + 1 < this.anchors.length ? 1 : -1 ) );
11888 }
11889
11890 options.disabled = $.map(
11891 $.grep( options.disabled, function( n ) {
11892 return n !== index;
11893 }),
11894 function( n ) {
11895 return n >= index ? --n : n;
11896 });
11897
11898 this.refresh();
11899
11900 this._trigger( "remove", null, this._ui( tab.find( "a" )[ 0 ], panel[ 0 ] ) );
11901 return this;
11902 }
11903 });
11904
11905 // length method
11906 $.widget( "ui.tabs", $.ui.tabs, {
11907 length: function() {
11908 return this.anchors.length;
11909 }
11910 });
11911
11912 // panel ids (idPrefix option + title attribute)
11913 $.widget( "ui.tabs", $.ui.tabs, {
11914 options: {
11915 idPrefix: "ui-tabs-"
11916 },
11917
11918 _tabId: function( tab ) {
11919 var a = tab.is( "li" ) ? tab.find( "a[href]" ) : tab;
11920 a = a[0];
11921 return $( a ).closest( "li" ).attr( "aria-controls" ) ||
11922 a.title && a.title.replace( /\s/g, "_" ).replace( /[^\w\u00c0-\uFFFF\-]/g, "" ) ||
11923 this.options.idPrefix + getNextTabId();
11924 }
11925 });
11926
11927 // _createPanel method
11928 $.widget( "ui.tabs", $.ui.tabs, {
11929 options: {
11930 panelTemplate: "<div></div>"
11931 },
11932
11933 _createPanel: function( id ) {
11934 return $( this.options.panelTemplate )
11935 .attr( "id", id )
11936 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
11937 .data( "ui-tabs-destroy", true );
11938 }
11939 });
11940
11941 // selected option
11942 $.widget( "ui.tabs", $.ui.tabs, {
11943 _create: function() {
11944 var options = this.options;
11945 if ( options.active === null && options.selected !== undefined ) {
11946 options.active = options.selected === -1 ? false : options.selected;
11947 }
11948 this._super();
11949 options.selected = options.active;
11950 if ( options.selected === false ) {
11951 options.selected = -1;
11952 }
11953 },
11954
11955 _setOption: function( key, value ) {
11956 if ( key !== "selected" ) {
11957 return this._super( key, value );
11958 }
11959
11960 var options = this.options;
11961 this._super( "active", value === -1 ? false : value );
11962 options.selected = options.active;
11963 if ( options.selected === false ) {
11964 options.selected = -1;
11965 }
11966 },
11967
11968 _eventHandler: function( event ) {
11969 this._superApply( arguments );
11970 this.options.selected = this.options.active;
11971 if ( this.options.selected === false ) {
11972 this.options.selected = -1;
11973 }
11974 }
11975 });
11976
11977 // show and select event
11978 $.widget( "ui.tabs", $.ui.tabs, {
11979 options: {
11980 show: null,
11981 select: null
11982 },
11983 _create: function() {
11984 this._super();
11985 if ( this.options.active !== false ) {
11986 this._trigger( "show", null, this._ui(
11987 this.active.find( ".ui-tabs-anchor" )[ 0 ],
11988 this._getPanelForTab( this.active )[ 0 ] ) );
11989 }
11990 },
11991 _trigger: function( type, event, data ) {
11992 var ret = this._superApply( arguments );
11993 if ( !ret ) {
11994 return false;
11995 }
11996 if ( type === "beforeActivate" && data.newTab.length ) {
11997 ret = this._super( "select", event, {
11998 tab: data.newTab.find( ".ui-tabs-anchor" )[ 0],
11999 panel: data.newPanel[ 0 ],
12000 index: data.newTab.closest( "li" ).index()
12001 });
12002 } else if ( type === "activate" && data.newTab.length ) {
12003 ret = this._super( "show", event, {
12004 tab: data.newTab.find( ".ui-tabs-anchor" )[ 0 ],
12005 panel: data.newPanel[ 0 ],
12006 index: data.newTab.closest( "li" ).index()
12007 });
12008 }
12009 return ret;
12010 }
12011 });
12012
12013 // select method
12014 $.widget( "ui.tabs", $.ui.tabs, {
12015 select: function( index ) {
12016 index = this._getIndex( index );
12017 if ( index === -1 ) {
12018 if ( this.options.collapsible && this.options.selected !== -1 ) {
12019 index = this.options.selected;
12020 } else {
12021 return;
12022 }
12023 }
12024 this.anchors.eq( index ).trigger( this.options.event + this.eventNamespace );
12025 }
12026 });
12027
12028 // cookie option
12029 (function() {
12030
12031 var listId = 0;
12032
12033 $.widget( "ui.tabs", $.ui.tabs, {
12034 options: {
12035 cookie: null // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
12036 },
12037 _create: function() {
12038 var options = this.options,
12039 active;
12040 if ( options.active == null && options.cookie ) {
12041 active = parseInt( this._cookie(), 10 );
12042 if ( active === -1 ) {
12043 active = false;
12044 }
12045 options.active = active;
12046 }
12047 this._super();
12048 },
12049 _cookie: function( active ) {
12050 var cookie = [ this.cookie ||
12051 ( this.cookie = this.options.cookie.name || "ui-tabs-" + (++listId) ) ];
12052 if ( arguments.length ) {
12053 cookie.push( active === false ? -1 : active );
12054 cookie.push( this.options.cookie );
12055 }
12056 return $.cookie.apply( null, cookie );
12057 },
12058 _refresh: function() {
12059 this._super();
12060 if ( this.options.cookie ) {
12061 this._cookie( this.options.active, this.options.cookie );
12062 }
12063 },
12064 _eventHandler: function( event ) {
12065 this._superApply( arguments );
12066 if ( this.options.cookie ) {
12067 this._cookie( this.options.active, this.options.cookie );
12068 }
12069 },
12070 _destroy: function() {
12071 this._super();
12072 if ( this.options.cookie ) {
12073 this._cookie( null, this.options.cookie );
12074 }
12075 }
12076 });
12077
12078 })();
12079
12080 // load event
12081 $.widget( "ui.tabs", $.ui.tabs, {
12082 _trigger: function( type, event, data ) {
12083 var _data = $.extend( {}, data );
12084 if ( type === "load" ) {
12085 _data.panel = _data.panel[ 0 ];
12086 _data.tab = _data.tab.find( ".ui-tabs-anchor" )[ 0 ];
12087 }
12088 return this._super( type, event, _data );
12089 }
12090 });
12091
12092 // fx option
12093 // The new animation options (show, hide) conflict with the old show callback.
12094 // The old fx option wins over show/hide anyway (always favor back-compat).
12095 // If a user wants to use the new animation API, they must give up the old API.
12096 $.widget( "ui.tabs", $.ui.tabs, {
12097 options: {
12098 fx: null // e.g. { height: "toggle", opacity: "toggle", duration: 200 }
12099 },
12100
12101 _getFx: function() {
12102 var hide, show,
12103 fx = this.options.fx;
12104
12105 if ( fx ) {
12106 if ( $.isArray( fx ) ) {
12107 hide = fx[ 0 ];
12108 show = fx[ 1 ];
12109 } else {
12110 hide = show = fx;
12111 }
12112 }
12113
12114 return fx ? { show: show, hide: hide } : null;
12115 },
12116
12117 _toggle: function( event, eventData ) {
12118 var that = this,
12119 toShow = eventData.newPanel,
12120 toHide = eventData.oldPanel,
12121 fx = this._getFx();
12122
12123 if ( !fx ) {
12124 return this._super( event, eventData );
12125 }
12126
12127 that.running = true;
12128
12129 function complete() {
12130 that.running = false;
12131 that._trigger( "activate", event, eventData );
12132 }
12133
12134 function show() {
12135 eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
12136
12137 if ( toShow.length && fx.show ) {
12138 toShow
12139 .animate( fx.show, fx.show.duration, function() {
12140 complete();
12141 });
12142 } else {
12143 toShow.show();
12144 complete();
12145 }
12146 }
12147
12148 // start out by hiding, then showing, then completing
12149 if ( toHide.length && fx.hide ) {
12150 toHide.animate( fx.hide, fx.hide.duration, function() {
12151 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
12152 show();
12153 });
12154 } else {
12155 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
12156 toHide.hide();
12157 show();
12158 }
12159 }
12160 });
12161 }
12162
12163 })( jQuery );
12164 (function( $ ) {
12165
12166 var increments = 0;
12167
12168 function addDescribedBy( elem, id ) {
12169 var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ );
12170 describedby.push( id );
12171 elem
12172 .data( "ui-tooltip-id", id )
12173 .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
12174 }
12175
12176 function removeDescribedBy( elem ) {
12177 var id = elem.data( "ui-tooltip-id" ),
12178 describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ),
12179 index = $.inArray( id, describedby );
12180 if ( index !== -1 ) {
12181 describedby.splice( index, 1 );
12182 }
12183
12184 elem.removeData( "ui-tooltip-id" );
12185 describedby = $.trim( describedby.join( " " ) );
12186 if ( describedby ) {
12187 elem.attr( "aria-describedby", describedby );
12188 } else {
12189 elem.removeAttr( "aria-describedby" );
12190 }
12191 }
12192
12193 $.widget( "ui.tooltip", {
12194 version: "1.9.0",
12195 options: {
12196 content: function() {
12197 return $( this ).attr( "title" );
12198 },
12199 hide: true,
12200 items: "[title]",
12201 position: {
12202 my: "left+15 center",
12203 at: "right center",
12204 collision: "flipfit flipfit"
12205 },
12206 show: true,
12207 tooltipClass: null,
12208 track: false,
12209
12210 // callbacks
12211 close: null,
12212 open: null
12213 },
12214
12215 _create: function() {
12216 this._on({
12217 mouseover: "open",
12218 focusin: "open"
12219 });
12220
12221 // IDs of generated tooltips, needed for destroy
12222 this.tooltips = {};
12223 },
12224
12225 _setOption: function( key, value ) {
12226 var that = this;
12227
12228 if ( key === "disabled" ) {
12229 this[ value ? "_disable" : "_enable" ]();
12230 this.options[ key ] = value;
12231 // disable element style changes
12232 return;
12233 }
12234
12235 this._super( key, value );
12236
12237 if ( key === "content" ) {
12238 $.each( this.tooltips, function( id, element ) {
12239 that._updateContent( element );
12240 });
12241 }
12242 },
12243
12244 _disable: function() {
12245 var that = this;
12246
12247 // close open tooltips
12248 $.each( this.tooltips, function( id, element ) {
12249 var event = $.Event( "blur" );
12250 event.target = event.currentTarget = element[0];
12251 that.close( event, true );
12252 });
12253
12254 // remove title attributes to prevent native tooltips
12255 this.element.find( this.options.items ).andSelf().each(function() {
12256 var element = $( this );
12257 if ( element.is( "[title]" ) ) {
12258 element
12259 .data( "ui-tooltip-title", element.attr( "title" ) )
12260 .attr( "title", "" );
12261 }
12262 });
12263 },
12264
12265 _enable: function() {
12266 // restore title attributes
12267 this.element.find( this.options.items ).andSelf().each(function() {
12268 var element = $( this );
12269 if ( element.data( "ui-tooltip-title" ) ) {
12270 element.attr( "title", element.data( "ui-tooltip-title" ) );
12271 }
12272 });
12273 },
12274
12275 open: function( event ) {
12276 var target = $( event ? event.target : this.element )
12277 .closest( this.options.items );
12278
12279 // No element to show a tooltip for
12280 if ( !target.length ) {
12281 return;
12282 }
12283
12284 // If the tooltip is open and we're tracking then reposition the tooltip.
12285 // This makes sure that a tracking tooltip doesn't obscure a focused element
12286 // if the user was hovering when the element gained focused.
12287 if ( this.options.track && target.data( "ui-tooltip-id" ) ) {
12288 this._find( target ).position( $.extend({
12289 of: target
12290 }, this.options.position ) );
12291 // Stop tracking (#8622)
12292 this._off( this.document, "mousemove" );
12293 return;
12294 }
12295
12296 if ( target.attr( "title" ) ) {
12297 target.data( "ui-tooltip-title", target.attr( "title" ) );
12298 }
12299
12300 target.data( "tooltip-open", true );
12301
12302 this._updateContent( target, event );
12303 },
12304
12305 _updateContent: function( target, event ) {
12306 var content,
12307 contentOption = this.options.content,
12308 that = this;
12309
12310 if ( typeof contentOption === "string" ) {
12311 return this._open( event, target, contentOption );
12312 }
12313
12314 content = contentOption.call( target[0], function( response ) {
12315 // ignore async response if tooltip was closed already
12316 if ( !target.data( "tooltip-open" ) ) {
12317 return;
12318 }
12319 // IE may instantly serve a cached response for ajax requests
12320 // delay this call to _open so the other call to _open runs first
12321 that._delay(function() {
12322 this._open( event, target, response );
12323 });
12324 });
12325 if ( content ) {
12326 this._open( event, target, content );
12327 }
12328 },
12329
12330 _open: function( event, target, content ) {
12331 var tooltip, positionOption;
12332 if ( !content ) {
12333 return;
12334 }
12335
12336 // Content can be updated multiple times. If the tooltip already
12337 // exists, then just update the content and bail.
12338 tooltip = this._find( target );
12339 if ( tooltip.length ) {
12340 tooltip.find( ".ui-tooltip-content" ).html( content );
12341 return;
12342 }
12343
12344 // if we have a title, clear it to prevent the native tooltip
12345 // we have to check first to avoid defining a title if none exists
12346 // (we don't want to cause an element to start matching [title])
12347 //
12348 // We use removeAttr only for key events, to allow IE to export the correct
12349 // accessible attributes. For mouse events, set to empty string to avoid
12350 // native tooltip showing up (happens only when removing inside mouseover).
12351 if ( target.is( "[title]" ) ) {
12352 if ( event && event.type === "mouseover" ) {
12353 target.attr( "title", "" );
12354 } else {
12355 target.removeAttr( "title" );
12356 }
12357 }
12358
12359 tooltip = this._tooltip( target );
12360 addDescribedBy( target, tooltip.attr( "id" ) );
12361 tooltip.find( ".ui-tooltip-content" ).html( content );
12362
12363 function position( event ) {
12364 positionOption.of = event;
12365 tooltip.position( positionOption );
12366 }
12367 if ( this.options.track && event && /^mouse/.test( event.originalEvent.type ) ) {
12368 positionOption = $.extend( {}, this.options.position );
12369 this._on( this.document, {
12370 mousemove: position
12371 });
12372 // trigger once to override element-relative positioning
12373 position( event );
12374 } else {
12375 tooltip.position( $.extend({
12376 of: target
12377 }, this.options.position ) );
12378 }
12379
12380 tooltip.hide();
12381
12382 this._show( tooltip, this.options.show );
12383
12384 this._trigger( "open", event, { tooltip: tooltip } );
12385
12386 this._on( target, {
12387 mouseleave: "close",
12388 focusout: "close",
12389 keyup: function( event ) {
12390 if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
12391 var fakeEvent = $.Event(event);
12392 fakeEvent.currentTarget = target[0];
12393 this.close( fakeEvent, true );
12394 }
12395 }
12396 });
12397 },
12398
12399 close: function( event, force ) {
12400 var that = this,
12401 target = $( event ? event.currentTarget : this.element ),
12402 tooltip = this._find( target );
12403
12404 // disabling closes the tooltip, so we need to track when we're closing
12405 // to avoid an infinite loop in case the tooltip becomes disabled on close
12406 if ( this.closing ) {
12407 return;
12408 }
12409
12410 // don't close if the element has focus
12411 // this prevents the tooltip from closing if you hover while focused
12412 //
12413 // we have to check the event type because tabbing out of the document
12414 // may leave the element as the activeElement
12415 if ( !force && event && event.type !== "focusout" &&
12416 this.document[0].activeElement === target[0] ) {
12417 return;
12418 }
12419
12420 // only set title if we had one before (see comment in _open())
12421 if ( target.data( "ui-tooltip-title" ) ) {
12422 target.attr( "title", target.data( "ui-tooltip-title" ) );
12423 }
12424
12425 removeDescribedBy( target );
12426
12427 tooltip.stop( true );
12428 this._hide( tooltip, this.options.hide, function() {
12429 $( this ).remove();
12430 delete that.tooltips[ this.id ];
12431 });
12432
12433 target.removeData( "tooltip-open" );
12434 this._off( target, "mouseleave focusout keyup" );
12435 this._off( this.document, "mousemove" );
12436
12437 this.closing = true;
12438 this._trigger( "close", event, { tooltip: tooltip } );
12439 this.closing = false;
12440 },
12441
12442 _tooltip: function( element ) {
12443 var id = "ui-tooltip-" + increments++,
12444 tooltip = $( "<div>" )
12445 .attr({
12446 id: id,
12447 role: "tooltip"
12448 })
12449 .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " +
12450 ( this.options.tooltipClass || "" ) );
12451 $( "<div>" )
12452 .addClass( "ui-tooltip-content" )
12453 .appendTo( tooltip );
12454 tooltip.appendTo( this.document[0].body );
12455 if ( $.fn.bgiframe ) {
12456 tooltip.bgiframe();
12457 }
12458 this.tooltips[ id ] = element;
12459 return tooltip;
12460 },
12461
12462 _find: function( target ) {
12463 var id = target.data( "ui-tooltip-id" );
12464 return id ? $( "#" + id ) : $();
12465 },
12466
12467 _destroy: function() {
12468 var that = this;
12469
12470 // close open tooltips
12471 $.each( this.tooltips, function( id, element ) {
12472 // Delegate to close method to handle common cleanup
12473 var event = $.Event( "blur" );
12474 event.target = event.currentTarget = element[0];
12475 that.close( event, true );
12476
12477 // Remove immediately; destroying an open tooltip doesn't use the
12478 // hide animation
12479 $( "#" + id ).remove();
12480
12481 // Restore the title
12482 if ( element.data( "ui-tooltip-title" ) ) {
12483 element.attr( "title", element.data( "ui-tooltip-title" ) );
12484 element.removeData( "ui-tooltip-title" );
12485 }
12486 });
12487 }
12488 });
12489
12490 }( jQuery ) );
12491 ;(jQuery.effects || (function($, undefined) {
12492
12493 var backCompat = $.uiBackCompat !== false,
12494 // prefix used for storing data on .data()
12495 dataSpace = "ui-effects-";
12496
12497 $.effects = {
12498 effect: {}
12499 };
12500
12501 /*!
12502 * jQuery Color Animations v2.0.0
12503 * http://jquery.com/
12504 *
12505 * Copyright 2012 jQuery Foundation and other contributors
12506 * Released under the MIT license.
12507 * http://jquery.org/license
12508 *
12509 * Date: Mon Aug 13 13:41:02 2012 -0500
12510 */
12511 (function( jQuery, undefined ) {
12512
12513 var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor".split(" "),
12514
12515 // plusequals test for += 100 -= 100
12516 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
12517 // a set of RE's that can match strings and generate color tuples.
12518 stringParsers = [{
12519 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,
12520 parse: function( execResult ) {
12521 return [
12522 execResult[ 1 ],
12523 execResult[ 2 ],
12524 execResult[ 3 ],
12525 execResult[ 4 ]
12526 ];
12527 }
12528 }, {
12529 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,
12530 parse: function( execResult ) {
12531 return [
12532 execResult[ 1 ] * 2.55,
12533 execResult[ 2 ] * 2.55,
12534 execResult[ 3 ] * 2.55,
12535 execResult[ 4 ]
12536 ];
12537 }
12538 }, {
12539 // this regex ignores A-F because it's compared against an already lowercased string
12540 re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
12541 parse: function( execResult ) {
12542 return [
12543 parseInt( execResult[ 1 ], 16 ),
12544 parseInt( execResult[ 2 ], 16 ),
12545 parseInt( execResult[ 3 ], 16 )
12546 ];
12547 }
12548 }, {
12549 // this regex ignores A-F because it's compared against an already lowercased string
12550 re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
12551 parse: function( execResult ) {
12552 return [
12553 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
12554 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
12555 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
12556 ];
12557 }
12558 }, {
12559 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,
12560 space: "hsla",
12561 parse: function( execResult ) {
12562 return [
12563 execResult[ 1 ],
12564 execResult[ 2 ] / 100,
12565 execResult[ 3 ] / 100,
12566 execResult[ 4 ]
12567 ];
12568 }
12569 }],
12570
12571 // jQuery.Color( )
12572 color = jQuery.Color = function( color, green, blue, alpha ) {
12573 return new jQuery.Color.fn.parse( color, green, blue, alpha );
12574 },
12575 spaces = {
12576 rgba: {
12577 props: {
12578 red: {
12579 idx: 0,
12580 type: "byte"
12581 },
12582 green: {
12583 idx: 1,
12584 type: "byte"
12585 },
12586 blue: {
12587 idx: 2,
12588 type: "byte"
12589 }
12590 }
12591 },
12592
12593 hsla: {
12594 props: {
12595 hue: {
12596 idx: 0,
12597 type: "degrees"
12598 },
12599 saturation: {
12600 idx: 1,
12601 type: "percent"
12602 },
12603 lightness: {
12604 idx: 2,
12605 type: "percent"
12606 }
12607 }
12608 }
12609 },
12610 propTypes = {
12611 "byte": {
12612 floor: true,
12613 max: 255
12614 },
12615 "percent": {
12616 max: 1
12617 },
12618 "degrees": {
12619 mod: 360,
12620 floor: true
12621 }
12622 },
12623 support = color.support = {},
12624
12625 // element for support tests
12626 supportElem = jQuery( "<p>" )[ 0 ],
12627
12628 // colors = jQuery.Color.names
12629 colors,
12630
12631 // local aliases of functions called often
12632 each = jQuery.each;
12633
12634 // determine rgba support immediately
12635 supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
12636 support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
12637
12638 // define cache name and alpha properties
12639 // for rgba and hsla spaces
12640 each( spaces, function( spaceName, space ) {
12641 space.cache = "_" + spaceName;
12642 space.props.alpha = {
12643 idx: 3,
12644 type: "percent",
12645 def: 1
12646 };
12647 });
12648
12649 function clamp( value, prop, allowEmpty ) {
12650 var type = propTypes[ prop.type ] || {};
12651
12652 if ( value == null ) {
12653 return (allowEmpty || !prop.def) ? null : prop.def;
12654 }
12655
12656 // ~~ is an short way of doing floor for positive numbers
12657 value = type.floor ? ~~value : parseFloat( value );
12658
12659 // IE will pass in empty strings as value for alpha,
12660 // which will hit this case
12661 if ( isNaN( value ) ) {
12662 return prop.def;
12663 }
12664
12665 if ( type.mod ) {
12666 // we add mod before modding to make sure that negatives values
12667 // get converted properly: -10 -> 350
12668 return (value + type.mod) % type.mod;
12669 }
12670
12671 // for now all property types without mod have min and max
12672 return 0 > value ? 0 : type.max < value ? type.max : value;
12673 }
12674
12675 function stringParse( string ) {
12676 var inst = color(),
12677 rgba = inst._rgba = [];
12678
12679 string = string.toLowerCase();
12680
12681 each( stringParsers, function( i, parser ) {
12682 var parsed,
12683 match = parser.re.exec( string ),
12684 values = match && parser.parse( match ),
12685 spaceName = parser.space || "rgba";
12686
12687 if ( values ) {
12688 parsed = inst[ spaceName ]( values );
12689
12690 // if this was an rgba parse the assignment might happen twice
12691 // oh well....
12692 inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
12693 rgba = inst._rgba = parsed._rgba;
12694
12695 // exit each( stringParsers ) here because we matched
12696 return false;
12697 }
12698 });
12699
12700 // Found a stringParser that handled it
12701 if ( rgba.length ) {
12702
12703 // if this came from a parsed string, force "transparent" when alpha is 0
12704 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
12705 if ( rgba.join() === "0,0,0,0" ) {
12706 jQuery.extend( rgba, colors.transparent );
12707 }
12708 return inst;
12709 }
12710
12711 // named colors
12712 return colors[ string ];
12713 }
12714
12715 color.fn = jQuery.extend( color.prototype, {
12716 parse: function( red, green, blue, alpha ) {
12717 if ( red === undefined ) {
12718 this._rgba = [ null, null, null, null ];
12719 return this;
12720 }
12721 if ( red.jquery || red.nodeType ) {
12722 red = jQuery( red ).css( green );
12723 green = undefined;
12724 }
12725
12726 var inst = this,
12727 type = jQuery.type( red ),
12728 rgba = this._rgba = [],
12729 source;
12730
12731 // more than 1 argument specified - assume ( red, green, blue, alpha )
12732 if ( green !== undefined ) {
12733 red = [ red, green, blue, alpha ];
12734 type = "array";
12735 }
12736
12737 if ( type === "string" ) {
12738 return this.parse( stringParse( red ) || colors._default );
12739 }
12740
12741 if ( type === "array" ) {
12742 each( spaces.rgba.props, function( key, prop ) {
12743 rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
12744 });
12745 return this;
12746 }
12747
12748 if ( type === "object" ) {
12749 if ( red instanceof color ) {
12750 each( spaces, function( spaceName, space ) {
12751 if ( red[ space.cache ] ) {
12752 inst[ space.cache ] = red[ space.cache ].slice();
12753 }
12754 });
12755 } else {
12756 each( spaces, function( spaceName, space ) {
12757 var cache = space.cache;
12758 each( space.props, function( key, prop ) {
12759
12760 // if the cache doesn't exist, and we know how to convert
12761 if ( !inst[ cache ] && space.to ) {
12762
12763 // if the value was null, we don't need to copy it
12764 // if the key was alpha, we don't need to copy it either
12765 if ( key === "alpha" || red[ key ] == null ) {
12766 return;
12767 }
12768 inst[ cache ] = space.to( inst._rgba );
12769 }
12770
12771 // this is the only case where we allow nulls for ALL properties.
12772 // call clamp with alwaysAllowEmpty
12773 inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
12774 });
12775
12776 // everything defined but alpha?
12777 if ( inst[ cache ] && $.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
12778 // use the default of 1
12779 inst[ cache ][ 3 ] = 1;
12780 if ( space.from ) {
12781 inst._rgba = space.from( inst[ cache ] );
12782 }
12783 }
12784 });
12785 }
12786 return this;
12787 }
12788 },
12789 is: function( compare ) {
12790 var is = color( compare ),
12791 same = true,
12792 inst = this;
12793
12794 each( spaces, function( _, space ) {
12795 var localCache,
12796 isCache = is[ space.cache ];
12797 if (isCache) {
12798 localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
12799 each( space.props, function( _, prop ) {
12800 if ( isCache[ prop.idx ] != null ) {
12801 same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
12802 return same;
12803 }
12804 });
12805 }
12806 return same;
12807 });
12808 return same;
12809 },
12810 _space: function() {
12811 var used = [],
12812 inst = this;
12813 each( spaces, function( spaceName, space ) {
12814 if ( inst[ space.cache ] ) {
12815 used.push( spaceName );
12816 }
12817 });
12818 return used.pop();
12819 },
12820 transition: function( other, distance ) {
12821 var end = color( other ),
12822 spaceName = end._space(),
12823 space = spaces[ spaceName ],
12824 startColor = this.alpha() === 0 ? color( "transparent" ) : this,
12825 start = startColor[ space.cache ] || space.to( startColor._rgba ),
12826 result = start.slice();
12827
12828 end = end[ space.cache ];
12829 each( space.props, function( key, prop ) {
12830 var index = prop.idx,
12831 startValue = start[ index ],
12832 endValue = end[ index ],
12833 type = propTypes[ prop.type ] || {};
12834
12835 // if null, don't override start value
12836 if ( endValue === null ) {
12837 return;
12838 }
12839 // if null - use end
12840 if ( startValue === null ) {
12841 result[ index ] = endValue;
12842 } else {
12843 if ( type.mod ) {
12844 if ( endValue - startValue > type.mod / 2 ) {
12845 startValue += type.mod;
12846 } else if ( startValue - endValue > type.mod / 2 ) {
12847 startValue -= type.mod;
12848 }
12849 }
12850 result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
12851 }
12852 });
12853 return this[ spaceName ]( result );
12854 },
12855 blend: function( opaque ) {
12856 // if we are already opaque - return ourself
12857 if ( this._rgba[ 3 ] === 1 ) {
12858 return this;
12859 }
12860
12861 var rgb = this._rgba.slice(),
12862 a = rgb.pop(),
12863 blend = color( opaque )._rgba;
12864
12865 return color( jQuery.map( rgb, function( v, i ) {
12866 return ( 1 - a ) * blend[ i ] + a * v;
12867 }));
12868 },
12869 toRgbaString: function() {
12870 var prefix = "rgba(",
12871 rgba = jQuery.map( this._rgba, function( v, i ) {
12872 return v == null ? ( i > 2 ? 1 : 0 ) : v;
12873 });
12874
12875 if ( rgba[ 3 ] === 1 ) {
12876 rgba.pop();
12877 prefix = "rgb(";
12878 }
12879
12880 return prefix + rgba.join() + ")";
12881 },
12882 toHslaString: function() {
12883 var prefix = "hsla(",
12884 hsla = jQuery.map( this.hsla(), function( v, i ) {
12885 if ( v == null ) {
12886 v = i > 2 ? 1 : 0;
12887 }
12888
12889 // catch 1 and 2
12890 if ( i && i < 3 ) {
12891 v = Math.round( v * 100 ) + "%";
12892 }
12893 return v;
12894 });
12895
12896 if ( hsla[ 3 ] === 1 ) {
12897 hsla.pop();
12898 prefix = "hsl(";
12899 }
12900 return prefix + hsla.join() + ")";
12901 },
12902 toHexString: function( includeAlpha ) {
12903 var rgba = this._rgba.slice(),
12904 alpha = rgba.pop();
12905
12906 if ( includeAlpha ) {
12907 rgba.push( ~~( alpha * 255 ) );
12908 }
12909
12910 return "#" + jQuery.map( rgba, function( v, i ) {
12911
12912 // default to 0 when nulls exist
12913 v = ( v || 0 ).toString( 16 );
12914 return v.length === 1 ? "0" + v : v;
12915 }).join("");
12916 },
12917 toString: function() {
12918 return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
12919 }
12920 });
12921 color.fn.parse.prototype = color.fn;
12922
12923 // hsla conversions adapted from:
12924 // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
12925
12926 function hue2rgb( p, q, h ) {
12927 h = ( h + 1 ) % 1;
12928 if ( h * 6 < 1 ) {
12929 return p + (q - p) * h * 6;
12930 }
12931 if ( h * 2 < 1) {
12932 return q;
12933 }
12934 if ( h * 3 < 2 ) {
12935 return p + (q - p) * ((2/3) - h) * 6;
12936 }
12937 return p;
12938 }
12939
12940 spaces.hsla.to = function ( rgba ) {
12941 if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
12942 return [ null, null, null, rgba[ 3 ] ];
12943 }
12944 var r = rgba[ 0 ] / 255,
12945 g = rgba[ 1 ] / 255,
12946 b = rgba[ 2 ] / 255,
12947 a = rgba[ 3 ],
12948 max = Math.max( r, g, b ),
12949 min = Math.min( r, g, b ),
12950 diff = max - min,
12951 add = max + min,
12952 l = add * 0.5,
12953 h, s;
12954
12955 if ( min === max ) {
12956 h = 0;
12957 } else if ( r === max ) {
12958 h = ( 60 * ( g - b ) / diff ) + 360;
12959 } else if ( g === max ) {
12960 h = ( 60 * ( b - r ) / diff ) + 120;
12961 } else {
12962 h = ( 60 * ( r - g ) / diff ) + 240;
12963 }
12964
12965 if ( l === 0 || l === 1 ) {
12966 s = l;
12967 } else if ( l <= 0.5 ) {
12968 s = diff / add;
12969 } else {
12970 s = diff / ( 2 - add );
12971 }
12972 return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
12973 };
12974
12975 spaces.hsla.from = function ( hsla ) {
12976 if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
12977 return [ null, null, null, hsla[ 3 ] ];
12978 }
12979 var h = hsla[ 0 ] / 360,
12980 s = hsla[ 1 ],
12981 l = hsla[ 2 ],
12982 a = hsla[ 3 ],
12983 q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
12984 p = 2 * l - q,
12985 r, g, b;
12986
12987 return [
12988 Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
12989 Math.round( hue2rgb( p, q, h ) * 255 ),
12990 Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
12991 a
12992 ];
12993 };
12994
12995
12996 each( spaces, function( spaceName, space ) {
12997 var props = space.props,
12998 cache = space.cache,
12999 to = space.to,
13000 from = space.from;
13001
13002 // makes rgba() and hsla()
13003 color.fn[ spaceName ] = function( value ) {
13004
13005 // generate a cache for this space if it doesn't exist
13006 if ( to && !this[ cache ] ) {
13007 this[ cache ] = to( this._rgba );
13008 }
13009 if ( value === undefined ) {
13010 return this[ cache ].slice();
13011 }
13012
13013 var ret,
13014 type = jQuery.type( value ),
13015 arr = ( type === "array" || type === "object" ) ? value : arguments,
13016 local = this[ cache ].slice();
13017
13018 each( props, function( key, prop ) {
13019 var val = arr[ type === "object" ? key : prop.idx ];
13020 if ( val == null ) {
13021 val = local[ prop.idx ];
13022 }
13023 local[ prop.idx ] = clamp( val, prop );
13024 });
13025
13026 if ( from ) {
13027 ret = color( from( local ) );
13028 ret[ cache ] = local;
13029 return ret;
13030 } else {
13031 return color( local );
13032 }
13033 };
13034
13035 // makes red() green() blue() alpha() hue() saturation() lightness()
13036 each( props, function( key, prop ) {
13037 // alpha is included in more than one space
13038 if ( color.fn[ key ] ) {
13039 return;
13040 }
13041 color.fn[ key ] = function( value ) {
13042 var vtype = jQuery.type( value ),
13043 fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
13044 local = this[ fn ](),
13045 cur = local[ prop.idx ],
13046 match;
13047
13048 if ( vtype === "undefined" ) {
13049 return cur;
13050 }
13051
13052 if ( vtype === "function" ) {
13053 value = value.call( this, cur );
13054 vtype = jQuery.type( value );
13055 }
13056 if ( value == null && prop.empty ) {
13057 return this;
13058 }
13059 if ( vtype === "string" ) {
13060 match = rplusequals.exec( value );
13061 if ( match ) {
13062 value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
13063 }
13064 }
13065 local[ prop.idx ] = value;
13066 return this[ fn ]( local );
13067 };
13068 });
13069 });
13070
13071 // add .fx.step functions
13072 each( stepHooks, function( i, hook ) {
13073 jQuery.cssHooks[ hook ] = {
13074 set: function( elem, value ) {
13075 var parsed, curElem,
13076 backgroundColor = "";
13077
13078 if ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) {
13079 value = color( parsed || value );
13080 if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
13081 curElem = hook === "backgroundColor" ? elem.parentNode : elem;
13082 while (
13083 (backgroundColor === "" || backgroundColor === "transparent") &&
13084 curElem && curElem.style
13085 ) {
13086 try {
13087 backgroundColor = jQuery.css( curElem, "backgroundColor" );
13088 curElem = curElem.parentNode;
13089 } catch ( e ) {
13090 }
13091 }
13092
13093 value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
13094 backgroundColor :
13095 "_default" );
13096 }
13097
13098 value = value.toRgbaString();
13099 }
13100 try {
13101 elem.style[ hook ] = value;
13102 } catch( value ) {
13103 // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
13104 }
13105 }
13106 };
13107 jQuery.fx.step[ hook ] = function( fx ) {
13108 if ( !fx.colorInit ) {
13109 fx.start = color( fx.elem, hook );
13110 fx.end = color( fx.end );
13111 fx.colorInit = true;
13112 }
13113 jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
13114 };
13115 });
13116
13117 jQuery.cssHooks.borderColor = {
13118 expand: function( value ) {
13119 var expanded = {};
13120
13121 each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
13122 expanded[ "border" + part + "Color" ] = value;
13123 });
13124 return expanded;
13125 }
13126 };
13127
13128 // Basic color names only.
13129 // Usage of any of the other color names requires adding yourself or including
13130 // jquery.color.svg-names.js.
13131 colors = jQuery.Color.names = {
13132 // 4.1. Basic color keywords
13133 aqua: "#00ffff",
13134 black: "#000000",
13135 blue: "#0000ff",
13136 fuchsia: "#ff00ff",
13137 gray: "#808080",
13138 green: "#008000",
13139 lime: "#00ff00",
13140 maroon: "#800000",
13141 navy: "#000080",
13142 olive: "#808000",
13143 purple: "#800080",
13144 red: "#ff0000",
13145 silver: "#c0c0c0",
13146 teal: "#008080",
13147 white: "#ffffff",
13148 yellow: "#ffff00",
13149
13150 // 4.2.3. "transparent" color keyword
13151 transparent: [ null, null, null, 0 ],
13152
13153 _default: "#ffffff"
13154 };
13155
13156 })( jQuery );
13157
13158
13159
13160 /******************************************************************************/
13161 /****************************** CLASS ANIMATIONS ******************************/
13162 /******************************************************************************/
13163 (function() {
13164
13165 var classAnimationActions = [ "add", "remove", "toggle" ],
13166 shorthandStyles = {
13167 border: 1,
13168 borderBottom: 1,
13169 borderColor: 1,
13170 borderLeft: 1,
13171 borderRight: 1,
13172 borderTop: 1,
13173 borderWidth: 1,
13174 margin: 1,
13175 padding: 1
13176 };
13177
13178 $.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) {
13179 $.fx.step[ prop ] = function( fx ) {
13180 if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
13181 jQuery.style( fx.elem, prop, fx.end );
13182 fx.setAttr = true;
13183 }
13184 };
13185 });
13186
13187 function getElementStyles() {
13188 var style = this.ownerDocument.defaultView ?
13189 this.ownerDocument.defaultView.getComputedStyle( this, null ) :
13190 this.currentStyle,
13191 newStyle = {},
13192 key,
13193 camelCase,
13194 len;
13195
13196 // webkit enumerates style porperties
13197 if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
13198 len = style.length;
13199 while ( len-- ) {
13200 key = style[ len ];
13201 if ( typeof style[ key ] === "string" ) {
13202 newStyle[ $.camelCase( key ) ] = style[ key ];
13203 }
13204 }
13205 } else {
13206 for ( key in style ) {
13207 if ( typeof style[ key ] === "string" ) {
13208 newStyle[ key ] = style[ key ];
13209 }
13210 }
13211 }
13212
13213 return newStyle;
13214 }
13215
13216
13217 function styleDifference( oldStyle, newStyle ) {
13218 var diff = {},
13219 name, value;
13220
13221 for ( name in newStyle ) {
13222 value = newStyle[ name ];
13223 if ( oldStyle[ name ] !== value ) {
13224 if ( !shorthandStyles[ name ] ) {
13225 if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
13226 diff[ name ] = value;
13227 }
13228 }
13229 }
13230 }
13231
13232 return diff;
13233 }
13234
13235 $.effects.animateClass = function( value, duration, easing, callback ) {
13236 var o = $.speed( duration, easing, callback );
13237
13238 return this.queue( function() {
13239 var animated = $( this ),
13240 baseClass = animated.attr( "class" ) || "",
13241 applyClassChange,
13242 allAnimations = o.children ? animated.find( "*" ).andSelf() : animated;
13243
13244 // map the animated objects to store the original styles.
13245 allAnimations = allAnimations.map(function() {
13246 var el = $( this );
13247 return {
13248 el: el,
13249 start: getElementStyles.call( this )
13250 };
13251 });
13252
13253 // apply class change
13254 applyClassChange = function() {
13255 $.each( classAnimationActions, function(i, action) {
13256 if ( value[ action ] ) {
13257 animated[ action + "Class" ]( value[ action ] );
13258 }
13259 });
13260 };
13261 applyClassChange();
13262
13263 // map all animated objects again - calculate new styles and diff
13264 allAnimations = allAnimations.map(function() {
13265 this.end = getElementStyles.call( this.el[ 0 ] );
13266 this.diff = styleDifference( this.start, this.end );
13267 return this;
13268 });
13269
13270 // apply original class
13271 animated.attr( "class", baseClass );
13272
13273 // map all animated objects again - this time collecting a promise
13274 allAnimations = allAnimations.map(function() {
13275 var styleInfo = this,
13276 dfd = $.Deferred(),
13277 opts = jQuery.extend({}, o, {
13278 queue: false,
13279 complete: function() {
13280 dfd.resolve( styleInfo );
13281 }
13282 });
13283
13284 this.el.animate( this.diff, opts );
13285 return dfd.promise();
13286 });
13287
13288 // once all animations have completed:
13289 $.when.apply( $, allAnimations.get() ).done(function() {
13290
13291 // set the final class
13292 applyClassChange();
13293
13294 // for each animated element,
13295 // clear all css properties that were animated
13296 $.each( arguments, function() {
13297 var el = this.el;
13298 $.each( this.diff, function(key) {
13299 el.css( key, '' );
13300 });
13301 });
13302
13303 // this is guarnteed to be there if you use jQuery.speed()
13304 // it also handles dequeuing the next anim...
13305 o.complete.call( animated[ 0 ] );
13306 });
13307 });
13308 };
13309
13310 $.fn.extend({
13311 _addClass: $.fn.addClass,
13312 addClass: function( classNames, speed, easing, callback ) {
13313 return speed ?
13314 $.effects.animateClass.call( this,
13315 { add: classNames }, speed, easing, callback ) :
13316 this._addClass( classNames );
13317 },
13318
13319 _removeClass: $.fn.removeClass,
13320 removeClass: function( classNames, speed, easing, callback ) {
13321 return speed ?
13322 $.effects.animateClass.call( this,
13323 { remove: classNames }, speed, easing, callback ) :
13324 this._removeClass( classNames );
13325 },
13326
13327 _toggleClass: $.fn.toggleClass,
13328 toggleClass: function( classNames, force, speed, easing, callback ) {
13329 if ( typeof force === "boolean" || force === undefined ) {
13330 if ( !speed ) {
13331 // without speed parameter
13332 return this._toggleClass( classNames, force );
13333 } else {
13334 return $.effects.animateClass.call( this,
13335 (force ? { add: classNames } : { remove: classNames }),
13336 speed, easing, callback );
13337 }
13338 } else {
13339 // without force parameter
13340 return $.effects.animateClass.call( this,
13341 { toggle: classNames }, force, speed, easing );
13342 }
13343 },
13344
13345 switchClass: function( remove, add, speed, easing, callback) {
13346 return $.effects.animateClass.call( this, {
13347 add: add,
13348 remove: remove
13349 }, speed, easing, callback );
13350 }
13351 });
13352
13353 })();
13354
13355 /******************************************************************************/
13356 /*********************************** EFFECTS **********************************/
13357 /******************************************************************************/
13358
13359 (function() {
13360
13361 $.extend( $.effects, {
13362 version: "1.9.0",
13363
13364 // Saves a set of properties in a data storage
13365 save: function( element, set ) {
13366 for( var i=0; i < set.length; i++ ) {
13367 if ( set[ i ] !== null ) {
13368 element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
13369 }
13370 }
13371 },
13372
13373 // Restores a set of previously saved properties from a data storage
13374 restore: function( element, set ) {
13375 var val, i;
13376 for( i=0; i < set.length; i++ ) {
13377 if ( set[ i ] !== null ) {
13378 val = element.data( dataSpace + set[ i ] );
13379 // support: jQuery 1.6.2
13380 // http://bugs.jquery.com/ticket/9917
13381 // jQuery 1.6.2 incorrectly returns undefined for any falsy value.
13382 // We can't differentiate between "" and 0 here, so we just assume
13383 // empty string since it's likely to be a more common value...
13384 if ( val === undefined ) {
13385 val = "";
13386 }
13387 element.css( set[ i ], val );
13388 }
13389 }
13390 },
13391
13392 setMode: function( el, mode ) {
13393 if (mode === "toggle") {
13394 mode = el.is( ":hidden" ) ? "show" : "hide";
13395 }
13396 return mode;
13397 },
13398
13399 // Translates a [top,left] array into a baseline value
13400 // this should be a little more flexible in the future to handle a string & hash
13401 getBaseline: function( origin, original ) {
13402 var y, x;
13403 switch ( origin[ 0 ] ) {
13404 case "top": y = 0; break;
13405 case "middle": y = 0.5; break;
13406 case "bottom": y = 1; break;
13407 default: y = origin[ 0 ] / original.height;
13408 }
13409 switch ( origin[ 1 ] ) {
13410 case "left": x = 0; break;
13411 case "center": x = 0.5; break;
13412 case "right": x = 1; break;
13413 default: x = origin[ 1 ] / original.width;
13414 }
13415 return {
13416 x: x,
13417 y: y
13418 };
13419 },
13420
13421 // Wraps the element around a wrapper that copies position properties
13422 createWrapper: function( element ) {
13423
13424 // if the element is already wrapped, return it
13425 if ( element.parent().is( ".ui-effects-wrapper" )) {
13426 return element.parent();
13427 }
13428
13429 // wrap the element
13430 var props = {
13431 width: element.outerWidth(true),
13432 height: element.outerHeight(true),
13433 "float": element.css( "float" )
13434 },
13435 wrapper = $( "<div></div>" )
13436 .addClass( "ui-effects-wrapper" )
13437 .css({
13438 fontSize: "100%",
13439 background: "transparent",
13440 border: "none",
13441 margin: 0,
13442 padding: 0
13443 }),
13444 // Store the size in case width/height are defined in % - Fixes #5245
13445 size = {
13446 width: element.width(),
13447 height: element.height()
13448 },
13449 active = document.activeElement;
13450
13451 // support: Firefox
13452 // Firefox incorrectly exposes anonymous content
13453 // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
13454 try {
13455 active.id;
13456 } catch( e ) {
13457 active = document.body;
13458 }
13459
13460 element.wrap( wrapper );
13461
13462 // Fixes #7595 - Elements lose focus when wrapped.
13463 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
13464 $( active ).focus();
13465 }
13466
13467 wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element
13468
13469 // transfer positioning properties to the wrapper
13470 if ( element.css( "position" ) === "static" ) {
13471 wrapper.css({ position: "relative" });
13472 element.css({ position: "relative" });
13473 } else {
13474 $.extend( props, {
13475 position: element.css( "position" ),
13476 zIndex: element.css( "z-index" )
13477 });
13478 $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
13479 props[ pos ] = element.css( pos );
13480 if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
13481 props[ pos ] = "auto";
13482 }
13483 });
13484 element.css({
13485 position: "relative",
13486 top: 0,
13487 left: 0,
13488 right: "auto",
13489 bottom: "auto"
13490 });
13491 }
13492 element.css(size);
13493
13494 return wrapper.css( props ).show();
13495 },
13496
13497 removeWrapper: function( element ) {
13498 var active = document.activeElement;
13499
13500 if ( element.parent().is( ".ui-effects-wrapper" ) ) {
13501 element.parent().replaceWith( element );
13502
13503 // Fixes #7595 - Elements lose focus when wrapped.
13504 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
13505 $( active ).focus();
13506 }
13507 }
13508
13509
13510 return element;
13511 },
13512
13513 setTransition: function( element, list, factor, value ) {
13514 value = value || {};
13515 $.each( list, function( i, x ) {
13516 var unit = element.cssUnit( x );
13517 if ( unit[ 0 ] > 0 ) {
13518 value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
13519 }
13520 });
13521 return value;
13522 }
13523 });
13524
13525 // return an effect options object for the given parameters:
13526 function _normalizeArguments( effect, options, speed, callback ) {
13527
13528 // allow passing all optinos as the first parameter
13529 if ( $.isPlainObject( effect ) ) {
13530 options = effect;
13531 effect = effect.effect;
13532 }
13533
13534 // convert to an object
13535 effect = { effect: effect };
13536
13537 // catch (effect)
13538 if ( options === undefined ) {
13539 options = {};
13540 }
13541
13542 // catch (effect, callback)
13543 if ( $.isFunction( options ) ) {
13544 callback = options;
13545 speed = null;
13546 options = {};
13547 }
13548
13549 // catch (effect, speed, ?)
13550 if ( typeof options === "number" || $.fx.speeds[ options ] ) {
13551 callback = speed;
13552 speed = options;
13553 options = {};
13554 }
13555
13556 // catch (effect, options, callback)
13557 if ( $.isFunction( speed ) ) {
13558 callback = speed;
13559 speed = null;
13560 }
13561
13562 // add options to effect
13563 if ( options ) {
13564 $.extend( effect, options );
13565 }
13566
13567 speed = speed || options.duration;
13568 effect.duration = $.fx.off ? 0 :
13569 typeof speed === "number" ? speed :
13570 speed in $.fx.speeds ? $.fx.speeds[ speed ] :
13571 $.fx.speeds._default;
13572
13573 effect.complete = callback || options.complete;
13574
13575 return effect;
13576 }
13577
13578 function standardSpeed( speed ) {
13579 // valid standard speeds
13580 if ( !speed || typeof speed === "number" || $.fx.speeds[ speed ] ) {
13581 return true;
13582 }
13583
13584 // invalid strings - treat as "normal" speed
13585 if ( typeof speed === "string" && !$.effects.effect[ speed ] ) {
13586 // TODO: remove in 2.0 (#7115)
13587 if ( backCompat && $.effects[ speed ] ) {
13588 return false;
13589 }
13590 return true;
13591 }
13592
13593 return false;
13594 }
13595
13596 $.fn.extend({
13597 effect: function( effect, options, speed, callback ) {
13598 var args = _normalizeArguments.apply( this, arguments ),
13599 mode = args.mode,
13600 queue = args.queue,
13601 effectMethod = $.effects.effect[ args.effect ],
13602
13603 // DEPRECATED: remove in 2.0 (#7115)
13604 oldEffectMethod = !effectMethod && backCompat && $.effects[ args.effect ];
13605
13606 if ( $.fx.off || !( effectMethod || oldEffectMethod ) ) {
13607 // delegate to the original method (e.g., .show()) if possible
13608 if ( mode ) {
13609 return this[ mode ]( args.duration, args.complete );
13610 } else {
13611 return this.each( function() {
13612 if ( args.complete ) {
13613 args.complete.call( this );
13614 }
13615 });
13616 }
13617 }
13618
13619 function run( next ) {
13620 var elem = $( this ),
13621 complete = args.complete,
13622 mode = args.mode;
13623
13624 function done() {
13625 if ( $.isFunction( complete ) ) {
13626 complete.call( elem[0] );
13627 }
13628 if ( $.isFunction( next ) ) {
13629 next();
13630 }
13631 }
13632
13633 // if the element is hiddden and mode is hide,
13634 // or element is visible and mode is show
13635 if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
13636 done();
13637 } else {
13638 effectMethod.call( elem[0], args, done );
13639 }
13640 }
13641
13642 // TODO: remove this check in 2.0, effectMethod will always be true
13643 if ( effectMethod ) {
13644 return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
13645 } else {
13646 // DEPRECATED: remove in 2.0 (#7115)
13647 return oldEffectMethod.call(this, {
13648 options: args,
13649 duration: args.duration,
13650 callback: args.complete,
13651 mode: args.mode
13652 });
13653 }
13654 },
13655
13656 _show: $.fn.show,
13657 show: function( speed ) {
13658 if ( standardSpeed( speed ) ) {
13659 return this._show.apply( this, arguments );
13660 } else {
13661 var args = _normalizeArguments.apply( this, arguments );
13662 args.mode = "show";
13663 return this.effect.call( this, args );
13664 }
13665 },
13666
13667 _hide: $.fn.hide,
13668 hide: function( speed ) {
13669 if ( standardSpeed( speed ) ) {
13670 return this._hide.apply( this, arguments );
13671 } else {
13672 var args = _normalizeArguments.apply( this, arguments );
13673 args.mode = "hide";
13674 return this.effect.call( this, args );
13675 }
13676 },
13677
13678 // jQuery core overloads toggle and creates _toggle
13679 __toggle: $.fn.toggle,
13680 toggle: function( speed ) {
13681 if ( standardSpeed( speed ) || typeof speed === "boolean" || $.isFunction( speed ) ) {
13682 return this.__toggle.apply( this, arguments );
13683 } else {
13684 var args = _normalizeArguments.apply( this, arguments );
13685 args.mode = "toggle";
13686 return this.effect.call( this, args );
13687 }
13688 },
13689
13690 // helper functions
13691 cssUnit: function(key) {
13692 var style = this.css( key ),
13693 val = [];
13694
13695 $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
13696 if ( style.indexOf( unit ) > 0 ) {
13697 val = [ parseFloat( style ), unit ];
13698 }
13699 });
13700 return val;
13701 }
13702 });
13703
13704 })();
13705
13706 /******************************************************************************/
13707 /*********************************** EASING ***********************************/
13708 /******************************************************************************/
13709
13710 (function() {
13711
13712 // based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
13713
13714 var baseEasings = {};
13715
13716 $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
13717 baseEasings[ name ] = function( p ) {
13718 return Math.pow( p, i + 2 );
13719 };
13720 });
13721
13722 $.extend( baseEasings, {
13723 Sine: function ( p ) {
13724 return 1 - Math.cos( p * Math.PI / 2 );
13725 },
13726 Circ: function ( p ) {
13727 return 1 - Math.sqrt( 1 - p * p );
13728 },
13729 Elastic: function( p ) {
13730 return p === 0 || p === 1 ? p :
13731 -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 );
13732 },
13733 Back: function( p ) {
13734 return p * p * ( 3 * p - 2 );
13735 },
13736 Bounce: function ( p ) {
13737 var pow2,
13738 bounce = 4;
13739
13740 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
13741 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
13742 }
13743 });
13744
13745 $.each( baseEasings, function( name, easeIn ) {
13746 $.easing[ "easeIn" + name ] = easeIn;
13747 $.easing[ "easeOut" + name ] = function( p ) {
13748 return 1 - easeIn( 1 - p );
13749 };
13750 $.easing[ "easeInOut" + name ] = function( p ) {
13751 return p < 0.5 ?
13752 easeIn( p * 2 ) / 2 :
13753 1 - easeIn( p * -2 + 2 ) / 2;
13754 };
13755 });
13756
13757 })();
13758
13759 })(jQuery));
13760 (function( $, undefined ) {
13761
13762 var rvertical = /up|down|vertical/,
13763 rpositivemotion = /up|left|vertical|horizontal/;
13764
13765 $.effects.effect.blind = function( o, done ) {
13766 // Create element
13767 var el = $( this ),
13768 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
13769 mode = $.effects.setMode( el, o.mode || "hide" ),
13770 direction = o.direction || "up",
13771 vertical = rvertical.test( direction ),
13772 ref = vertical ? "height" : "width",
13773 ref2 = vertical ? "top" : "left",
13774 motion = rpositivemotion.test( direction ),
13775 animation = {},
13776 show = mode === "show",
13777 wrapper, distance, margin;
13778
13779 // if already wrapped, the wrapper's properties are my property. #6245
13780 if ( el.parent().is( ".ui-effects-wrapper" ) ) {
13781 $.effects.save( el.parent(), props );
13782 } else {
13783 $.effects.save( el, props );
13784 }
13785 el.show();
13786 wrapper = $.effects.createWrapper( el ).css({
13787 overflow: "hidden"
13788 });
13789
13790 distance = wrapper[ ref ]();
13791 margin = parseFloat( wrapper.css( ref2 ) ) || 0;
13792
13793 animation[ ref ] = show ? distance : 0;
13794 if ( !motion ) {
13795 el
13796 .css( vertical ? "bottom" : "right", 0 )
13797 .css( vertical ? "top" : "left", "auto" )
13798 .css({ position: "absolute" });
13799
13800 animation[ ref2 ] = show ? margin : distance + margin;
13801 }
13802
13803 // start at 0 if we are showing
13804 if ( show ) {
13805 wrapper.css( ref, 0 );
13806 if ( ! motion ) {
13807 wrapper.css( ref2, margin + distance );
13808 }
13809 }
13810
13811 // Animate
13812 wrapper.animate( animation, {
13813 duration: o.duration,
13814 easing: o.easing,
13815 queue: false,
13816 complete: function() {
13817 if ( mode === "hide" ) {
13818 el.hide();
13819 }
13820 $.effects.restore( el, props );
13821 $.effects.removeWrapper( el );
13822 done();
13823 }
13824 });
13825
13826 };
13827
13828 })(jQuery);
13829 (function( $, undefined ) {
13830
13831 $.effects.effect.bounce = function( o, done ) {
13832 var el = $( this ),
13833 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
13834
13835 // defaults:
13836 mode = $.effects.setMode( el, o.mode || "effect" ),
13837 hide = mode === "hide",
13838 show = mode === "show",
13839 direction = o.direction || "up",
13840 distance = o.distance,
13841 times = o.times || 5,
13842
13843 // number of internal animations
13844 anims = times * 2 + ( show || hide ? 1 : 0 ),
13845 speed = o.duration / anims,
13846 easing = o.easing,
13847
13848 // utility:
13849 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
13850 motion = ( direction === "up" || direction === "left" ),
13851 i,
13852 upAnim,
13853 downAnim,
13854
13855 // we will need to re-assemble the queue to stack our animations in place
13856 queue = el.queue(),
13857 queuelen = queue.length;
13858
13859 // Avoid touching opacity to prevent clearType and PNG issues in IE
13860 if ( show || hide ) {
13861 props.push( "opacity" );
13862 }
13863
13864 $.effects.save( el, props );
13865 el.show();
13866 $.effects.createWrapper( el ); // Create Wrapper
13867
13868 // default distance for the BIGGEST bounce is the outer Distance / 3
13869 if ( !distance ) {
13870 distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
13871 }
13872
13873 if ( show ) {
13874 downAnim = { opacity: 1 };
13875 downAnim[ ref ] = 0;
13876
13877 // if we are showing, force opacity 0 and set the initial position
13878 // then do the "first" animation
13879 el.css( "opacity", 0 )
13880 .css( ref, motion ? -distance * 2 : distance * 2 )
13881 .animate( downAnim, speed, easing );
13882 }
13883
13884 // start at the smallest distance if we are hiding
13885 if ( hide ) {
13886 distance = distance / Math.pow( 2, times - 1 );
13887 }
13888
13889 downAnim = {};
13890 downAnim[ ref ] = 0;
13891 // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
13892 for ( i = 0; i < times; i++ ) {
13893 upAnim = {};
13894 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
13895
13896 el.animate( upAnim, speed, easing )
13897 .animate( downAnim, speed, easing );
13898
13899 distance = hide ? distance * 2 : distance / 2;
13900 }
13901
13902 // Last Bounce when Hiding
13903 if ( hide ) {
13904 upAnim = { opacity: 0 };
13905 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
13906
13907 el.animate( upAnim, speed, easing );
13908 }
13909
13910 el.queue(function() {
13911 if ( hide ) {
13912 el.hide();
13913 }
13914 $.effects.restore( el, props );
13915 $.effects.removeWrapper( el );
13916 done();
13917 });
13918
13919 // inject all the animations we just queued to be first in line (after "inprogress")
13920 if ( queuelen > 1) {
13921 queue.splice.apply( queue,
13922 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
13923 }
13924 el.dequeue();
13925
13926 };
13927
13928 })(jQuery);
13929 (function( $, undefined ) {
13930
13931 $.effects.effect.clip = function( o, done ) {
13932 // Create element
13933 var el = $( this ),
13934 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
13935 mode = $.effects.setMode( el, o.mode || "hide" ),
13936 show = mode === "show",
13937 direction = o.direction || "vertical",
13938 vert = direction === "vertical",
13939 size = vert ? "height" : "width",
13940 position = vert ? "top" : "left",
13941 animation = {},
13942 wrapper, animate, distance;
13943
13944 // Save & Show
13945 $.effects.save( el, props );
13946 el.show();
13947
13948 // Create Wrapper
13949 wrapper = $.effects.createWrapper( el ).css({
13950 overflow: "hidden"
13951 });
13952 animate = ( el[0].tagName === "IMG" ) ? wrapper : el;
13953 distance = animate[ size ]();
13954
13955 // Shift
13956 if ( show ) {
13957 animate.css( size, 0 );
13958 animate.css( position, distance / 2 );
13959 }
13960
13961 // Create Animation Object:
13962 animation[ size ] = show ? distance : 0;
13963 animation[ position ] = show ? 0 : distance / 2;
13964
13965 // Animate
13966 animate.animate( animation, {
13967 queue: false,
13968 duration: o.duration,
13969 easing: o.easing,
13970 complete: function() {
13971 if ( !show ) {
13972 el.hide();
13973 }
13974 $.effects.restore( el, props );
13975 $.effects.removeWrapper( el );
13976 done();
13977 }
13978 });
13979
13980 };
13981
13982 })(jQuery);
13983 (function( $, undefined ) {
13984
13985 $.effects.effect.drop = function( o, done ) {
13986
13987 var el = $( this ),
13988 props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
13989 mode = $.effects.setMode( el, o.mode || "hide" ),
13990 show = mode === "show",
13991 direction = o.direction || "left",
13992 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
13993 motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
13994 animation = {
13995 opacity: show ? 1 : 0
13996 },
13997 distance;
13998
13999 // Adjust
14000 $.effects.save( el, props );
14001 el.show();
14002 $.effects.createWrapper( el );
14003
14004 distance = o.distance || el[ ref === "top" ? "outerHeight": "outerWidth" ]( true ) / 2;
14005
14006 if ( show ) {
14007 el
14008 .css( "opacity", 0 )
14009 .css( ref, motion === "pos" ? -distance : distance );
14010 }
14011
14012 // Animation
14013 animation[ ref ] = ( show ?
14014 ( motion === "pos" ? "+=" : "-=" ) :
14015 ( motion === "pos" ? "-=" : "+=" ) ) +
14016 distance;
14017
14018 // Animate
14019 el.animate( animation, {
14020 queue: false,
14021 duration: o.duration,
14022 easing: o.easing,
14023 complete: function() {
14024 if ( mode === "hide" ) {
14025 el.hide();
14026 }
14027 $.effects.restore( el, props );
14028 $.effects.removeWrapper( el );
14029 done();
14030 }
14031 });
14032 };
14033
14034 })(jQuery);
14035 (function( $, undefined ) {
14036
14037 $.effects.effect.explode = function( o, done ) {
14038
14039 var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3,
14040 cells = rows,
14041 el = $( this ),
14042 mode = $.effects.setMode( el, o.mode || "hide" ),
14043 show = mode === "show",
14044
14045 // show and then visibility:hidden the element before calculating offset
14046 offset = el.show().css( "visibility", "hidden" ).offset(),
14047
14048 // width and height of a piece
14049 width = Math.ceil( el.outerWidth() / cells ),
14050 height = Math.ceil( el.outerHeight() / rows ),
14051 pieces = [],
14052
14053 // loop
14054 i, j, left, top, mx, my;
14055
14056 // children animate complete:
14057 function childComplete() {
14058 pieces.push( this );
14059 if ( pieces.length === rows * cells ) {
14060 animComplete();
14061 }
14062 }
14063
14064 // clone the element for each row and cell.
14065 for( i = 0; i < rows ; i++ ) { // ===>
14066 top = offset.top + i * height;
14067 my = i - ( rows - 1 ) / 2 ;
14068
14069 for( j = 0; j < cells ; j++ ) { // |||
14070 left = offset.left + j * width;
14071 mx = j - ( cells - 1 ) / 2 ;
14072
14073 // Create a clone of the now hidden main element that will be absolute positioned
14074 // within a wrapper div off the -left and -top equal to size of our pieces
14075 el
14076 .clone()
14077 .appendTo( "body" )
14078 .wrap( "<div></div>" )
14079 .css({
14080 position: "absolute",
14081 visibility: "visible",
14082 left: -j * width,
14083 top: -i * height
14084 })
14085
14086 // select the wrapper - make it overflow: hidden and absolute positioned based on
14087 // where the original was located +left and +top equal to the size of pieces
14088 .parent()
14089 .addClass( "ui-effects-explode" )
14090 .css({
14091 position: "absolute",
14092 overflow: "hidden",
14093 width: width,
14094 height: height,
14095 left: left + ( show ? mx * width : 0 ),
14096 top: top + ( show ? my * height : 0 ),
14097 opacity: show ? 0 : 1
14098 }).animate({
14099 left: left + ( show ? 0 : mx * width ),
14100 top: top + ( show ? 0 : my * height ),
14101 opacity: show ? 1 : 0
14102 }, o.duration || 500, o.easing, childComplete );
14103 }
14104 }
14105
14106 function animComplete() {
14107 el.css({
14108 visibility: "visible"
14109 });
14110 $( pieces ).remove();
14111 if ( !show ) {
14112 el.hide();
14113 }
14114 done();
14115 }
14116 };
14117
14118 })(jQuery);
14119 (function( $, undefined ) {
14120
14121 $.effects.effect.fade = function( o, done ) {
14122 var el = $( this ),
14123 mode = $.effects.setMode( el, o.mode || "toggle" );
14124
14125 el.animate({
14126 opacity: mode
14127 }, {
14128 queue: false,
14129 duration: o.duration,
14130 easing: o.easing,
14131 complete: done
14132 });
14133 };
14134
14135 })( jQuery );
14136 (function( $, undefined ) {
14137
14138 $.effects.effect.fold = function( o, done ) {
14139
14140 // Create element
14141 var el = $( this ),
14142 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
14143 mode = $.effects.setMode( el, o.mode || "hide" ),
14144 show = mode === "show",
14145 hide = mode === "hide",
14146 size = o.size || 15,
14147 percent = /([0-9]+)%/.exec( size ),
14148 horizFirst = !!o.horizFirst,
14149 widthFirst = show !== horizFirst,
14150 ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ],
14151 duration = o.duration / 2,
14152 wrapper, distance,
14153 animation1 = {},
14154 animation2 = {};
14155
14156 $.effects.save( el, props );
14157 el.show();
14158
14159 // Create Wrapper
14160 wrapper = $.effects.createWrapper( el ).css({
14161 overflow: "hidden"
14162 });
14163 distance = widthFirst ?
14164 [ wrapper.width(), wrapper.height() ] :
14165 [ wrapper.height(), wrapper.width() ];
14166
14167 if ( percent ) {
14168 size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
14169 }
14170 if ( show ) {
14171 wrapper.css( horizFirst ? {
14172 height: 0,
14173 width: size
14174 } : {
14175 height: size,
14176 width: 0
14177 });
14178 }
14179
14180 // Animation
14181 animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size;
14182 animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0;
14183
14184 // Animate
14185 wrapper
14186 .animate( animation1, duration, o.easing )
14187 .animate( animation2, duration, o.easing, function() {
14188 if ( hide ) {
14189 el.hide();
14190 }
14191 $.effects.restore( el, props );
14192 $.effects.removeWrapper( el );
14193 done();
14194 });
14195
14196 };
14197
14198 })(jQuery);
14199 (function( $, undefined ) {
14200
14201 $.effects.effect.highlight = function( o, done ) {
14202 var elem = $( this ),
14203 props = [ "backgroundImage", "backgroundColor", "opacity" ],
14204 mode = $.effects.setMode( elem, o.mode || "show" ),
14205 animation = {
14206 backgroundColor: elem.css( "backgroundColor" )
14207 };
14208
14209 if (mode === "hide") {
14210 animation.opacity = 0;
14211 }
14212
14213 $.effects.save( elem, props );
14214
14215 elem
14216 .show()
14217 .css({
14218 backgroundImage: "none",
14219 backgroundColor: o.color || "#ffff99"
14220 })
14221 .animate( animation, {
14222 queue: false,
14223 duration: o.duration,
14224 easing: o.easing,
14225 complete: function() {
14226 if ( mode === "hide" ) {
14227 elem.hide();
14228 }
14229 $.effects.restore( elem, props );
14230 done();
14231 }
14232 });
14233 };
14234
14235 })(jQuery);
14236 (function( $, undefined ) {
14237
14238 $.effects.effect.pulsate = function( o, done ) {
14239 var elem = $( this ),
14240 mode = $.effects.setMode( elem, o.mode || "show" ),
14241 show = mode === "show",
14242 hide = mode === "hide",
14243 showhide = ( show || mode === "hide" ),
14244
14245 // showing or hiding leaves of the "last" animation
14246 anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
14247 duration = o.duration / anims,
14248 animateTo = 0,
14249 queue = elem.queue(),
14250 queuelen = queue.length,
14251 i;
14252
14253 if ( show || !elem.is(":visible")) {
14254 elem.css( "opacity", 0 ).show();
14255 animateTo = 1;
14256 }
14257
14258 // anims - 1 opacity "toggles"
14259 for ( i = 1; i < anims; i++ ) {
14260 elem.animate({
14261 opacity: animateTo
14262 }, duration, o.easing );
14263 animateTo = 1 - animateTo;
14264 }
14265
14266 elem.animate({
14267 opacity: animateTo
14268 }, duration, o.easing);
14269
14270 elem.queue(function() {
14271 if ( hide ) {
14272 elem.hide();
14273 }
14274 done();
14275 });
14276
14277 // We just queued up "anims" animations, we need to put them next in the queue
14278 if ( queuelen > 1 ) {
14279 queue.splice.apply( queue,
14280 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
14281 }
14282 elem.dequeue();
14283 };
14284
14285 })(jQuery);
14286 (function( $, undefined ) {
14287
14288 $.effects.effect.puff = function( o, done ) {
14289 var elem = $( this ),
14290 mode = $.effects.setMode( elem, o.mode || "hide" ),
14291 hide = mode === "hide",
14292 percent = parseInt( o.percent, 10 ) || 150,
14293 factor = percent / 100,
14294 original = {
14295 height: elem.height(),
14296 width: elem.width()
14297 };
14298
14299 $.extend( o, {
14300 effect: "scale",
14301 queue: false,
14302 fade: true,
14303 mode: mode,
14304 complete: done,
14305 percent: hide ? percent : 100,
14306 from: hide ?
14307 original :
14308 {
14309 height: original.height * factor,
14310 width: original.width * factor
14311 }
14312 });
14313
14314 elem.effect( o );
14315 };
14316
14317 $.effects.effect.scale = function( o, done ) {
14318
14319 // Create element
14320 var el = $( this ),
14321 options = $.extend( true, {}, o ),
14322 mode = $.effects.setMode( el, o.mode || "effect" ),
14323 percent = parseInt( o.percent, 10 ) ||
14324 ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ),
14325 direction = o.direction || "both",
14326 origin = o.origin,
14327 original = {
14328 height: el.height(),
14329 width: el.width(),
14330 outerHeight: el.outerHeight(),
14331 outerWidth: el.outerWidth()
14332 },
14333 factor = {
14334 y: direction !== "horizontal" ? (percent / 100) : 1,
14335 x: direction !== "vertical" ? (percent / 100) : 1
14336 };
14337
14338 // We are going to pass this effect to the size effect:
14339 options.effect = "size";
14340 options.queue = false;
14341 options.complete = done;
14342
14343 // Set default origin and restore for show/hide
14344 if ( mode !== "effect" ) {
14345 options.origin = origin || ["middle","center"];
14346 options.restore = true;
14347 }
14348
14349 options.from = o.from || ( mode === "show" ? { height: 0, width: 0 } : original );
14350 options.to = {
14351 height: original.height * factor.y,
14352 width: original.width * factor.x,
14353 outerHeight: original.outerHeight * factor.y,
14354 outerWidth: original.outerWidth * factor.x
14355 };
14356
14357 // Fade option to support puff
14358 if ( options.fade ) {
14359 if ( mode === "show" ) {
14360 options.from.opacity = 0;
14361 options.to.opacity = 1;
14362 }
14363 if ( mode === "hide" ) {
14364 options.from.opacity = 1;
14365 options.to.opacity = 0;
14366 }
14367 }
14368
14369 // Animate
14370 el.effect( options );
14371
14372 };
14373
14374 $.effects.effect.size = function( o, done ) {
14375
14376 // Create element
14377 var el = $( this ),
14378 props = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ],
14379
14380 // Always restore
14381 props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ],
14382
14383 // Copy for children
14384 props2 = [ "width", "height", "overflow" ],
14385 cProps = [ "fontSize" ],
14386 vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
14387 hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
14388
14389 // Set options
14390 mode = $.effects.setMode( el, o.mode || "effect" ),
14391 restore = o.restore || mode !== "effect",
14392 scale = o.scale || "both",
14393 origin = o.origin || [ "middle", "center" ],
14394 original, baseline, factor,
14395 position = el.css( "position" );
14396
14397 if ( mode === "show" ) {
14398 el.show();
14399 }
14400 original = {
14401 height: el.height(),
14402 width: el.width(),
14403 outerHeight: el.outerHeight(),
14404 outerWidth: el.outerWidth()
14405 };
14406
14407 el.from = o.from || original;
14408 el.to = o.to || original;
14409
14410 // Set scaling factor
14411 factor = {
14412 from: {
14413 y: el.from.height / original.height,
14414 x: el.from.width / original.width
14415 },
14416 to: {
14417 y: el.to.height / original.height,
14418 x: el.to.width / original.width
14419 }
14420 };
14421
14422 // Scale the css box
14423 if ( scale === "box" || scale === "both" ) {
14424
14425 // Vertical props scaling
14426 if ( factor.from.y !== factor.to.y ) {
14427 props = props.concat( vProps );
14428 el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
14429 el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
14430 }
14431
14432 // Horizontal props scaling
14433 if ( factor.from.x !== factor.to.x ) {
14434 props = props.concat( hProps );
14435 el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
14436 el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
14437 }
14438 }
14439
14440 // Scale the content
14441 if ( scale === "content" || scale === "both" ) {
14442
14443 // Vertical props scaling
14444 if ( factor.from.y !== factor.to.y ) {
14445 props = props.concat( cProps );
14446 el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
14447 el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
14448 }
14449 }
14450
14451 $.effects.save( el, restore ? props : props1 );
14452 el.show();
14453 $.effects.createWrapper( el );
14454 el.css( "overflow", "hidden" ).css( el.from );
14455
14456 // Adjust
14457 if (origin) { // Calculate baseline shifts
14458 baseline = $.effects.getBaseline( origin, original );
14459 el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
14460 el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
14461 el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
14462 el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
14463 }
14464 el.css( el.from ); // set top & left
14465
14466 // Animate
14467 if ( scale === "content" || scale === "both" ) { // Scale the children
14468
14469 // Add margins/font-size
14470 vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps);
14471 hProps = hProps.concat([ "marginLeft", "marginRight" ]);
14472 props2 = props.concat(vProps).concat(hProps);
14473
14474 el.find( "*[width]" ).each( function(){
14475 var child = $( this ),
14476 c_original = {
14477 height: child.height(),
14478 width: child.width()
14479 };
14480 if (restore) {
14481 $.effects.save(child, props2);
14482 }
14483
14484 child.from = {
14485 height: c_original.height * factor.from.y,
14486 width: c_original.width * factor.from.x
14487 };
14488 child.to = {
14489 height: c_original.height * factor.to.y,
14490 width: c_original.width * factor.to.x
14491 };
14492
14493 // Vertical props scaling
14494 if ( factor.from.y !== factor.to.y ) {
14495 child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
14496 child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
14497 }
14498
14499 // Horizontal props scaling
14500 if ( factor.from.x !== factor.to.x ) {
14501 child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
14502 child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
14503 }
14504
14505 // Animate children
14506 child.css( child.from );
14507 child.animate( child.to, o.duration, o.easing, function() {
14508
14509 // Restore children
14510 if ( restore ) {
14511 $.effects.restore( child, props2 );
14512 }
14513 });
14514 });
14515 }
14516
14517 // Animate
14518 el.animate( el.to, {
14519 queue: false,
14520 duration: o.duration,
14521 easing: o.easing,
14522 complete: function() {
14523 if ( el.to.opacity === 0 ) {
14524 el.css( "opacity", el.from.opacity );
14525 }
14526 if( mode === "hide" ) {
14527 el.hide();
14528 }
14529 $.effects.restore( el, restore ? props : props1 );
14530 if ( !restore ) {
14531
14532 // we need to calculate our new positioning based on the scaling
14533 if ( position === "static" ) {
14534 el.css({
14535 position: "relative",
14536 top: el.to.top,
14537 left: el.to.left
14538 });
14539 } else {
14540 $.each([ "top", "left" ], function( idx, pos ) {
14541 el.css( pos, function( _, str ) {
14542 var val = parseInt( str, 10 ),
14543 toRef = idx ? el.to.left : el.to.top;
14544
14545 // if original was "auto", recalculate the new value from wrapper
14546 if ( str === "auto" ) {
14547 return toRef + "px";
14548 }
14549
14550 return val + toRef + "px";
14551 });
14552 });
14553 }
14554 }
14555
14556 $.effects.removeWrapper( el );
14557 done();
14558 }
14559 });
14560
14561 };
14562
14563 })(jQuery);
14564 (function( $, undefined ) {
14565
14566 $.effects.effect.shake = function( o, done ) {
14567
14568 var el = $( this ),
14569 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
14570 mode = $.effects.setMode( el, o.mode || "effect" ),
14571 direction = o.direction || "left",
14572 distance = o.distance || 20,
14573 times = o.times || 3,
14574 anims = times * 2 + 1,
14575 speed = Math.round(o.duration/anims),
14576 ref = (direction === "up" || direction === "down") ? "top" : "left",
14577 positiveMotion = (direction === "up" || direction === "left"),
14578 animation = {},
14579 animation1 = {},
14580 animation2 = {},
14581 i,
14582
14583 // we will need to re-assemble the queue to stack our animations in place
14584 queue = el.queue(),
14585 queuelen = queue.length;
14586
14587 $.effects.save( el, props );
14588 el.show();
14589 $.effects.createWrapper( el );
14590
14591 // Animation
14592 animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
14593 animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
14594 animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
14595
14596 // Animate
14597 el.animate( animation, speed, o.easing );
14598
14599 // Shakes
14600 for ( i = 1; i < times; i++ ) {
14601 el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing );
14602 }
14603 el
14604 .animate( animation1, speed, o.easing )
14605 .animate( animation, speed / 2, o.easing )
14606 .queue(function() {
14607 if ( mode === "hide" ) {
14608 el.hide();
14609 }
14610 $.effects.restore( el, props );
14611 $.effects.removeWrapper( el );
14612 done();
14613 });
14614
14615 // inject all the animations we just queued to be first in line (after "inprogress")
14616 if ( queuelen > 1) {
14617 queue.splice.apply( queue,
14618 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
14619 }
14620 el.dequeue();
14621
14622 };
14623
14624 })(jQuery);
14625 (function( $, undefined ) {
14626
14627 $.effects.effect.slide = function( o, done ) {
14628
14629 // Create element
14630 var el = $( this ),
14631 props = [ "position", "top", "bottom", "left", "right", "width", "height" ],
14632 mode = $.effects.setMode( el, o.mode || "show" ),
14633 show = mode === "show",
14634 direction = o.direction || "left",
14635 ref = (direction === "up" || direction === "down") ? "top" : "left",
14636 positiveMotion = (direction === "up" || direction === "left"),
14637 distance,
14638 animation = {};
14639
14640 // Adjust
14641 $.effects.save( el, props );
14642 el.show();
14643 distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true );
14644
14645 $.effects.createWrapper( el ).css({
14646 overflow: "hidden"
14647 });
14648
14649 if ( show ) {
14650 el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance );
14651 }
14652
14653 // Animation
14654 animation[ ref ] = ( show ?
14655 ( positiveMotion ? "+=" : "-=") :
14656 ( positiveMotion ? "-=" : "+=")) +
14657 distance;
14658
14659 // Animate
14660 el.animate( animation, {
14661 queue: false,
14662 duration: o.duration,
14663 easing: o.easing,
14664 complete: function() {
14665 if ( mode === "hide" ) {
14666 el.hide();
14667 }
14668 $.effects.restore( el, props );
14669 $.effects.removeWrapper( el );
14670 done();
14671 }
14672 });
14673 };
14674
14675 })(jQuery);
14676 (function( $, undefined ) {
14677
14678 $.effects.effect.transfer = function( o, done ) {
14679 var elem = $( this ),
14680 target = $( o.to ),
14681 targetFixed = target.css( "position" ) === "fixed",
14682 body = $("body"),
14683 fixTop = targetFixed ? body.scrollTop() : 0,
14684 fixLeft = targetFixed ? body.scrollLeft() : 0,
14685 endPosition = target.offset(),
14686 animation = {
14687 top: endPosition.top - fixTop ,
14688 left: endPosition.left - fixLeft ,
14689 height: target.innerHeight(),
14690 width: target.innerWidth()
14691 },
14692 startPosition = elem.offset(),
14693 transfer = $( '<div class="ui-effects-transfer"></div>' )
14694 .appendTo( document.body )
14695 .addClass( o.className )
14696 .css({
14697 top: startPosition.top - fixTop ,
14698 left: startPosition.left - fixLeft ,
14699 height: elem.innerHeight(),
14700 width: elem.innerWidth(),
14701 position: targetFixed ? "fixed" : "absolute"
14702 })
14703 .animate( animation, o.duration, o.easing, function() {
14704 transfer.remove();
14705 done();
14706 });
14707 };
14708
14709 })(jQuery);