luci2: use custom jQuery UI build with all uneeded functionality trimmed, saves 320K...
[project/luci2/ui.git] / luci2 / htdocs / luci2 / jquery-ui-1.10.3.custom.js
1 /*! jQuery UI - v1.10.3 - 2013-10-15
2 * http://jqueryui.com
3 * Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.sortable.js, jquery.ui.accordion.js, jquery.ui.tabs.js
4 * Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
5
6 (function( $, undefined ) {
7
8 var uuid = 0,
9 runiqueId = /^ui-id-\d+$/;
10
11 // $.ui might exist from components with no dependencies, e.g., $.ui.position
12 $.ui = $.ui || {};
13
14 $.extend( $.ui, {
15 version: "1.10.3",
16
17 keyCode: {
18 BACKSPACE: 8,
19 COMMA: 188,
20 DELETE: 46,
21 DOWN: 40,
22 END: 35,
23 ENTER: 13,
24 ESCAPE: 27,
25 HOME: 36,
26 LEFT: 37,
27 NUMPAD_ADD: 107,
28 NUMPAD_DECIMAL: 110,
29 NUMPAD_DIVIDE: 111,
30 NUMPAD_ENTER: 108,
31 NUMPAD_MULTIPLY: 106,
32 NUMPAD_SUBTRACT: 109,
33 PAGE_DOWN: 34,
34 PAGE_UP: 33,
35 PERIOD: 190,
36 RIGHT: 39,
37 SPACE: 32,
38 TAB: 9,
39 UP: 38
40 }
41 });
42
43 // plugins
44 $.fn.extend({
45 focus: (function( orig ) {
46 return function( delay, fn ) {
47 return typeof delay === "number" ?
48 this.each(function() {
49 var elem = this;
50 setTimeout(function() {
51 $( elem ).focus();
52 if ( fn ) {
53 fn.call( elem );
54 }
55 }, delay );
56 }) :
57 orig.apply( this, arguments );
58 };
59 })( $.fn.focus ),
60
61 scrollParent: function() {
62 var scrollParent;
63 if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) {
64 scrollParent = this.parents().filter(function() {
65 return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
66 }).eq(0);
67 } else {
68 scrollParent = this.parents().filter(function() {
69 return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
70 }).eq(0);
71 }
72
73 return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent;
74 },
75
76 zIndex: function( zIndex ) {
77 if ( zIndex !== undefined ) {
78 return this.css( "zIndex", zIndex );
79 }
80
81 if ( this.length ) {
82 var elem = $( this[ 0 ] ), position, value;
83 while ( elem.length && elem[ 0 ] !== document ) {
84 // Ignore z-index if position is set to a value where z-index is ignored by the browser
85 // This makes behavior of this function consistent across browsers
86 // WebKit always returns auto if the element is positioned
87 position = elem.css( "position" );
88 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
89 // IE returns 0 when zIndex is not specified
90 // other browsers return a string
91 // we ignore the case of nested elements with an explicit value of 0
92 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
93 value = parseInt( elem.css( "zIndex" ), 10 );
94 if ( !isNaN( value ) && value !== 0 ) {
95 return value;
96 }
97 }
98 elem = elem.parent();
99 }
100 }
101
102 return 0;
103 },
104
105 uniqueId: function() {
106 return this.each(function() {
107 if ( !this.id ) {
108 this.id = "ui-id-" + (++uuid);
109 }
110 });
111 },
112
113 removeUniqueId: function() {
114 return this.each(function() {
115 if ( runiqueId.test( this.id ) ) {
116 $( this ).removeAttr( "id" );
117 }
118 });
119 }
120 });
121
122 // selectors
123 function focusable( element, isTabIndexNotNaN ) {
124 var map, mapName, img,
125 nodeName = element.nodeName.toLowerCase();
126 if ( "area" === nodeName ) {
127 map = element.parentNode;
128 mapName = map.name;
129 if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
130 return false;
131 }
132 img = $( "img[usemap=#" + mapName + "]" )[0];
133 return !!img && visible( img );
134 }
135 return ( /input|select|textarea|button|object/.test( nodeName ) ?
136 !element.disabled :
137 "a" === nodeName ?
138 element.href || isTabIndexNotNaN :
139 isTabIndexNotNaN) &&
140 // the element and all of its ancestors must be visible
141 visible( element );
142 }
143
144 function visible( element ) {
145 return $.expr.filters.visible( element ) &&
146 !$( element ).parents().addBack().filter(function() {
147 return $.css( this, "visibility" ) === "hidden";
148 }).length;
149 }
150
151 $.extend( $.expr[ ":" ], {
152 data: $.expr.createPseudo ?
153 $.expr.createPseudo(function( dataName ) {
154 return function( elem ) {
155 return !!$.data( elem, dataName );
156 };
157 }) :
158 // support: jQuery <1.8
159 function( elem, i, match ) {
160 return !!$.data( elem, match[ 3 ] );
161 },
162
163 focusable: function( element ) {
164 return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
165 },
166
167 tabbable: function( element ) {
168 var tabIndex = $.attr( element, "tabindex" ),
169 isTabIndexNaN = isNaN( tabIndex );
170 return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
171 }
172 });
173
174 // support: jQuery <1.8
175 if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
176 $.each( [ "Width", "Height" ], function( i, name ) {
177 var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
178 type = name.toLowerCase(),
179 orig = {
180 innerWidth: $.fn.innerWidth,
181 innerHeight: $.fn.innerHeight,
182 outerWidth: $.fn.outerWidth,
183 outerHeight: $.fn.outerHeight
184 };
185
186 function reduce( elem, size, border, margin ) {
187 $.each( side, function() {
188 size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
189 if ( border ) {
190 size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
191 }
192 if ( margin ) {
193 size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
194 }
195 });
196 return size;
197 }
198
199 $.fn[ "inner" + name ] = function( size ) {
200 if ( size === undefined ) {
201 return orig[ "inner" + name ].call( this );
202 }
203
204 return this.each(function() {
205 $( this ).css( type, reduce( this, size ) + "px" );
206 });
207 };
208
209 $.fn[ "outer" + name] = function( size, margin ) {
210 if ( typeof size !== "number" ) {
211 return orig[ "outer" + name ].call( this, size );
212 }
213
214 return this.each(function() {
215 $( this).css( type, reduce( this, size, true, margin ) + "px" );
216 });
217 };
218 });
219 }
220
221 // support: jQuery <1.8
222 if ( !$.fn.addBack ) {
223 $.fn.addBack = function( selector ) {
224 return this.add( selector == null ?
225 this.prevObject : this.prevObject.filter( selector )
226 );
227 };
228 }
229
230 // support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
231 if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
232 $.fn.removeData = (function( removeData ) {
233 return function( key ) {
234 if ( arguments.length ) {
235 return removeData.call( this, $.camelCase( key ) );
236 } else {
237 return removeData.call( this );
238 }
239 };
240 })( $.fn.removeData );
241 }
242
243
244
245
246
247 // deprecated
248 $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
249
250 $.support.selectstart = "onselectstart" in document.createElement( "div" );
251 $.fn.extend({
252 disableSelection: function() {
253 return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
254 ".ui-disableSelection", function( event ) {
255 event.preventDefault();
256 });
257 },
258
259 enableSelection: function() {
260 return this.unbind( ".ui-disableSelection" );
261 }
262 });
263
264 $.extend( $.ui, {
265 // $.ui.plugin is deprecated. Use $.widget() extensions instead.
266 plugin: {
267 add: function( module, option, set ) {
268 var i,
269 proto = $.ui[ module ].prototype;
270 for ( i in set ) {
271 proto.plugins[ i ] = proto.plugins[ i ] || [];
272 proto.plugins[ i ].push( [ option, set[ i ] ] );
273 }
274 },
275 call: function( instance, name, args ) {
276 var i,
277 set = instance.plugins[ name ];
278 if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) {
279 return;
280 }
281
282 for ( i = 0; i < set.length; i++ ) {
283 if ( instance.options[ set[ i ][ 0 ] ] ) {
284 set[ i ][ 1 ].apply( instance.element, args );
285 }
286 }
287 }
288 },
289
290 // only used by resizable
291 hasScroll: function( el, a ) {
292
293 //If overflow is hidden, the element might have extra content, but the user wants to hide it
294 if ( $( el ).css( "overflow" ) === "hidden") {
295 return false;
296 }
297
298 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
299 has = false;
300
301 if ( el[ scroll ] > 0 ) {
302 return true;
303 }
304
305 // TODO: determine which cases actually cause this to happen
306 // if the element doesn't have the scroll set, see if it's possible to
307 // set the scroll
308 el[ scroll ] = 1;
309 has = ( el[ scroll ] > 0 );
310 el[ scroll ] = 0;
311 return has;
312 }
313 });
314
315 })( jQuery );
316 (function( $, undefined ) {
317
318 var uuid = 0,
319 slice = Array.prototype.slice,
320 _cleanData = $.cleanData;
321 $.cleanData = function( elems ) {
322 for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
323 try {
324 $( elem ).triggerHandler( "remove" );
325 // http://bugs.jquery.com/ticket/8235
326 } catch( e ) {}
327 }
328 _cleanData( elems );
329 };
330
331 $.widget = function( name, base, prototype ) {
332 var fullName, existingConstructor, constructor, basePrototype,
333 // proxiedPrototype allows the provided prototype to remain unmodified
334 // so that it can be used as a mixin for multiple widgets (#8876)
335 proxiedPrototype = {},
336 namespace = name.split( "." )[ 0 ];
337
338 name = name.split( "." )[ 1 ];
339 fullName = namespace + "-" + name;
340
341 if ( !prototype ) {
342 prototype = base;
343 base = $.Widget;
344 }
345
346 // create selector for plugin
347 $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
348 return !!$.data( elem, fullName );
349 };
350
351 $[ namespace ] = $[ namespace ] || {};
352 existingConstructor = $[ namespace ][ name ];
353 constructor = $[ namespace ][ name ] = function( options, element ) {
354 // allow instantiation without "new" keyword
355 if ( !this._createWidget ) {
356 return new constructor( options, element );
357 }
358
359 // allow instantiation without initializing for simple inheritance
360 // must use "new" keyword (the code above always passes args)
361 if ( arguments.length ) {
362 this._createWidget( options, element );
363 }
364 };
365 // extend with the existing constructor to carry over any static properties
366 $.extend( constructor, existingConstructor, {
367 version: prototype.version,
368 // copy the object used to create the prototype in case we need to
369 // redefine the widget later
370 _proto: $.extend( {}, prototype ),
371 // track widgets that inherit from this widget in case this widget is
372 // redefined after a widget inherits from it
373 _childConstructors: []
374 });
375
376 basePrototype = new base();
377 // we need to make the options hash a property directly on the new instance
378 // otherwise we'll modify the options hash on the prototype that we're
379 // inheriting from
380 basePrototype.options = $.widget.extend( {}, basePrototype.options );
381 $.each( prototype, function( prop, value ) {
382 if ( !$.isFunction( value ) ) {
383 proxiedPrototype[ prop ] = value;
384 return;
385 }
386 proxiedPrototype[ prop ] = (function() {
387 var _super = function() {
388 return base.prototype[ prop ].apply( this, arguments );
389 },
390 _superApply = function( args ) {
391 return base.prototype[ prop ].apply( this, args );
392 };
393 return function() {
394 var __super = this._super,
395 __superApply = this._superApply,
396 returnValue;
397
398 this._super = _super;
399 this._superApply = _superApply;
400
401 returnValue = value.apply( this, arguments );
402
403 this._super = __super;
404 this._superApply = __superApply;
405
406 return returnValue;
407 };
408 })();
409 });
410 constructor.prototype = $.widget.extend( basePrototype, {
411 // TODO: remove support for widgetEventPrefix
412 // always use the name + a colon as the prefix, e.g., draggable:start
413 // don't prefix for widgets that aren't DOM-based
414 widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name
415 }, proxiedPrototype, {
416 constructor: constructor,
417 namespace: namespace,
418 widgetName: name,
419 widgetFullName: fullName
420 });
421
422 // If this widget is being redefined then we need to find all widgets that
423 // are inheriting from it and redefine all of them so that they inherit from
424 // the new version of this widget. We're essentially trying to replace one
425 // level in the prototype chain.
426 if ( existingConstructor ) {
427 $.each( existingConstructor._childConstructors, function( i, child ) {
428 var childPrototype = child.prototype;
429
430 // redefine the child widget using the same prototype that was
431 // originally used, but inherit from the new version of the base
432 $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
433 });
434 // remove the list of existing child constructors from the old constructor
435 // so the old child constructors can be garbage collected
436 delete existingConstructor._childConstructors;
437 } else {
438 base._childConstructors.push( constructor );
439 }
440
441 $.widget.bridge( name, constructor );
442 };
443
444 $.widget.extend = function( target ) {
445 var input = slice.call( arguments, 1 ),
446 inputIndex = 0,
447 inputLength = input.length,
448 key,
449 value;
450 for ( ; inputIndex < inputLength; inputIndex++ ) {
451 for ( key in input[ inputIndex ] ) {
452 value = input[ inputIndex ][ key ];
453 if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
454 // Clone objects
455 if ( $.isPlainObject( value ) ) {
456 target[ key ] = $.isPlainObject( target[ key ] ) ?
457 $.widget.extend( {}, target[ key ], value ) :
458 // Don't extend strings, arrays, etc. with objects
459 $.widget.extend( {}, value );
460 // Copy everything else by reference
461 } else {
462 target[ key ] = value;
463 }
464 }
465 }
466 }
467 return target;
468 };
469
470 $.widget.bridge = function( name, object ) {
471 var fullName = object.prototype.widgetFullName || name;
472 $.fn[ name ] = function( options ) {
473 var isMethodCall = typeof options === "string",
474 args = slice.call( arguments, 1 ),
475 returnValue = this;
476
477 // allow multiple hashes to be passed on init
478 options = !isMethodCall && args.length ?
479 $.widget.extend.apply( null, [ options ].concat(args) ) :
480 options;
481
482 if ( isMethodCall ) {
483 this.each(function() {
484 var methodValue,
485 instance = $.data( this, fullName );
486 if ( !instance ) {
487 return $.error( "cannot call methods on " + name + " prior to initialization; " +
488 "attempted to call method '" + options + "'" );
489 }
490 if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
491 return $.error( "no such method '" + options + "' for " + name + " widget instance" );
492 }
493 methodValue = instance[ options ].apply( instance, args );
494 if ( methodValue !== instance && methodValue !== undefined ) {
495 returnValue = methodValue && methodValue.jquery ?
496 returnValue.pushStack( methodValue.get() ) :
497 methodValue;
498 return false;
499 }
500 });
501 } else {
502 this.each(function() {
503 var instance = $.data( this, fullName );
504 if ( instance ) {
505 instance.option( options || {} )._init();
506 } else {
507 $.data( this, fullName, new object( options, this ) );
508 }
509 });
510 }
511
512 return returnValue;
513 };
514 };
515
516 $.Widget = function( /* options, element */ ) {};
517 $.Widget._childConstructors = [];
518
519 $.Widget.prototype = {
520 widgetName: "widget",
521 widgetEventPrefix: "",
522 defaultElement: "<div>",
523 options: {
524 disabled: false,
525
526 // callbacks
527 create: null
528 },
529 _createWidget: function( options, element ) {
530 element = $( element || this.defaultElement || this )[ 0 ];
531 this.element = $( element );
532 this.uuid = uuid++;
533 this.eventNamespace = "." + this.widgetName + this.uuid;
534 this.options = $.widget.extend( {},
535 this.options,
536 this._getCreateOptions(),
537 options );
538
539 this.bindings = $();
540 this.hoverable = $();
541 this.focusable = $();
542
543 if ( element !== this ) {
544 $.data( element, this.widgetFullName, this );
545 this._on( true, this.element, {
546 remove: function( event ) {
547 if ( event.target === element ) {
548 this.destroy();
549 }
550 }
551 });
552 this.document = $( element.style ?
553 // element within the document
554 element.ownerDocument :
555 // element is window or document
556 element.document || element );
557 this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
558 }
559
560 this._create();
561 this._trigger( "create", null, this._getCreateEventData() );
562 this._init();
563 },
564 _getCreateOptions: $.noop,
565 _getCreateEventData: $.noop,
566 _create: $.noop,
567 _init: $.noop,
568
569 destroy: function() {
570 this._destroy();
571 // we can probably remove the unbind calls in 2.0
572 // all event bindings should go through this._on()
573 this.element
574 .unbind( this.eventNamespace )
575 // 1.9 BC for #7810
576 // TODO remove dual storage
577 .removeData( this.widgetName )
578 .removeData( this.widgetFullName )
579 // support: jquery <1.6.3
580 // http://bugs.jquery.com/ticket/9413
581 .removeData( $.camelCase( this.widgetFullName ) );
582 this.widget()
583 .unbind( this.eventNamespace )
584 .removeAttr( "aria-disabled" )
585 .removeClass(
586 this.widgetFullName + "-disabled " +
587 "ui-state-disabled" );
588
589 // clean up events and states
590 this.bindings.unbind( this.eventNamespace );
591 this.hoverable.removeClass( "ui-state-hover" );
592 this.focusable.removeClass( "ui-state-focus" );
593 },
594 _destroy: $.noop,
595
596 widget: function() {
597 return this.element;
598 },
599
600 option: function( key, value ) {
601 var options = key,
602 parts,
603 curOption,
604 i;
605
606 if ( arguments.length === 0 ) {
607 // don't return a reference to the internal hash
608 return $.widget.extend( {}, this.options );
609 }
610
611 if ( typeof key === "string" ) {
612 // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
613 options = {};
614 parts = key.split( "." );
615 key = parts.shift();
616 if ( parts.length ) {
617 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
618 for ( i = 0; i < parts.length - 1; i++ ) {
619 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
620 curOption = curOption[ parts[ i ] ];
621 }
622 key = parts.pop();
623 if ( value === undefined ) {
624 return curOption[ key ] === undefined ? null : curOption[ key ];
625 }
626 curOption[ key ] = value;
627 } else {
628 if ( value === undefined ) {
629 return this.options[ key ] === undefined ? null : this.options[ key ];
630 }
631 options[ key ] = value;
632 }
633 }
634
635 this._setOptions( options );
636
637 return this;
638 },
639 _setOptions: function( options ) {
640 var key;
641
642 for ( key in options ) {
643 this._setOption( key, options[ key ] );
644 }
645
646 return this;
647 },
648 _setOption: function( key, value ) {
649 this.options[ key ] = value;
650
651 if ( key === "disabled" ) {
652 this.widget()
653 .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value )
654 .attr( "aria-disabled", value );
655 this.hoverable.removeClass( "ui-state-hover" );
656 this.focusable.removeClass( "ui-state-focus" );
657 }
658
659 return this;
660 },
661
662 enable: function() {
663 return this._setOption( "disabled", false );
664 },
665 disable: function() {
666 return this._setOption( "disabled", true );
667 },
668
669 _on: function( suppressDisabledCheck, element, handlers ) {
670 var delegateElement,
671 instance = this;
672
673 // no suppressDisabledCheck flag, shuffle arguments
674 if ( typeof suppressDisabledCheck !== "boolean" ) {
675 handlers = element;
676 element = suppressDisabledCheck;
677 suppressDisabledCheck = false;
678 }
679
680 // no element argument, shuffle and use this.element
681 if ( !handlers ) {
682 handlers = element;
683 element = this.element;
684 delegateElement = this.widget();
685 } else {
686 // accept selectors, DOM elements
687 element = delegateElement = $( element );
688 this.bindings = this.bindings.add( element );
689 }
690
691 $.each( handlers, function( event, handler ) {
692 function handlerProxy() {
693 // allow widgets to customize the disabled handling
694 // - disabled as an array instead of boolean
695 // - disabled class as method for disabling individual parts
696 if ( !suppressDisabledCheck &&
697 ( instance.options.disabled === true ||
698 $( this ).hasClass( "ui-state-disabled" ) ) ) {
699 return;
700 }
701 return ( typeof handler === "string" ? instance[ handler ] : handler )
702 .apply( instance, arguments );
703 }
704
705 // copy the guid so direct unbinding works
706 if ( typeof handler !== "string" ) {
707 handlerProxy.guid = handler.guid =
708 handler.guid || handlerProxy.guid || $.guid++;
709 }
710
711 var match = event.match( /^(\w+)\s*(.*)$/ ),
712 eventName = match[1] + instance.eventNamespace,
713 selector = match[2];
714 if ( selector ) {
715 delegateElement.delegate( selector, eventName, handlerProxy );
716 } else {
717 element.bind( eventName, handlerProxy );
718 }
719 });
720 },
721
722 _off: function( element, eventName ) {
723 eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
724 element.unbind( eventName ).undelegate( eventName );
725 },
726
727 _delay: function( handler, delay ) {
728 function handlerProxy() {
729 return ( typeof handler === "string" ? instance[ handler ] : handler )
730 .apply( instance, arguments );
731 }
732 var instance = this;
733 return setTimeout( handlerProxy, delay || 0 );
734 },
735
736 _hoverable: function( element ) {
737 this.hoverable = this.hoverable.add( element );
738 this._on( element, {
739 mouseenter: function( event ) {
740 $( event.currentTarget ).addClass( "ui-state-hover" );
741 },
742 mouseleave: function( event ) {
743 $( event.currentTarget ).removeClass( "ui-state-hover" );
744 }
745 });
746 },
747
748 _focusable: function( element ) {
749 this.focusable = this.focusable.add( element );
750 this._on( element, {
751 focusin: function( event ) {
752 $( event.currentTarget ).addClass( "ui-state-focus" );
753 },
754 focusout: function( event ) {
755 $( event.currentTarget ).removeClass( "ui-state-focus" );
756 }
757 });
758 },
759
760 _trigger: function( type, event, data ) {
761 var prop, orig,
762 callback = this.options[ type ];
763
764 data = data || {};
765 event = $.Event( event );
766 event.type = ( type === this.widgetEventPrefix ?
767 type :
768 this.widgetEventPrefix + type ).toLowerCase();
769 // the original event may come from any element
770 // so we need to reset the target on the new event
771 event.target = this.element[ 0 ];
772
773 // copy original event properties over to the new event
774 orig = event.originalEvent;
775 if ( orig ) {
776 for ( prop in orig ) {
777 if ( !( prop in event ) ) {
778 event[ prop ] = orig[ prop ];
779 }
780 }
781 }
782
783 this.element.trigger( event, data );
784 return !( $.isFunction( callback ) &&
785 callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
786 event.isDefaultPrevented() );
787 }
788 };
789
790 $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
791 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
792 if ( typeof options === "string" ) {
793 options = { effect: options };
794 }
795 var hasOptions,
796 effectName = !options ?
797 method :
798 options === true || typeof options === "number" ?
799 defaultEffect :
800 options.effect || defaultEffect;
801 options = options || {};
802 if ( typeof options === "number" ) {
803 options = { duration: options };
804 }
805 hasOptions = !$.isEmptyObject( options );
806 options.complete = callback;
807 if ( options.delay ) {
808 element.delay( options.delay );
809 }
810 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
811 element[ method ]( options );
812 } else if ( effectName !== method && element[ effectName ] ) {
813 element[ effectName ]( options.duration, options.easing, callback );
814 } else {
815 element.queue(function( next ) {
816 $( this )[ method ]();
817 if ( callback ) {
818 callback.call( element[ 0 ] );
819 }
820 next();
821 });
822 }
823 };
824 });
825
826 })( jQuery );
827 (function( $, undefined ) {
828
829 var mouseHandled = false;
830 $( document ).mouseup( function() {
831 mouseHandled = false;
832 });
833
834 $.widget("ui.mouse", {
835 version: "1.10.3",
836 options: {
837 cancel: "input,textarea,button,select,option",
838 distance: 1,
839 delay: 0
840 },
841 _mouseInit: function() {
842 var that = this;
843
844 this.element
845 .bind("mousedown."+this.widgetName, function(event) {
846 return that._mouseDown(event);
847 })
848 .bind("click."+this.widgetName, function(event) {
849 if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) {
850 $.removeData(event.target, that.widgetName + ".preventClickEvent");
851 event.stopImmediatePropagation();
852 return false;
853 }
854 });
855
856 this.started = false;
857 },
858
859 // TODO: make sure destroying one instance of mouse doesn't mess with
860 // other instances of mouse
861 _mouseDestroy: function() {
862 this.element.unbind("."+this.widgetName);
863 if ( this._mouseMoveDelegate ) {
864 $(document)
865 .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate)
866 .unbind("mouseup."+this.widgetName, this._mouseUpDelegate);
867 }
868 },
869
870 _mouseDown: function(event) {
871 // don't let more than one widget handle mouseStart
872 if( mouseHandled ) { return; }
873
874 // we may have missed mouseup (out of window)
875 (this._mouseStarted && this._mouseUp(event));
876
877 this._mouseDownEvent = event;
878
879 var that = this,
880 btnIsLeft = (event.which === 1),
881 // event.target.nodeName works around a bug in IE 8 with
882 // disabled inputs (#7620)
883 elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
884 if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
885 return true;
886 }
887
888 this.mouseDelayMet = !this.options.delay;
889 if (!this.mouseDelayMet) {
890 this._mouseDelayTimer = setTimeout(function() {
891 that.mouseDelayMet = true;
892 }, this.options.delay);
893 }
894
895 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
896 this._mouseStarted = (this._mouseStart(event) !== false);
897 if (!this._mouseStarted) {
898 event.preventDefault();
899 return true;
900 }
901 }
902
903 // Click event may never have fired (Gecko & Opera)
904 if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) {
905 $.removeData(event.target, this.widgetName + ".preventClickEvent");
906 }
907
908 // these delegates are required to keep context
909 this._mouseMoveDelegate = function(event) {
910 return that._mouseMove(event);
911 };
912 this._mouseUpDelegate = function(event) {
913 return that._mouseUp(event);
914 };
915 $(document)
916 .bind("mousemove."+this.widgetName, this._mouseMoveDelegate)
917 .bind("mouseup."+this.widgetName, this._mouseUpDelegate);
918
919 event.preventDefault();
920
921 mouseHandled = true;
922 return true;
923 },
924
925 _mouseMove: function(event) {
926 // IE mouseup check - mouseup happened when mouse was out of window
927 if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) {
928 return this._mouseUp(event);
929 }
930
931 if (this._mouseStarted) {
932 this._mouseDrag(event);
933 return event.preventDefault();
934 }
935
936 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
937 this._mouseStarted =
938 (this._mouseStart(this._mouseDownEvent, event) !== false);
939 (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
940 }
941
942 return !this._mouseStarted;
943 },
944
945 _mouseUp: function(event) {
946 $(document)
947 .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate)
948 .unbind("mouseup."+this.widgetName, this._mouseUpDelegate);
949
950 if (this._mouseStarted) {
951 this._mouseStarted = false;
952
953 if (event.target === this._mouseDownEvent.target) {
954 $.data(event.target, this.widgetName + ".preventClickEvent", true);
955 }
956
957 this._mouseStop(event);
958 }
959
960 return false;
961 },
962
963 _mouseDistanceMet: function(event) {
964 return (Math.max(
965 Math.abs(this._mouseDownEvent.pageX - event.pageX),
966 Math.abs(this._mouseDownEvent.pageY - event.pageY)
967 ) >= this.options.distance
968 );
969 },
970
971 _mouseDelayMet: function(/* event */) {
972 return this.mouseDelayMet;
973 },
974
975 // These are placeholder methods, to be overriden by extending plugin
976 _mouseStart: function(/* event */) {},
977 _mouseDrag: function(/* event */) {},
978 _mouseStop: function(/* event */) {},
979 _mouseCapture: function(/* event */) { return true; }
980 });
981
982 })(jQuery);
983 (function( $, undefined ) {
984
985 /*jshint loopfunc: true */
986
987 function isOverAxis( x, reference, size ) {
988 return ( x > reference ) && ( x < ( reference + size ) );
989 }
990
991 function isFloating(item) {
992 return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display"));
993 }
994
995 $.widget("ui.sortable", $.ui.mouse, {
996 version: "1.10.3",
997 widgetEventPrefix: "sort",
998 ready: false,
999 options: {
1000 appendTo: "parent",
1001 axis: false,
1002 connectWith: false,
1003 containment: false,
1004 cursor: "auto",
1005 cursorAt: false,
1006 dropOnEmpty: true,
1007 forcePlaceholderSize: false,
1008 forceHelperSize: false,
1009 grid: false,
1010 handle: false,
1011 helper: "original",
1012 items: "> *",
1013 opacity: false,
1014 placeholder: false,
1015 revert: false,
1016 scroll: true,
1017 scrollSensitivity: 20,
1018 scrollSpeed: 20,
1019 scope: "default",
1020 tolerance: "intersect",
1021 zIndex: 1000,
1022
1023 // callbacks
1024 activate: null,
1025 beforeStop: null,
1026 change: null,
1027 deactivate: null,
1028 out: null,
1029 over: null,
1030 receive: null,
1031 remove: null,
1032 sort: null,
1033 start: null,
1034 stop: null,
1035 update: null
1036 },
1037 _create: function() {
1038
1039 var o = this.options;
1040 this.containerCache = {};
1041 this.element.addClass("ui-sortable");
1042
1043 //Get the items
1044 this.refresh();
1045
1046 //Let's determine if the items are being displayed horizontally
1047 this.floating = this.items.length ? o.axis === "x" || isFloating(this.items[0].item) : false;
1048
1049 //Let's determine the parent's offset
1050 this.offset = this.element.offset();
1051
1052 //Initialize mouse events for interaction
1053 this._mouseInit();
1054
1055 //We're ready to go
1056 this.ready = true;
1057
1058 },
1059
1060 _destroy: function() {
1061 this.element
1062 .removeClass("ui-sortable ui-sortable-disabled");
1063 this._mouseDestroy();
1064
1065 for ( var i = this.items.length - 1; i >= 0; i-- ) {
1066 this.items[i].item.removeData(this.widgetName + "-item");
1067 }
1068
1069 return this;
1070 },
1071
1072 _setOption: function(key, value){
1073 if ( key === "disabled" ) {
1074 this.options[ key ] = value;
1075
1076 this.widget().toggleClass( "ui-sortable-disabled", !!value );
1077 } else {
1078 // Don't call widget base _setOption for disable as it adds ui-state-disabled class
1079 $.Widget.prototype._setOption.apply(this, arguments);
1080 }
1081 },
1082
1083 _mouseCapture: function(event, overrideHandle) {
1084 var currentItem = null,
1085 validHandle = false,
1086 that = this;
1087
1088 if (this.reverting) {
1089 return false;
1090 }
1091
1092 if(this.options.disabled || this.options.type === "static") {
1093 return false;
1094 }
1095
1096 //We have to refresh the items data once first
1097 this._refreshItems(event);
1098
1099 //Find out if the clicked node (or one of its parents) is a actual item in this.items
1100 $(event.target).parents().each(function() {
1101 if($.data(this, that.widgetName + "-item") === that) {
1102 currentItem = $(this);
1103 return false;
1104 }
1105 });
1106 if($.data(event.target, that.widgetName + "-item") === that) {
1107 currentItem = $(event.target);
1108 }
1109
1110 if(!currentItem) {
1111 return false;
1112 }
1113 if(this.options.handle && !overrideHandle) {
1114 $(this.options.handle, currentItem).find("*").addBack().each(function() {
1115 if(this === event.target) {
1116 validHandle = true;
1117 }
1118 });
1119 if(!validHandle) {
1120 return false;
1121 }
1122 }
1123
1124 this.currentItem = currentItem;
1125 this._removeCurrentsFromItems();
1126 return true;
1127
1128 },
1129
1130 _mouseStart: function(event, overrideHandle, noActivation) {
1131
1132 var i, body,
1133 o = this.options;
1134
1135 this.currentContainer = this;
1136
1137 //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
1138 this.refreshPositions();
1139
1140 //Create and append the visible helper
1141 this.helper = this._createHelper(event);
1142
1143 //Cache the helper size
1144 this._cacheHelperProportions();
1145
1146 /*
1147 * - Position generation -
1148 * This block generates everything position related - it's the core of draggables.
1149 */
1150
1151 //Cache the margins of the original element
1152 this._cacheMargins();
1153
1154 //Get the next scrolling parent
1155 this.scrollParent = this.helper.scrollParent();
1156
1157 //The element's absolute position on the page minus margins
1158 this.offset = this.currentItem.offset();
1159 this.offset = {
1160 top: this.offset.top - this.margins.top,
1161 left: this.offset.left - this.margins.left
1162 };
1163
1164 $.extend(this.offset, {
1165 click: { //Where the click happened, relative to the element
1166 left: event.pageX - this.offset.left,
1167 top: event.pageY - this.offset.top
1168 },
1169 parent: this._getParentOffset(),
1170 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
1171 });
1172
1173 // Only after we got the offset, we can change the helper's position to absolute
1174 // TODO: Still need to figure out a way to make relative sorting possible
1175 this.helper.css("position", "absolute");
1176 this.cssPosition = this.helper.css("position");
1177
1178 //Generate the original position
1179 this.originalPosition = this._generatePosition(event);
1180 this.originalPageX = event.pageX;
1181 this.originalPageY = event.pageY;
1182
1183 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
1184 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
1185
1186 //Cache the former DOM position
1187 this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
1188
1189 //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
1190 if(this.helper[0] !== this.currentItem[0]) {
1191 this.currentItem.hide();
1192 }
1193
1194 //Create the placeholder
1195 this._createPlaceholder();
1196
1197 //Set a containment if given in the options
1198 if(o.containment) {
1199 this._setContainment();
1200 }
1201
1202 if( o.cursor && o.cursor !== "auto" ) { // cursor option
1203 body = this.document.find( "body" );
1204
1205 // support: IE
1206 this.storedCursor = body.css( "cursor" );
1207 body.css( "cursor", o.cursor );
1208
1209 this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body );
1210 }
1211
1212 if(o.opacity) { // opacity option
1213 if (this.helper.css("opacity")) {
1214 this._storedOpacity = this.helper.css("opacity");
1215 }
1216 this.helper.css("opacity", o.opacity);
1217 }
1218
1219 if(o.zIndex) { // zIndex option
1220 if (this.helper.css("zIndex")) {
1221 this._storedZIndex = this.helper.css("zIndex");
1222 }
1223 this.helper.css("zIndex", o.zIndex);
1224 }
1225
1226 //Prepare scrolling
1227 if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
1228 this.overflowOffset = this.scrollParent.offset();
1229 }
1230
1231 //Call callbacks
1232 this._trigger("start", event, this._uiHash());
1233
1234 //Recache the helper size
1235 if(!this._preserveHelperProportions) {
1236 this._cacheHelperProportions();
1237 }
1238
1239
1240 //Post "activate" events to possible containers
1241 if( !noActivation ) {
1242 for ( i = this.containers.length - 1; i >= 0; i-- ) {
1243 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
1244 }
1245 }
1246
1247 //Prepare possible droppables
1248 if($.ui.ddmanager) {
1249 $.ui.ddmanager.current = this;
1250 }
1251
1252 if ($.ui.ddmanager && !o.dropBehaviour) {
1253 $.ui.ddmanager.prepareOffsets(this, event);
1254 }
1255
1256 this.dragging = true;
1257
1258 this.helper.addClass("ui-sortable-helper");
1259 this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
1260 return true;
1261
1262 },
1263
1264 _mouseDrag: function(event) {
1265 var i, item, itemElement, intersection,
1266 o = this.options,
1267 scrolled = false;
1268
1269 //Compute the helpers position
1270 this.position = this._generatePosition(event);
1271 this.positionAbs = this._convertPositionTo("absolute");
1272
1273 if (!this.lastPositionAbs) {
1274 this.lastPositionAbs = this.positionAbs;
1275 }
1276
1277 //Do scrolling
1278 if(this.options.scroll) {
1279 if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
1280
1281 if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
1282 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
1283 } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
1284 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
1285 }
1286
1287 if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
1288 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
1289 } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
1290 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
1291 }
1292
1293 } else {
1294
1295 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
1296 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
1297 } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
1298 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
1299 }
1300
1301 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
1302 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
1303 } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
1304 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
1305 }
1306
1307 }
1308
1309 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
1310 $.ui.ddmanager.prepareOffsets(this, event);
1311 }
1312 }
1313
1314 //Regenerate the absolute position used for position checks
1315 this.positionAbs = this._convertPositionTo("absolute");
1316
1317 //Set the helper position
1318 if(!this.options.axis || this.options.axis !== "y") {
1319 this.helper[0].style.left = this.position.left+"px";
1320 }
1321 if(!this.options.axis || this.options.axis !== "x") {
1322 this.helper[0].style.top = this.position.top+"px";
1323 }
1324
1325 //Rearrange
1326 for (i = this.items.length - 1; i >= 0; i--) {
1327
1328 //Cache variables and intersection, continue if no intersection
1329 item = this.items[i];
1330 itemElement = item.item[0];
1331 intersection = this._intersectsWithPointer(item);
1332 if (!intersection) {
1333 continue;
1334 }
1335
1336 // Only put the placeholder inside the current Container, skip all
1337 // items form other containers. This works because when moving
1338 // an item from one container to another the
1339 // currentContainer is switched before the placeholder is moved.
1340 //
1341 // Without this moving items in "sub-sortables" can cause the placeholder to jitter
1342 // beetween the outer and inner container.
1343 if (item.instance !== this.currentContainer) {
1344 continue;
1345 }
1346
1347 // cannot intersect with itself
1348 // no useless actions that have been done before
1349 // no action if the item moved is the parent of the item checked
1350 if (itemElement !== this.currentItem[0] &&
1351 this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement &&
1352 !$.contains(this.placeholder[0], itemElement) &&
1353 (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true)
1354 ) {
1355
1356 this.direction = intersection === 1 ? "down" : "up";
1357
1358 if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
1359 this._rearrange(event, item);
1360 } else {
1361 break;
1362 }
1363
1364 this._trigger("change", event, this._uiHash());
1365 break;
1366 }
1367 }
1368
1369 //Post events to containers
1370 this._contactContainers(event);
1371
1372 //Interconnect with droppables
1373 if($.ui.ddmanager) {
1374 $.ui.ddmanager.drag(this, event);
1375 }
1376
1377 //Call callbacks
1378 this._trigger("sort", event, this._uiHash());
1379
1380 this.lastPositionAbs = this.positionAbs;
1381 return false;
1382
1383 },
1384
1385 _mouseStop: function(event, noPropagation) {
1386
1387 if(!event) {
1388 return;
1389 }
1390
1391 //If we are using droppables, inform the manager about the drop
1392 if ($.ui.ddmanager && !this.options.dropBehaviour) {
1393 $.ui.ddmanager.drop(this, event);
1394 }
1395
1396 if(this.options.revert) {
1397 var that = this,
1398 cur = this.placeholder.offset(),
1399 axis = this.options.axis,
1400 animation = {};
1401
1402 if ( !axis || axis === "x" ) {
1403 animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft);
1404 }
1405 if ( !axis || axis === "y" ) {
1406 animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop);
1407 }
1408 this.reverting = true;
1409 $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() {
1410 that._clear(event);
1411 });
1412 } else {
1413 this._clear(event, noPropagation);
1414 }
1415
1416 return false;
1417
1418 },
1419
1420 cancel: function() {
1421
1422 if(this.dragging) {
1423
1424 this._mouseUp({ target: null });
1425
1426 if(this.options.helper === "original") {
1427 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
1428 } else {
1429 this.currentItem.show();
1430 }
1431
1432 //Post deactivating events to containers
1433 for (var i = this.containers.length - 1; i >= 0; i--){
1434 this.containers[i]._trigger("deactivate", null, this._uiHash(this));
1435 if(this.containers[i].containerCache.over) {
1436 this.containers[i]._trigger("out", null, this._uiHash(this));
1437 this.containers[i].containerCache.over = 0;
1438 }
1439 }
1440
1441 }
1442
1443 if (this.placeholder) {
1444 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
1445 if(this.placeholder[0].parentNode) {
1446 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
1447 }
1448 if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) {
1449 this.helper.remove();
1450 }
1451
1452 $.extend(this, {
1453 helper: null,
1454 dragging: false,
1455 reverting: false,
1456 _noFinalSort: null
1457 });
1458
1459 if(this.domPosition.prev) {
1460 $(this.domPosition.prev).after(this.currentItem);
1461 } else {
1462 $(this.domPosition.parent).prepend(this.currentItem);
1463 }
1464 }
1465
1466 return this;
1467
1468 },
1469
1470 serialize: function(o) {
1471
1472 var items = this._getItemsAsjQuery(o && o.connected),
1473 str = [];
1474 o = o || {};
1475
1476 $(items).each(function() {
1477 var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/));
1478 if (res) {
1479 str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2]));
1480 }
1481 });
1482
1483 if(!str.length && o.key) {
1484 str.push(o.key + "=");
1485 }
1486
1487 return str.join("&");
1488
1489 },
1490
1491 toArray: function(o) {
1492
1493 var items = this._getItemsAsjQuery(o && o.connected),
1494 ret = [];
1495
1496 o = o || {};
1497
1498 items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); });
1499 return ret;
1500
1501 },
1502
1503 /* Be careful with the following core functions */
1504 _intersectsWith: function(item) {
1505
1506 var x1 = this.positionAbs.left,
1507 x2 = x1 + this.helperProportions.width,
1508 y1 = this.positionAbs.top,
1509 y2 = y1 + this.helperProportions.height,
1510 l = item.left,
1511 r = l + item.width,
1512 t = item.top,
1513 b = t + item.height,
1514 dyClick = this.offset.click.top,
1515 dxClick = this.offset.click.left,
1516 isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ),
1517 isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ),
1518 isOverElement = isOverElementHeight && isOverElementWidth;
1519
1520 if ( this.options.tolerance === "pointer" ||
1521 this.options.forcePointerForContainers ||
1522 (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"])
1523 ) {
1524 return isOverElement;
1525 } else {
1526
1527 return (l < x1 + (this.helperProportions.width / 2) && // Right Half
1528 x2 - (this.helperProportions.width / 2) < r && // Left Half
1529 t < y1 + (this.helperProportions.height / 2) && // Bottom Half
1530 y2 - (this.helperProportions.height / 2) < b ); // Top Half
1531
1532 }
1533 },
1534
1535 _intersectsWithPointer: function(item) {
1536
1537 var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
1538 isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
1539 isOverElement = isOverElementHeight && isOverElementWidth,
1540 verticalDirection = this._getDragVerticalDirection(),
1541 horizontalDirection = this._getDragHorizontalDirection();
1542
1543 if (!isOverElement) {
1544 return false;
1545 }
1546
1547 return this.floating ?
1548 ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 )
1549 : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) );
1550
1551 },
1552
1553 _intersectsWithSides: function(item) {
1554
1555 var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
1556 isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
1557 verticalDirection = this._getDragVerticalDirection(),
1558 horizontalDirection = this._getDragHorizontalDirection();
1559
1560 if (this.floating && horizontalDirection) {
1561 return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf));
1562 } else {
1563 return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf));
1564 }
1565
1566 },
1567
1568 _getDragVerticalDirection: function() {
1569 var delta = this.positionAbs.top - this.lastPositionAbs.top;
1570 return delta !== 0 && (delta > 0 ? "down" : "up");
1571 },
1572
1573 _getDragHorizontalDirection: function() {
1574 var delta = this.positionAbs.left - this.lastPositionAbs.left;
1575 return delta !== 0 && (delta > 0 ? "right" : "left");
1576 },
1577
1578 refresh: function(event) {
1579 this._refreshItems(event);
1580 this.refreshPositions();
1581 return this;
1582 },
1583
1584 _connectWith: function() {
1585 var options = this.options;
1586 return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith;
1587 },
1588
1589 _getItemsAsjQuery: function(connected) {
1590
1591 var i, j, cur, inst,
1592 items = [],
1593 queries = [],
1594 connectWith = this._connectWith();
1595
1596 if(connectWith && connected) {
1597 for (i = connectWith.length - 1; i >= 0; i--){
1598 cur = $(connectWith[i]);
1599 for ( j = cur.length - 1; j >= 0; j--){
1600 inst = $.data(cur[j], this.widgetFullName);
1601 if(inst && inst !== this && !inst.options.disabled) {
1602 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]);
1603 }
1604 }
1605 }
1606 }
1607
1608 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]);
1609
1610 for (i = queries.length - 1; i >= 0; i--){
1611 queries[i][0].each(function() {
1612 items.push(this);
1613 });
1614 }
1615
1616 return $(items);
1617
1618 },
1619
1620 _removeCurrentsFromItems: function() {
1621
1622 var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
1623
1624 this.items = $.grep(this.items, function (item) {
1625 for (var j=0; j < list.length; j++) {
1626 if(list[j] === item.item[0]) {
1627 return false;
1628 }
1629 }
1630 return true;
1631 });
1632
1633 },
1634
1635 _refreshItems: function(event) {
1636
1637 this.items = [];
1638 this.containers = [this];
1639
1640 var i, j, cur, inst, targetData, _queries, item, queriesLength,
1641 items = this.items,
1642 queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]],
1643 connectWith = this._connectWith();
1644
1645 if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
1646 for (i = connectWith.length - 1; i >= 0; i--){
1647 cur = $(connectWith[i]);
1648 for (j = cur.length - 1; j >= 0; j--){
1649 inst = $.data(cur[j], this.widgetFullName);
1650 if(inst && inst !== this && !inst.options.disabled) {
1651 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
1652 this.containers.push(inst);
1653 }
1654 }
1655 }
1656 }
1657
1658 for (i = queries.length - 1; i >= 0; i--) {
1659 targetData = queries[i][1];
1660 _queries = queries[i][0];
1661
1662 for (j=0, queriesLength = _queries.length; j < queriesLength; j++) {
1663 item = $(_queries[j]);
1664
1665 item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager)
1666
1667 items.push({
1668 item: item,
1669 instance: targetData,
1670 width: 0, height: 0,
1671 left: 0, top: 0
1672 });
1673 }
1674 }
1675
1676 },
1677
1678 refreshPositions: function(fast) {
1679
1680 //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
1681 if(this.offsetParent && this.helper) {
1682 this.offset.parent = this._getParentOffset();
1683 }
1684
1685 var i, item, t, p;
1686
1687 for (i = this.items.length - 1; i >= 0; i--){
1688 item = this.items[i];
1689
1690 //We ignore calculating positions of all connected containers when we're not over them
1691 if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) {
1692 continue;
1693 }
1694
1695 t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
1696
1697 if (!fast) {
1698 item.width = t.outerWidth();
1699 item.height = t.outerHeight();
1700 }
1701
1702 p = t.offset();
1703 item.left = p.left;
1704 item.top = p.top;
1705 }
1706
1707 if(this.options.custom && this.options.custom.refreshContainers) {
1708 this.options.custom.refreshContainers.call(this);
1709 } else {
1710 for (i = this.containers.length - 1; i >= 0; i--){
1711 p = this.containers[i].element.offset();
1712 this.containers[i].containerCache.left = p.left;
1713 this.containers[i].containerCache.top = p.top;
1714 this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
1715 this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
1716 }
1717 }
1718
1719 return this;
1720 },
1721
1722 _createPlaceholder: function(that) {
1723 that = that || this;
1724 var className,
1725 o = that.options;
1726
1727 if(!o.placeholder || o.placeholder.constructor === String) {
1728 className = o.placeholder;
1729 o.placeholder = {
1730 element: function() {
1731
1732 var nodeName = that.currentItem[0].nodeName.toLowerCase(),
1733 element = $( "<" + nodeName + ">", that.document[0] )
1734 .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
1735 .removeClass("ui-sortable-helper");
1736
1737 if ( nodeName === "tr" ) {
1738 that.currentItem.children().each(function() {
1739 $( "<td>&#160;</td>", that.document[0] )
1740 .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
1741 .appendTo( element );
1742 });
1743 } else if ( nodeName === "img" ) {
1744 element.attr( "src", that.currentItem.attr( "src" ) );
1745 }
1746
1747 if ( !className ) {
1748 element.css( "visibility", "hidden" );
1749 }
1750
1751 return element;
1752 },
1753 update: function(container, p) {
1754
1755 // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
1756 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
1757 if(className && !o.forcePlaceholderSize) {
1758 return;
1759 }
1760
1761 //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
1762 if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); }
1763 if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); }
1764 }
1765 };
1766 }
1767
1768 //Create the placeholder
1769 that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));
1770
1771 //Append it after the actual current item
1772 that.currentItem.after(that.placeholder);
1773
1774 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
1775 o.placeholder.update(that, that.placeholder);
1776
1777 },
1778
1779 _contactContainers: function(event) {
1780 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom, floating,
1781 innermostContainer = null,
1782 innermostIndex = null;
1783
1784 // get innermost container that intersects with item
1785 for (i = this.containers.length - 1; i >= 0; i--) {
1786
1787 // never consider a container that's located within the item itself
1788 if($.contains(this.currentItem[0], this.containers[i].element[0])) {
1789 continue;
1790 }
1791
1792 if(this._intersectsWith(this.containers[i].containerCache)) {
1793
1794 // if we've already found a container and it's more "inner" than this, then continue
1795 if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) {
1796 continue;
1797 }
1798
1799 innermostContainer = this.containers[i];
1800 innermostIndex = i;
1801
1802 } else {
1803 // container doesn't intersect. trigger "out" event if necessary
1804 if(this.containers[i].containerCache.over) {
1805 this.containers[i]._trigger("out", event, this._uiHash(this));
1806 this.containers[i].containerCache.over = 0;
1807 }
1808 }
1809
1810 }
1811
1812 // if no intersecting containers found, return
1813 if(!innermostContainer) {
1814 return;
1815 }
1816
1817 // move the item into the container if it's not there already
1818 if(this.containers.length === 1) {
1819 if (!this.containers[innermostIndex].containerCache.over) {
1820 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
1821 this.containers[innermostIndex].containerCache.over = 1;
1822 }
1823 } else {
1824
1825 //When entering a new container, we will find the item with the least distance and append our item near it
1826 dist = 10000;
1827 itemWithLeastDistance = null;
1828 floating = innermostContainer.floating || isFloating(this.currentItem);
1829 posProperty = floating ? "left" : "top";
1830 sizeProperty = floating ? "width" : "height";
1831 base = this.positionAbs[posProperty] + this.offset.click[posProperty];
1832 for (j = this.items.length - 1; j >= 0; j--) {
1833 if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) {
1834 continue;
1835 }
1836 if(this.items[j].item[0] === this.currentItem[0]) {
1837 continue;
1838 }
1839 if (floating && !isOverAxis(this.positionAbs.top + this.offset.click.top, this.items[j].top, this.items[j].height)) {
1840 continue;
1841 }
1842 cur = this.items[j].item.offset()[posProperty];
1843 nearBottom = false;
1844 if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){
1845 nearBottom = true;
1846 cur += this.items[j][sizeProperty];
1847 }
1848
1849 if(Math.abs(cur - base) < dist) {
1850 dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j];
1851 this.direction = nearBottom ? "up": "down";
1852 }
1853 }
1854
1855 //Check if dropOnEmpty is enabled
1856 if(!itemWithLeastDistance && !this.options.dropOnEmpty) {
1857 return;
1858 }
1859
1860 if(this.currentContainer === this.containers[innermostIndex]) {
1861 return;
1862 }
1863
1864 itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
1865 this._trigger("change", event, this._uiHash());
1866 this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
1867 this.currentContainer = this.containers[innermostIndex];
1868
1869 //Update the placeholder
1870 this.options.placeholder.update(this.currentContainer, this.placeholder);
1871
1872 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
1873 this.containers[innermostIndex].containerCache.over = 1;
1874 }
1875
1876
1877 },
1878
1879 _createHelper: function(event) {
1880
1881 var o = this.options,
1882 helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem);
1883
1884 //Add the helper to the DOM if that didn't happen already
1885 if(!helper.parents("body").length) {
1886 $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
1887 }
1888
1889 if(helper[0] === this.currentItem[0]) {
1890 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") };
1891 }
1892
1893 if(!helper[0].style.width || o.forceHelperSize) {
1894 helper.width(this.currentItem.width());
1895 }
1896 if(!helper[0].style.height || o.forceHelperSize) {
1897 helper.height(this.currentItem.height());
1898 }
1899
1900 return helper;
1901
1902 },
1903
1904 _adjustOffsetFromHelper: function(obj) {
1905 if (typeof obj === "string") {
1906 obj = obj.split(" ");
1907 }
1908 if ($.isArray(obj)) {
1909 obj = {left: +obj[0], top: +obj[1] || 0};
1910 }
1911 if ("left" in obj) {
1912 this.offset.click.left = obj.left + this.margins.left;
1913 }
1914 if ("right" in obj) {
1915 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
1916 }
1917 if ("top" in obj) {
1918 this.offset.click.top = obj.top + this.margins.top;
1919 }
1920 if ("bottom" in obj) {
1921 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
1922 }
1923 },
1924
1925 _getParentOffset: function() {
1926
1927
1928 //Get the offsetParent and cache its position
1929 this.offsetParent = this.helper.offsetParent();
1930 var po = this.offsetParent.offset();
1931
1932 // This is a special case where we need to modify a offset calculated on start, since the following happened:
1933 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
1934 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
1935 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
1936 if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
1937 po.left += this.scrollParent.scrollLeft();
1938 po.top += this.scrollParent.scrollTop();
1939 }
1940
1941 // This needs to be actually done for all browsers, since pageX/pageY includes this information
1942 // with an ugly IE fix
1943 if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
1944 po = { top: 0, left: 0 };
1945 }
1946
1947 return {
1948 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
1949 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
1950 };
1951
1952 },
1953
1954 _getRelativeOffset: function() {
1955
1956 if(this.cssPosition === "relative") {
1957 var p = this.currentItem.position();
1958 return {
1959 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
1960 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
1961 };
1962 } else {
1963 return { top: 0, left: 0 };
1964 }
1965
1966 },
1967
1968 _cacheMargins: function() {
1969 this.margins = {
1970 left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
1971 top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
1972 };
1973 },
1974
1975 _cacheHelperProportions: function() {
1976 this.helperProportions = {
1977 width: this.helper.outerWidth(),
1978 height: this.helper.outerHeight()
1979 };
1980 },
1981
1982 _setContainment: function() {
1983
1984 var ce, co, over,
1985 o = this.options;
1986 if(o.containment === "parent") {
1987 o.containment = this.helper[0].parentNode;
1988 }
1989 if(o.containment === "document" || o.containment === "window") {
1990 this.containment = [
1991 0 - this.offset.relative.left - this.offset.parent.left,
1992 0 - this.offset.relative.top - this.offset.parent.top,
1993 $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left,
1994 ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
1995 ];
1996 }
1997
1998 if(!(/^(document|window|parent)$/).test(o.containment)) {
1999 ce = $(o.containment)[0];
2000 co = $(o.containment).offset();
2001 over = ($(ce).css("overflow") !== "hidden");
2002
2003 this.containment = [
2004 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
2005 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
2006 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,
2007 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
2008 ];
2009 }
2010
2011 },
2012
2013 _convertPositionTo: function(d, pos) {
2014
2015 if(!pos) {
2016 pos = this.position;
2017 }
2018 var mod = d === "absolute" ? 1 : -1,
2019 scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,
2020 scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
2021
2022 return {
2023 top: (
2024 pos.top + // The absolute mouse position
2025 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
2026 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
2027 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
2028 ),
2029 left: (
2030 pos.left + // The absolute mouse position
2031 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
2032 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
2033 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
2034 )
2035 };
2036
2037 },
2038
2039 _generatePosition: function(event) {
2040
2041 var top, left,
2042 o = this.options,
2043 pageX = event.pageX,
2044 pageY = event.pageY,
2045 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);
2046
2047 // This is another very weird special case that only happens for relative elements:
2048 // 1. If the css position is relative
2049 // 2. and the scroll parent is the document or similar to the offset parent
2050 // we have to refresh the relative offset during the scroll so there are no jumps
2051 if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) {
2052 this.offset.relative = this._getRelativeOffset();
2053 }
2054
2055 /*
2056 * - Position constraining -
2057 * Constrain the position to a mix of grid, containment.
2058 */
2059
2060 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
2061
2062 if(this.containment) {
2063 if(event.pageX - this.offset.click.left < this.containment[0]) {
2064 pageX = this.containment[0] + this.offset.click.left;
2065 }
2066 if(event.pageY - this.offset.click.top < this.containment[1]) {
2067 pageY = this.containment[1] + this.offset.click.top;
2068 }
2069 if(event.pageX - this.offset.click.left > this.containment[2]) {
2070 pageX = this.containment[2] + this.offset.click.left;
2071 }
2072 if(event.pageY - this.offset.click.top > this.containment[3]) {
2073 pageY = this.containment[3] + this.offset.click.top;
2074 }
2075 }
2076
2077 if(o.grid) {
2078 top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
2079 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;
2080
2081 left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
2082 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;
2083 }
2084
2085 }
2086
2087 return {
2088 top: (
2089 pageY - // The absolute mouse position
2090 this.offset.click.top - // Click offset (relative to the element)
2091 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
2092 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
2093 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
2094 ),
2095 left: (
2096 pageX - // The absolute mouse position
2097 this.offset.click.left - // Click offset (relative to the element)
2098 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
2099 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
2100 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
2101 )
2102 };
2103
2104 },
2105
2106 _rearrange: function(event, i, a, hardRefresh) {
2107
2108 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));
2109
2110 //Various things done here to improve the performance:
2111 // 1. we create a setTimeout, that calls refreshPositions
2112 // 2. on the instance, we have a counter variable, that get's higher after every append
2113 // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
2114 // 4. this lets only the last addition to the timeout stack through
2115 this.counter = this.counter ? ++this.counter : 1;
2116 var counter = this.counter;
2117
2118 this._delay(function() {
2119 if(counter === this.counter) {
2120 this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
2121 }
2122 });
2123
2124 },
2125
2126 _clear: function(event, noPropagation) {
2127
2128 this.reverting = false;
2129 // We delay all events that have to be triggered to after the point where the placeholder has been removed and
2130 // everything else normalized again
2131 var i,
2132 delayedTriggers = [];
2133
2134 // We first have to update the dom position of the actual currentItem
2135 // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
2136 if(!this._noFinalSort && this.currentItem.parent().length) {
2137 this.placeholder.before(this.currentItem);
2138 }
2139 this._noFinalSort = null;
2140
2141 if(this.helper[0] === this.currentItem[0]) {
2142 for(i in this._storedCSS) {
2143 if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") {
2144 this._storedCSS[i] = "";
2145 }
2146 }
2147 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
2148 } else {
2149 this.currentItem.show();
2150 }
2151
2152 if(this.fromOutside && !noPropagation) {
2153 delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
2154 }
2155 if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) {
2156 delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
2157 }
2158
2159 // Check if the items Container has Changed and trigger appropriate
2160 // events.
2161 if (this !== this.currentContainer) {
2162 if(!noPropagation) {
2163 delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
2164 delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
2165 delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
2166 }
2167 }
2168
2169
2170 //Post events to containers
2171 for (i = this.containers.length - 1; i >= 0; i--){
2172 if(!noPropagation) {
2173 delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
2174 }
2175 if(this.containers[i].containerCache.over) {
2176 delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
2177 this.containers[i].containerCache.over = 0;
2178 }
2179 }
2180
2181 //Do what was originally in plugins
2182 if ( this.storedCursor ) {
2183 this.document.find( "body" ).css( "cursor", this.storedCursor );
2184 this.storedStylesheet.remove();
2185 }
2186 if(this._storedOpacity) {
2187 this.helper.css("opacity", this._storedOpacity);
2188 }
2189 if(this._storedZIndex) {
2190 this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex);
2191 }
2192
2193 this.dragging = false;
2194 if(this.cancelHelperRemoval) {
2195 if(!noPropagation) {
2196 this._trigger("beforeStop", event, this._uiHash());
2197 for (i=0; i < delayedTriggers.length; i++) {
2198 delayedTriggers[i].call(this, event);
2199 } //Trigger all delayed events
2200 this._trigger("stop", event, this._uiHash());
2201 }
2202
2203 this.fromOutside = false;
2204 return false;
2205 }
2206
2207 if(!noPropagation) {
2208 this._trigger("beforeStop", event, this._uiHash());
2209 }
2210
2211 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
2212 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
2213
2214 if(this.helper[0] !== this.currentItem[0]) {
2215 this.helper.remove();
2216 }
2217 this.helper = null;
2218
2219 if(!noPropagation) {
2220 for (i=0; i < delayedTriggers.length; i++) {
2221 delayedTriggers[i].call(this, event);
2222 } //Trigger all delayed events
2223 this._trigger("stop", event, this._uiHash());
2224 }
2225
2226 this.fromOutside = false;
2227 return true;
2228
2229 },
2230
2231 _trigger: function() {
2232 if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
2233 this.cancel();
2234 }
2235 },
2236
2237 _uiHash: function(_inst) {
2238 var inst = _inst || this;
2239 return {
2240 helper: inst.helper,
2241 placeholder: inst.placeholder || $([]),
2242 position: inst.position,
2243 originalPosition: inst.originalPosition,
2244 offset: inst.positionAbs,
2245 item: inst.currentItem,
2246 sender: _inst ? _inst.element : null
2247 };
2248 }
2249
2250 });
2251
2252 })(jQuery);
2253 (function( $, undefined ) {
2254
2255 var uid = 0,
2256 hideProps = {},
2257 showProps = {};
2258
2259 hideProps.height = hideProps.paddingTop = hideProps.paddingBottom =
2260 hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide";
2261 showProps.height = showProps.paddingTop = showProps.paddingBottom =
2262 showProps.borderTopWidth = showProps.borderBottomWidth = "show";
2263
2264 $.widget( "ui.accordion", {
2265 version: "1.10.3",
2266 options: {
2267 active: 0,
2268 animate: {},
2269 collapsible: false,
2270 event: "click",
2271 header: "> li > :first-child,> :not(li):even",
2272 heightStyle: "auto",
2273 icons: {
2274 activeHeader: "ui-icon-triangle-1-s",
2275 header: "ui-icon-triangle-1-e"
2276 },
2277
2278 // callbacks
2279 activate: null,
2280 beforeActivate: null
2281 },
2282
2283 _create: function() {
2284 var options = this.options;
2285 this.prevShow = this.prevHide = $();
2286 this.element.addClass( "ui-accordion ui-widget ui-helper-reset" )
2287 // ARIA
2288 .attr( "role", "tablist" );
2289
2290 // don't allow collapsible: false and active: false / null
2291 if ( !options.collapsible && (options.active === false || options.active == null) ) {
2292 options.active = 0;
2293 }
2294
2295 this._processPanels();
2296 // handle negative values
2297 if ( options.active < 0 ) {
2298 options.active += this.headers.length;
2299 }
2300 this._refresh();
2301 },
2302
2303 _getCreateEventData: function() {
2304 return {
2305 header: this.active,
2306 panel: !this.active.length ? $() : this.active.next(),
2307 content: !this.active.length ? $() : this.active.next()
2308 };
2309 },
2310
2311 _createIcons: function() {
2312 var icons = this.options.icons;
2313 if ( icons ) {
2314 $( "<span>" )
2315 .addClass( "ui-accordion-header-icon ui-icon " + icons.header )
2316 .prependTo( this.headers );
2317 this.active.children( ".ui-accordion-header-icon" )
2318 .removeClass( icons.header )
2319 .addClass( icons.activeHeader );
2320 this.headers.addClass( "ui-accordion-icons" );
2321 }
2322 },
2323
2324 _destroyIcons: function() {
2325 this.headers
2326 .removeClass( "ui-accordion-icons" )
2327 .children( ".ui-accordion-header-icon" )
2328 .remove();
2329 },
2330
2331 _destroy: function() {
2332 var contents;
2333
2334 // clean up main element
2335 this.element
2336 .removeClass( "ui-accordion ui-widget ui-helper-reset" )
2337 .removeAttr( "role" );
2338
2339 // clean up headers
2340 this.headers
2341 .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" )
2342 .removeAttr( "role" )
2343 .removeAttr( "aria-selected" )
2344 .removeAttr( "aria-controls" )
2345 .removeAttr( "tabIndex" )
2346 .each(function() {
2347 if ( /^ui-accordion/.test( this.id ) ) {
2348 this.removeAttribute( "id" );
2349 }
2350 });
2351 this._destroyIcons();
2352
2353 // clean up content panels
2354 contents = this.headers.next()
2355 .css( "display", "" )
2356 .removeAttr( "role" )
2357 .removeAttr( "aria-expanded" )
2358 .removeAttr( "aria-hidden" )
2359 .removeAttr( "aria-labelledby" )
2360 .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" )
2361 .each(function() {
2362 if ( /^ui-accordion/.test( this.id ) ) {
2363 this.removeAttribute( "id" );
2364 }
2365 });
2366 if ( this.options.heightStyle !== "content" ) {
2367 contents.css( "height", "" );
2368 }
2369 },
2370
2371 _setOption: function( key, value ) {
2372 if ( key === "active" ) {
2373 // _activate() will handle invalid values and update this.options
2374 this._activate( value );
2375 return;
2376 }
2377
2378 if ( key === "event" ) {
2379 if ( this.options.event ) {
2380 this._off( this.headers, this.options.event );
2381 }
2382 this._setupEvents( value );
2383 }
2384
2385 this._super( key, value );
2386
2387 // setting collapsible: false while collapsed; open first panel
2388 if ( key === "collapsible" && !value && this.options.active === false ) {
2389 this._activate( 0 );
2390 }
2391
2392 if ( key === "icons" ) {
2393 this._destroyIcons();
2394 if ( value ) {
2395 this._createIcons();
2396 }
2397 }
2398
2399 // #5332 - opacity doesn't cascade to positioned elements in IE
2400 // so we need to add the disabled class to the headers and panels
2401 if ( key === "disabled" ) {
2402 this.headers.add( this.headers.next() )
2403 .toggleClass( "ui-state-disabled", !!value );
2404 }
2405 },
2406
2407 _keydown: function( event ) {
2408 /*jshint maxcomplexity:15*/
2409 if ( event.altKey || event.ctrlKey ) {
2410 return;
2411 }
2412
2413 var keyCode = $.ui.keyCode,
2414 length = this.headers.length,
2415 currentIndex = this.headers.index( event.target ),
2416 toFocus = false;
2417
2418 switch ( event.keyCode ) {
2419 case keyCode.RIGHT:
2420 case keyCode.DOWN:
2421 toFocus = this.headers[ ( currentIndex + 1 ) % length ];
2422 break;
2423 case keyCode.LEFT:
2424 case keyCode.UP:
2425 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
2426 break;
2427 case keyCode.SPACE:
2428 case keyCode.ENTER:
2429 this._eventHandler( event );
2430 break;
2431 case keyCode.HOME:
2432 toFocus = this.headers[ 0 ];
2433 break;
2434 case keyCode.END:
2435 toFocus = this.headers[ length - 1 ];
2436 break;
2437 }
2438
2439 if ( toFocus ) {
2440 $( event.target ).attr( "tabIndex", -1 );
2441 $( toFocus ).attr( "tabIndex", 0 );
2442 toFocus.focus();
2443 event.preventDefault();
2444 }
2445 },
2446
2447 _panelKeyDown : function( event ) {
2448 if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
2449 $( event.currentTarget ).prev().focus();
2450 }
2451 },
2452
2453 refresh: function() {
2454 var options = this.options;
2455 this._processPanels();
2456
2457 // was collapsed or no panel
2458 if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) {
2459 options.active = false;
2460 this.active = $();
2461 // active false only when collapsible is true
2462 } else if ( options.active === false ) {
2463 this._activate( 0 );
2464 // was active, but active panel is gone
2465 } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
2466 // all remaining panel are disabled
2467 if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) {
2468 options.active = false;
2469 this.active = $();
2470 // activate previous panel
2471 } else {
2472 this._activate( Math.max( 0, options.active - 1 ) );
2473 }
2474 // was active, active panel still exists
2475 } else {
2476 // make sure active index is correct
2477 options.active = this.headers.index( this.active );
2478 }
2479
2480 this._destroyIcons();
2481
2482 this._refresh();
2483 },
2484
2485 _processPanels: function() {
2486 this.headers = this.element.find( this.options.header )
2487 .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" );
2488
2489 this.headers.next()
2490 .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
2491 .filter(":not(.ui-accordion-content-active)")
2492 .hide();
2493 },
2494
2495 _refresh: function() {
2496 var maxHeight,
2497 options = this.options,
2498 heightStyle = options.heightStyle,
2499 parent = this.element.parent(),
2500 accordionId = this.accordionId = "ui-accordion-" +
2501 (this.element.attr( "id" ) || ++uid);
2502
2503 this.active = this._findActive( options.active )
2504 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" )
2505 .removeClass( "ui-corner-all" );
2506 this.active.next()
2507 .addClass( "ui-accordion-content-active" )
2508 .show();
2509
2510 this.headers
2511 .attr( "role", "tab" )
2512 .each(function( i ) {
2513 var header = $( this ),
2514 headerId = header.attr( "id" ),
2515 panel = header.next(),
2516 panelId = panel.attr( "id" );
2517 if ( !headerId ) {
2518 headerId = accordionId + "-header-" + i;
2519 header.attr( "id", headerId );
2520 }
2521 if ( !panelId ) {
2522 panelId = accordionId + "-panel-" + i;
2523 panel.attr( "id", panelId );
2524 }
2525 header.attr( "aria-controls", panelId );
2526 panel.attr( "aria-labelledby", headerId );
2527 })
2528 .next()
2529 .attr( "role", "tabpanel" );
2530
2531 this.headers
2532 .not( this.active )
2533 .attr({
2534 "aria-selected": "false",
2535 tabIndex: -1
2536 })
2537 .next()
2538 .attr({
2539 "aria-expanded": "false",
2540 "aria-hidden": "true"
2541 })
2542 .hide();
2543
2544 // make sure at least one header is in the tab order
2545 if ( !this.active.length ) {
2546 this.headers.eq( 0 ).attr( "tabIndex", 0 );
2547 } else {
2548 this.active.attr({
2549 "aria-selected": "true",
2550 tabIndex: 0
2551 })
2552 .next()
2553 .attr({
2554 "aria-expanded": "true",
2555 "aria-hidden": "false"
2556 });
2557 }
2558
2559 this._createIcons();
2560
2561 this._setupEvents( options.event );
2562
2563 if ( heightStyle === "fill" ) {
2564 maxHeight = parent.height();
2565 this.element.siblings( ":visible" ).each(function() {
2566 var elem = $( this ),
2567 position = elem.css( "position" );
2568
2569 if ( position === "absolute" || position === "fixed" ) {
2570 return;
2571 }
2572 maxHeight -= elem.outerHeight( true );
2573 });
2574
2575 this.headers.each(function() {
2576 maxHeight -= $( this ).outerHeight( true );
2577 });
2578
2579 this.headers.next()
2580 .each(function() {
2581 $( this ).height( Math.max( 0, maxHeight -
2582 $( this ).innerHeight() + $( this ).height() ) );
2583 })
2584 .css( "overflow", "auto" );
2585 } else if ( heightStyle === "auto" ) {
2586 maxHeight = 0;
2587 this.headers.next()
2588 .each(function() {
2589 maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
2590 })
2591 .height( maxHeight );
2592 }
2593 },
2594
2595 _activate: function( index ) {
2596 var active = this._findActive( index )[ 0 ];
2597
2598 // trying to activate the already active panel
2599 if ( active === this.active[ 0 ] ) {
2600 return;
2601 }
2602
2603 // trying to collapse, simulate a click on the currently active header
2604 active = active || this.active[ 0 ];
2605
2606 this._eventHandler({
2607 target: active,
2608 currentTarget: active,
2609 preventDefault: $.noop
2610 });
2611 },
2612
2613 _findActive: function( selector ) {
2614 return typeof selector === "number" ? this.headers.eq( selector ) : $();
2615 },
2616
2617 _setupEvents: function( event ) {
2618 var events = {
2619 keydown: "_keydown"
2620 };
2621 if ( event ) {
2622 $.each( event.split(" "), function( index, eventName ) {
2623 events[ eventName ] = "_eventHandler";
2624 });
2625 }
2626
2627 this._off( this.headers.add( this.headers.next() ) );
2628 this._on( this.headers, events );
2629 this._on( this.headers.next(), { keydown: "_panelKeyDown" });
2630 this._hoverable( this.headers );
2631 this._focusable( this.headers );
2632 },
2633
2634 _eventHandler: function( event ) {
2635 var options = this.options,
2636 active = this.active,
2637 clicked = $( event.currentTarget ),
2638 clickedIsActive = clicked[ 0 ] === active[ 0 ],
2639 collapsing = clickedIsActive && options.collapsible,
2640 toShow = collapsing ? $() : clicked.next(),
2641 toHide = active.next(),
2642 eventData = {
2643 oldHeader: active,
2644 oldPanel: toHide,
2645 newHeader: collapsing ? $() : clicked,
2646 newPanel: toShow
2647 };
2648
2649 event.preventDefault();
2650
2651 if (
2652 // click on active header, but not collapsible
2653 ( clickedIsActive && !options.collapsible ) ||
2654 // allow canceling activation
2655 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
2656 return;
2657 }
2658
2659 options.active = collapsing ? false : this.headers.index( clicked );
2660
2661 // when the call to ._toggle() comes after the class changes
2662 // it causes a very odd bug in IE 8 (see #6720)
2663 this.active = clickedIsActive ? $() : clicked;
2664 this._toggle( eventData );
2665
2666 // switch classes
2667 // corner classes on the previously active header stay after the animation
2668 active.removeClass( "ui-accordion-header-active ui-state-active" );
2669 if ( options.icons ) {
2670 active.children( ".ui-accordion-header-icon" )
2671 .removeClass( options.icons.activeHeader )
2672 .addClass( options.icons.header );
2673 }
2674
2675 if ( !clickedIsActive ) {
2676 clicked
2677 .removeClass( "ui-corner-all" )
2678 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" );
2679 if ( options.icons ) {
2680 clicked.children( ".ui-accordion-header-icon" )
2681 .removeClass( options.icons.header )
2682 .addClass( options.icons.activeHeader );
2683 }
2684
2685 clicked
2686 .next()
2687 .addClass( "ui-accordion-content-active" );
2688 }
2689 },
2690
2691 _toggle: function( data ) {
2692 var toShow = data.newPanel,
2693 toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
2694
2695 // handle activating a panel during the animation for another activation
2696 this.prevShow.add( this.prevHide ).stop( true, true );
2697 this.prevShow = toShow;
2698 this.prevHide = toHide;
2699
2700 if ( this.options.animate ) {
2701 this._animate( toShow, toHide, data );
2702 } else {
2703 toHide.hide();
2704 toShow.show();
2705 this._toggleComplete( data );
2706 }
2707
2708 toHide.attr({
2709 "aria-expanded": "false",
2710 "aria-hidden": "true"
2711 });
2712 toHide.prev().attr( "aria-selected", "false" );
2713 // if we're switching panels, remove the old header from the tab order
2714 // if we're opening from collapsed state, remove the previous header from the tab order
2715 // if we're collapsing, then keep the collapsing header in the tab order
2716 if ( toShow.length && toHide.length ) {
2717 toHide.prev().attr( "tabIndex", -1 );
2718 } else if ( toShow.length ) {
2719 this.headers.filter(function() {
2720 return $( this ).attr( "tabIndex" ) === 0;
2721 })
2722 .attr( "tabIndex", -1 );
2723 }
2724
2725 toShow
2726 .attr({
2727 "aria-expanded": "true",
2728 "aria-hidden": "false"
2729 })
2730 .prev()
2731 .attr({
2732 "aria-selected": "true",
2733 tabIndex: 0
2734 });
2735 },
2736
2737 _animate: function( toShow, toHide, data ) {
2738 var total, easing, duration,
2739 that = this,
2740 adjust = 0,
2741 down = toShow.length &&
2742 ( !toHide.length || ( toShow.index() < toHide.index() ) ),
2743 animate = this.options.animate || {},
2744 options = down && animate.down || animate,
2745 complete = function() {
2746 that._toggleComplete( data );
2747 };
2748
2749 if ( typeof options === "number" ) {
2750 duration = options;
2751 }
2752 if ( typeof options === "string" ) {
2753 easing = options;
2754 }
2755 // fall back from options to animation in case of partial down settings
2756 easing = easing || options.easing || animate.easing;
2757 duration = duration || options.duration || animate.duration;
2758
2759 if ( !toHide.length ) {
2760 return toShow.animate( showProps, duration, easing, complete );
2761 }
2762 if ( !toShow.length ) {
2763 return toHide.animate( hideProps, duration, easing, complete );
2764 }
2765
2766 total = toShow.show().outerHeight();
2767 toHide.animate( hideProps, {
2768 duration: duration,
2769 easing: easing,
2770 step: function( now, fx ) {
2771 fx.now = Math.round( now );
2772 }
2773 });
2774 toShow
2775 .hide()
2776 .animate( showProps, {
2777 duration: duration,
2778 easing: easing,
2779 complete: complete,
2780 step: function( now, fx ) {
2781 fx.now = Math.round( now );
2782 if ( fx.prop !== "height" ) {
2783 adjust += fx.now;
2784 } else if ( that.options.heightStyle !== "content" ) {
2785 fx.now = Math.round( total - toHide.outerHeight() - adjust );
2786 adjust = 0;
2787 }
2788 }
2789 });
2790 },
2791
2792 _toggleComplete: function( data ) {
2793 var toHide = data.oldPanel;
2794
2795 toHide
2796 .removeClass( "ui-accordion-content-active" )
2797 .prev()
2798 .removeClass( "ui-corner-top" )
2799 .addClass( "ui-corner-all" );
2800
2801 // Work around for rendering bug in IE (#5421)
2802 if ( toHide.length ) {
2803 toHide.parent()[0].className = toHide.parent()[0].className;
2804 }
2805
2806 this._trigger( "activate", null, data );
2807 }
2808 });
2809
2810 })( jQuery );
2811 (function( $, undefined ) {
2812
2813 var tabId = 0,
2814 rhash = /#.*$/;
2815
2816 function getNextTabId() {
2817 return ++tabId;
2818 }
2819
2820 function isLocal( anchor ) {
2821 return anchor.hash.length > 1 &&
2822 decodeURIComponent( anchor.href.replace( rhash, "" ) ) ===
2823 decodeURIComponent( location.href.replace( rhash, "" ) );
2824 }
2825
2826 $.widget( "ui.tabs", {
2827 version: "1.10.3",
2828 delay: 300,
2829 options: {
2830 active: null,
2831 collapsible: false,
2832 event: "click",
2833 heightStyle: "content",
2834 hide: null,
2835 show: null,
2836
2837 // callbacks
2838 activate: null,
2839 beforeActivate: null,
2840 beforeLoad: null,
2841 load: null
2842 },
2843
2844 _create: function() {
2845 var that = this,
2846 options = this.options;
2847
2848 this.running = false;
2849
2850 this.element
2851 .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" )
2852 .toggleClass( "ui-tabs-collapsible", options.collapsible )
2853 // Prevent users from focusing disabled tabs via click
2854 .delegate( ".ui-tabs-nav > li", "mousedown" + this.eventNamespace, function( event ) {
2855 if ( $( this ).is( ".ui-state-disabled" ) ) {
2856 event.preventDefault();
2857 }
2858 })
2859 // support: IE <9
2860 // Preventing the default action in mousedown doesn't prevent IE
2861 // from focusing the element, so if the anchor gets focused, blur.
2862 // We don't have to worry about focusing the previously focused
2863 // element since clicking on a non-focusable element should focus
2864 // the body anyway.
2865 .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() {
2866 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
2867 this.blur();
2868 }
2869 });
2870
2871 this._processTabs();
2872 options.active = this._initialActive();
2873
2874 // Take disabling tabs via class attribute from HTML
2875 // into account and update option properly.
2876 if ( $.isArray( options.disabled ) ) {
2877 options.disabled = $.unique( options.disabled.concat(
2878 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
2879 return that.tabs.index( li );
2880 })
2881 ) ).sort();
2882 }
2883
2884 // check for length avoids error when initializing empty list
2885 if ( this.options.active !== false && this.anchors.length ) {
2886 this.active = this._findActive( options.active );
2887 } else {
2888 this.active = $();
2889 }
2890
2891 this._refresh();
2892
2893 if ( this.active.length ) {
2894 this.load( options.active );
2895 }
2896 },
2897
2898 _initialActive: function() {
2899 var active = this.options.active,
2900 collapsible = this.options.collapsible,
2901 locationHash = location.hash.substring( 1 );
2902
2903 if ( active === null ) {
2904 // check the fragment identifier in the URL
2905 if ( locationHash ) {
2906 this.tabs.each(function( i, tab ) {
2907 if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
2908 active = i;
2909 return false;
2910 }
2911 });
2912 }
2913
2914 // check for a tab marked active via a class
2915 if ( active === null ) {
2916 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
2917 }
2918
2919 // no active tab, set to false
2920 if ( active === null || active === -1 ) {
2921 active = this.tabs.length ? 0 : false;
2922 }
2923 }
2924
2925 // handle numbers: negative, out of range
2926 if ( active !== false ) {
2927 active = this.tabs.index( this.tabs.eq( active ) );
2928 if ( active === -1 ) {
2929 active = collapsible ? false : 0;
2930 }
2931 }
2932
2933 // don't allow collapsible: false and active: false
2934 if ( !collapsible && active === false && this.anchors.length ) {
2935 active = 0;
2936 }
2937
2938 return active;
2939 },
2940
2941 _getCreateEventData: function() {
2942 return {
2943 tab: this.active,
2944 panel: !this.active.length ? $() : this._getPanelForTab( this.active )
2945 };
2946 },
2947
2948 _tabKeydown: function( event ) {
2949 /*jshint maxcomplexity:15*/
2950 var focusedTab = $( this.document[0].activeElement ).closest( "li" ),
2951 selectedIndex = this.tabs.index( focusedTab ),
2952 goingForward = true;
2953
2954 if ( this._handlePageNav( event ) ) {
2955 return;
2956 }
2957
2958 switch ( event.keyCode ) {
2959 case $.ui.keyCode.RIGHT:
2960 case $.ui.keyCode.DOWN:
2961 selectedIndex++;
2962 break;
2963 case $.ui.keyCode.UP:
2964 case $.ui.keyCode.LEFT:
2965 goingForward = false;
2966 selectedIndex--;
2967 break;
2968 case $.ui.keyCode.END:
2969 selectedIndex = this.anchors.length - 1;
2970 break;
2971 case $.ui.keyCode.HOME:
2972 selectedIndex = 0;
2973 break;
2974 case $.ui.keyCode.SPACE:
2975 // Activate only, no collapsing
2976 event.preventDefault();
2977 clearTimeout( this.activating );
2978 this._activate( selectedIndex );
2979 return;
2980 case $.ui.keyCode.ENTER:
2981 // Toggle (cancel delayed activation, allow collapsing)
2982 event.preventDefault();
2983 clearTimeout( this.activating );
2984 // Determine if we should collapse or activate
2985 this._activate( selectedIndex === this.options.active ? false : selectedIndex );
2986 return;
2987 default:
2988 return;
2989 }
2990
2991 // Focus the appropriate tab, based on which key was pressed
2992 event.preventDefault();
2993 clearTimeout( this.activating );
2994 selectedIndex = this._focusNextTab( selectedIndex, goingForward );
2995
2996 // Navigating with control key will prevent automatic activation
2997 if ( !event.ctrlKey ) {
2998 // Update aria-selected immediately so that AT think the tab is already selected.
2999 // Otherwise AT may confuse the user by stating that they need to activate the tab,
3000 // but the tab will already be activated by the time the announcement finishes.
3001 focusedTab.attr( "aria-selected", "false" );
3002 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
3003
3004 this.activating = this._delay(function() {
3005 this.option( "active", selectedIndex );
3006 }, this.delay );
3007 }
3008 },
3009
3010 _panelKeydown: function( event ) {
3011 if ( this._handlePageNav( event ) ) {
3012 return;
3013 }
3014
3015 // Ctrl+up moves focus to the current tab
3016 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
3017 event.preventDefault();
3018 this.active.focus();
3019 }
3020 },
3021
3022 // Alt+page up/down moves focus to the previous/next tab (and activates)
3023 _handlePageNav: function( event ) {
3024 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
3025 this._activate( this._focusNextTab( this.options.active - 1, false ) );
3026 return true;
3027 }
3028 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
3029 this._activate( this._focusNextTab( this.options.active + 1, true ) );
3030 return true;
3031 }
3032 },
3033
3034 _findNextTab: function( index, goingForward ) {
3035 var lastTabIndex = this.tabs.length - 1;
3036
3037 function constrain() {
3038 if ( index > lastTabIndex ) {
3039 index = 0;
3040 }
3041 if ( index < 0 ) {
3042 index = lastTabIndex;
3043 }
3044 return index;
3045 }
3046
3047 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
3048 index = goingForward ? index + 1 : index - 1;
3049 }
3050
3051 return index;
3052 },
3053
3054 _focusNextTab: function( index, goingForward ) {
3055 index = this._findNextTab( index, goingForward );
3056 this.tabs.eq( index ).focus();
3057 return index;
3058 },
3059
3060 _setOption: function( key, value ) {
3061 if ( key === "active" ) {
3062 // _activate() will handle invalid values and update this.options
3063 this._activate( value );
3064 return;
3065 }
3066
3067 if ( key === "disabled" ) {
3068 // don't use the widget factory's disabled handling
3069 this._setupDisabled( value );
3070 return;
3071 }
3072
3073 this._super( key, value);
3074
3075 if ( key === "collapsible" ) {
3076 this.element.toggleClass( "ui-tabs-collapsible", value );
3077 // Setting collapsible: false while collapsed; open first panel
3078 if ( !value && this.options.active === false ) {
3079 this._activate( 0 );
3080 }
3081 }
3082
3083 if ( key === "event" ) {
3084 this._setupEvents( value );
3085 }
3086
3087 if ( key === "heightStyle" ) {
3088 this._setupHeightStyle( value );
3089 }
3090 },
3091
3092 _tabId: function( tab ) {
3093 return tab.attr( "aria-controls" ) || "ui-tabs-" + getNextTabId();
3094 },
3095
3096 _sanitizeSelector: function( hash ) {
3097 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
3098 },
3099
3100 refresh: function() {
3101 var options = this.options,
3102 lis = this.tablist.children( ":has(a[href])" );
3103
3104 // get disabled tabs from class attribute from HTML
3105 // this will get converted to a boolean if needed in _refresh()
3106 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
3107 return lis.index( tab );
3108 });
3109
3110 this._processTabs();
3111
3112 // was collapsed or no tabs
3113 if ( options.active === false || !this.anchors.length ) {
3114 options.active = false;
3115 this.active = $();
3116 // was active, but active tab is gone
3117 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
3118 // all remaining tabs are disabled
3119 if ( this.tabs.length === options.disabled.length ) {
3120 options.active = false;
3121 this.active = $();
3122 // activate previous tab
3123 } else {
3124 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
3125 }
3126 // was active, active tab still exists
3127 } else {
3128 // make sure active index is correct
3129 options.active = this.tabs.index( this.active );
3130 }
3131
3132 this._refresh();
3133 },
3134
3135 _refresh: function() {
3136 this._setupDisabled( this.options.disabled );
3137 this._setupEvents( this.options.event );
3138 this._setupHeightStyle( this.options.heightStyle );
3139
3140 this.tabs.not( this.active ).attr({
3141 "aria-selected": "false",
3142 tabIndex: -1
3143 });
3144 this.panels.not( this._getPanelForTab( this.active ) )
3145 .hide()
3146 .attr({
3147 "aria-expanded": "false",
3148 "aria-hidden": "true"
3149 });
3150
3151 // Make sure one tab is in the tab order
3152 if ( !this.active.length ) {
3153 this.tabs.eq( 0 ).attr( "tabIndex", 0 );
3154 } else {
3155 this.active
3156 .addClass( "ui-tabs-active ui-state-active" )
3157 .attr({
3158 "aria-selected": "true",
3159 tabIndex: 0
3160 });
3161 this._getPanelForTab( this.active )
3162 .show()
3163 .attr({
3164 "aria-expanded": "true",
3165 "aria-hidden": "false"
3166 });
3167 }
3168 },
3169
3170 _processTabs: function() {
3171 var that = this;
3172
3173 this.tablist = this._getList()
3174 .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
3175 .attr( "role", "tablist" );
3176
3177 this.tabs = this.tablist.find( "> li:has(a[href])" )
3178 .addClass( "ui-state-default ui-corner-top" )
3179 .attr({
3180 role: "tab",
3181 tabIndex: -1
3182 });
3183
3184 this.anchors = this.tabs.map(function() {
3185 return $( "a", this )[ 0 ];
3186 })
3187 .addClass( "ui-tabs-anchor" )
3188 .attr({
3189 role: "presentation",
3190 tabIndex: -1
3191 });
3192
3193 this.panels = $();
3194
3195 this.anchors.each(function( i, anchor ) {
3196 var selector, panel, panelId,
3197 anchorId = $( anchor ).uniqueId().attr( "id" ),
3198 tab = $( anchor ).closest( "li" ),
3199 originalAriaControls = tab.attr( "aria-controls" );
3200
3201 // inline tab
3202 if ( isLocal( anchor ) ) {
3203 selector = anchor.hash;
3204 panel = that.element.find( that._sanitizeSelector( selector ) );
3205 // remote tab
3206 } else {
3207 panelId = that._tabId( tab );
3208 selector = "#" + panelId;
3209 panel = that.element.find( selector );
3210 if ( !panel.length ) {
3211 panel = that._createPanel( panelId );
3212 panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
3213 }
3214 panel.attr( "aria-live", "polite" );
3215 }
3216
3217 if ( panel.length) {
3218 that.panels = that.panels.add( panel );
3219 }
3220 if ( originalAriaControls ) {
3221 tab.data( "ui-tabs-aria-controls", originalAriaControls );
3222 }
3223 tab.attr({
3224 "aria-controls": selector.substring( 1 ),
3225 "aria-labelledby": anchorId
3226 });
3227 panel.attr( "aria-labelledby", anchorId );
3228 });
3229
3230 this.panels
3231 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
3232 .attr( "role", "tabpanel" );
3233 },
3234
3235 // allow overriding how to find the list for rare usage scenarios (#7715)
3236 _getList: function() {
3237 return this.element.find( "ol,ul" ).eq( 0 );
3238 },
3239
3240 _createPanel: function( id ) {
3241 return $( "<div>" )
3242 .attr( "id", id )
3243 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
3244 .data( "ui-tabs-destroy", true );
3245 },
3246
3247 _setupDisabled: function( disabled ) {
3248 if ( $.isArray( disabled ) ) {
3249 if ( !disabled.length ) {
3250 disabled = false;
3251 } else if ( disabled.length === this.anchors.length ) {
3252 disabled = true;
3253 }
3254 }
3255
3256 // disable tabs
3257 for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {
3258 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
3259 $( li )
3260 .addClass( "ui-state-disabled" )
3261 .attr( "aria-disabled", "true" );
3262 } else {
3263 $( li )
3264 .removeClass( "ui-state-disabled" )
3265 .removeAttr( "aria-disabled" );
3266 }
3267 }
3268
3269 this.options.disabled = disabled;
3270 },
3271
3272 _setupEvents: function( event ) {
3273 var events = {
3274 click: function( event ) {
3275 event.preventDefault();
3276 }
3277 };
3278 if ( event ) {
3279 $.each( event.split(" "), function( index, eventName ) {
3280 events[ eventName ] = "_eventHandler";
3281 });
3282 }
3283
3284 this._off( this.anchors.add( this.tabs ).add( this.panels ) );
3285 this._on( this.anchors, events );
3286 this._on( this.tabs, { keydown: "_tabKeydown" } );
3287 this._on( this.panels, { keydown: "_panelKeydown" } );
3288
3289 this._focusable( this.tabs );
3290 this._hoverable( this.tabs );
3291 },
3292
3293 _setupHeightStyle: function( heightStyle ) {
3294 var maxHeight,
3295 parent = this.element.parent();
3296
3297 if ( heightStyle === "fill" ) {
3298 maxHeight = parent.height();
3299 maxHeight -= this.element.outerHeight() - this.element.height();
3300
3301 this.element.siblings( ":visible" ).each(function() {
3302 var elem = $( this ),
3303 position = elem.css( "position" );
3304
3305 if ( position === "absolute" || position === "fixed" ) {
3306 return;
3307 }
3308 maxHeight -= elem.outerHeight( true );
3309 });
3310
3311 this.element.children().not( this.panels ).each(function() {
3312 maxHeight -= $( this ).outerHeight( true );
3313 });
3314
3315 this.panels.each(function() {
3316 $( this ).height( Math.max( 0, maxHeight -
3317 $( this ).innerHeight() + $( this ).height() ) );
3318 })
3319 .css( "overflow", "auto" );
3320 } else if ( heightStyle === "auto" ) {
3321 maxHeight = 0;
3322 this.panels.each(function() {
3323 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
3324 }).height( maxHeight );
3325 }
3326 },
3327
3328 _eventHandler: function( event ) {
3329 var options = this.options,
3330 active = this.active,
3331 anchor = $( event.currentTarget ),
3332 tab = anchor.closest( "li" ),
3333 clickedIsActive = tab[ 0 ] === active[ 0 ],
3334 collapsing = clickedIsActive && options.collapsible,
3335 toShow = collapsing ? $() : this._getPanelForTab( tab ),
3336 toHide = !active.length ? $() : this._getPanelForTab( active ),
3337 eventData = {
3338 oldTab: active,
3339 oldPanel: toHide,
3340 newTab: collapsing ? $() : tab,
3341 newPanel: toShow
3342 };
3343
3344 event.preventDefault();
3345
3346 if ( tab.hasClass( "ui-state-disabled" ) ||
3347 // tab is already loading
3348 tab.hasClass( "ui-tabs-loading" ) ||
3349 // can't switch durning an animation
3350 this.running ||
3351 // click on active header, but not collapsible
3352 ( clickedIsActive && !options.collapsible ) ||
3353 // allow canceling activation
3354 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
3355 return;
3356 }
3357
3358 options.active = collapsing ? false : this.tabs.index( tab );
3359
3360 this.active = clickedIsActive ? $() : tab;
3361 if ( this.xhr ) {
3362 this.xhr.abort();
3363 }
3364
3365 if ( !toHide.length && !toShow.length ) {
3366 $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
3367 }
3368
3369 if ( toShow.length ) {
3370 this.load( this.tabs.index( tab ), event );
3371 }
3372 this._toggle( event, eventData );
3373 },
3374
3375 // handles show/hide for selecting tabs
3376 _toggle: function( event, eventData ) {
3377 var that = this,
3378 toShow = eventData.newPanel,
3379 toHide = eventData.oldPanel;
3380
3381 this.running = true;
3382
3383 function complete() {
3384 that.running = false;
3385 that._trigger( "activate", event, eventData );
3386 }
3387
3388 function show() {
3389 eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
3390
3391 if ( toShow.length && that.options.show ) {
3392 that._show( toShow, that.options.show, complete );
3393 } else {
3394 toShow.show();
3395 complete();
3396 }
3397 }
3398
3399 // start out by hiding, then showing, then completing
3400 if ( toHide.length && this.options.hide ) {
3401 this._hide( toHide, this.options.hide, function() {
3402 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
3403 show();
3404 });
3405 } else {
3406 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
3407 toHide.hide();
3408 show();
3409 }
3410
3411 toHide.attr({
3412 "aria-expanded": "false",
3413 "aria-hidden": "true"
3414 });
3415 eventData.oldTab.attr( "aria-selected", "false" );
3416 // If we're switching tabs, remove the old tab from the tab order.
3417 // If we're opening from collapsed state, remove the previous tab from the tab order.
3418 // If we're collapsing, then keep the collapsing tab in the tab order.
3419 if ( toShow.length && toHide.length ) {
3420 eventData.oldTab.attr( "tabIndex", -1 );
3421 } else if ( toShow.length ) {
3422 this.tabs.filter(function() {
3423 return $( this ).attr( "tabIndex" ) === 0;
3424 })
3425 .attr( "tabIndex", -1 );
3426 }
3427
3428 toShow.attr({
3429 "aria-expanded": "true",
3430 "aria-hidden": "false"
3431 });
3432 eventData.newTab.attr({
3433 "aria-selected": "true",
3434 tabIndex: 0
3435 });
3436 },
3437
3438 _activate: function( index ) {
3439 var anchor,
3440 active = this._findActive( index );
3441
3442 // trying to activate the already active panel
3443 if ( active[ 0 ] === this.active[ 0 ] ) {
3444 return;
3445 }
3446
3447 // trying to collapse, simulate a click on the current active header
3448 if ( !active.length ) {
3449 active = this.active;
3450 }
3451
3452 anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
3453 this._eventHandler({
3454 target: anchor,
3455 currentTarget: anchor,
3456 preventDefault: $.noop
3457 });
3458 },
3459
3460 _findActive: function( index ) {
3461 return index === false ? $() : this.tabs.eq( index );
3462 },
3463
3464 _getIndex: function( index ) {
3465 // meta-function to give users option to provide a href string instead of a numerical index.
3466 if ( typeof index === "string" ) {
3467 index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) );
3468 }
3469
3470 return index;
3471 },
3472
3473 _destroy: function() {
3474 if ( this.xhr ) {
3475 this.xhr.abort();
3476 }
3477
3478 this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" );
3479
3480 this.tablist
3481 .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
3482 .removeAttr( "role" );
3483
3484 this.anchors
3485 .removeClass( "ui-tabs-anchor" )
3486 .removeAttr( "role" )
3487 .removeAttr( "tabIndex" )
3488 .removeUniqueId();
3489
3490 this.tabs.add( this.panels ).each(function() {
3491 if ( $.data( this, "ui-tabs-destroy" ) ) {
3492 $( this ).remove();
3493 } else {
3494 $( this )
3495 .removeClass( "ui-state-default ui-state-active ui-state-disabled " +
3496 "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" )
3497 .removeAttr( "tabIndex" )
3498 .removeAttr( "aria-live" )
3499 .removeAttr( "aria-busy" )
3500 .removeAttr( "aria-selected" )
3501 .removeAttr( "aria-labelledby" )
3502 .removeAttr( "aria-hidden" )
3503 .removeAttr( "aria-expanded" )
3504 .removeAttr( "role" );
3505 }
3506 });
3507
3508 this.tabs.each(function() {
3509 var li = $( this ),
3510 prev = li.data( "ui-tabs-aria-controls" );
3511 if ( prev ) {
3512 li
3513 .attr( "aria-controls", prev )
3514 .removeData( "ui-tabs-aria-controls" );
3515 } else {
3516 li.removeAttr( "aria-controls" );
3517 }
3518 });
3519
3520 this.panels.show();
3521
3522 if ( this.options.heightStyle !== "content" ) {
3523 this.panels.css( "height", "" );
3524 }
3525 },
3526
3527 enable: function( index ) {
3528 var disabled = this.options.disabled;
3529 if ( disabled === false ) {
3530 return;
3531 }
3532
3533 if ( index === undefined ) {
3534 disabled = false;
3535 } else {
3536 index = this._getIndex( index );
3537 if ( $.isArray( disabled ) ) {
3538 disabled = $.map( disabled, function( num ) {
3539 return num !== index ? num : null;
3540 });
3541 } else {
3542 disabled = $.map( this.tabs, function( li, num ) {
3543 return num !== index ? num : null;
3544 });
3545 }
3546 }
3547 this._setupDisabled( disabled );
3548 },
3549
3550 disable: function( index ) {
3551 var disabled = this.options.disabled;
3552 if ( disabled === true ) {
3553 return;
3554 }
3555
3556 if ( index === undefined ) {
3557 disabled = true;
3558 } else {
3559 index = this._getIndex( index );
3560 if ( $.inArray( index, disabled ) !== -1 ) {
3561 return;
3562 }
3563 if ( $.isArray( disabled ) ) {
3564 disabled = $.merge( [ index ], disabled ).sort();
3565 } else {
3566 disabled = [ index ];
3567 }
3568 }
3569 this._setupDisabled( disabled );
3570 },
3571
3572 load: function( index, event ) {
3573 index = this._getIndex( index );
3574 var that = this,
3575 tab = this.tabs.eq( index ),
3576 anchor = tab.find( ".ui-tabs-anchor" ),
3577 panel = this._getPanelForTab( tab ),
3578 eventData = {
3579 tab: tab,
3580 panel: panel
3581 };
3582
3583 // not remote
3584 if ( isLocal( anchor[ 0 ] ) ) {
3585 return;
3586 }
3587
3588 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
3589
3590 // support: jQuery <1.8
3591 // jQuery <1.8 returns false if the request is canceled in beforeSend,
3592 // but as of 1.8, $.ajax() always returns a jqXHR object.
3593 if ( this.xhr && this.xhr.statusText !== "canceled" ) {
3594 tab.addClass( "ui-tabs-loading" );
3595 panel.attr( "aria-busy", "true" );
3596
3597 this.xhr
3598 .success(function( response ) {
3599 // support: jQuery <1.8
3600 // http://bugs.jquery.com/ticket/11778
3601 setTimeout(function() {
3602 panel.html( response );
3603 that._trigger( "load", event, eventData );
3604 }, 1 );
3605 })
3606 .complete(function( jqXHR, status ) {
3607 // support: jQuery <1.8
3608 // http://bugs.jquery.com/ticket/11778
3609 setTimeout(function() {
3610 if ( status === "abort" ) {
3611 that.panels.stop( false, true );
3612 }
3613
3614 tab.removeClass( "ui-tabs-loading" );
3615 panel.removeAttr( "aria-busy" );
3616
3617 if ( jqXHR === that.xhr ) {
3618 delete that.xhr;
3619 }
3620 }, 1 );
3621 });
3622 }
3623 },
3624
3625 _ajaxSettings: function( anchor, event, eventData ) {
3626 var that = this;
3627 return {
3628 url: anchor.attr( "href" ),
3629 beforeSend: function( jqXHR, settings ) {
3630 return that._trigger( "beforeLoad", event,
3631 $.extend( { jqXHR : jqXHR, ajaxSettings: settings }, eventData ) );
3632 }
3633 };
3634 },
3635
3636 _getPanelForTab: function( tab ) {
3637 var id = $( tab ).attr( "aria-controls" );
3638 return this.element.find( this._sanitizeSelector( "#" + id ) );
3639 }
3640 });
3641
3642 })( jQuery );