Line # Revision Author
1 386 ahitrov /*! jQuery UI - v1.9.2 - 2013-10-13
2 * http://jqueryui.com
3 * Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.position.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.menu.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js, jquery.ui.effect.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js
4 * Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
5
6 (function( $, undefined ) {
7
8 var uuid = 0,
9 runiqueId = /^ui-id-\d+$/;
10
11 // prevent duplicate loading
12 // this is only a problem because we proxy existing functions
13 // and we don't want to double proxy them
14 $.ui = $.ui || {};
15 if ( $.ui.version ) {
16 return;
17 }
18
19 $.extend( $.ui, {
20 version: "1.9.2",
21
22 keyCode: {
23 BACKSPACE: 8,
24 COMMA: 188,
25 DELETE: 46,
26 DOWN: 40,
27 END: 35,
28 ENTER: 13,
29 ESCAPE: 27,
30 HOME: 36,
31 LEFT: 37,
32 NUMPAD_ADD: 107,
33 NUMPAD_DECIMAL: 110,
34 NUMPAD_DIVIDE: 111,
35 NUMPAD_ENTER: 108,
36 NUMPAD_MULTIPLY: 106,
37 NUMPAD_SUBTRACT: 109,
38 PAGE_DOWN: 34,
39 PAGE_UP: 33,
40 PERIOD: 190,
41 RIGHT: 39,
42 SPACE: 32,
43 TAB: 9,
44 UP: 38
45 }
46 });
47
48 // plugins
49 $.fn.extend({
50 _focus: $.fn.focus,
51 focus: function( delay, fn ) {
52 return typeof delay === "number" ?
53 this.each(function() {
54 var elem = this;
55 setTimeout(function() {
56 $( elem ).focus();
57 if ( fn ) {
58 fn.call( elem );
59 }
60 }, delay );
61 }) :
62 this._focus.apply( this, arguments );
63 },
64
65 scrollParent: function() {
66 var scrollParent;
67 if (($.ui.ie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) {
68 scrollParent = this.parents().filter(function() {
69 return (/(relative|absolute|fixed)/).test($.css(this,'position')) && (/(auto|scroll)/).test($.css(this,'overflow')+$.css(this,'overflow-y')+$.css(this,'overflow-x'));
70 }).eq(0);
71 } else {
72 scrollParent = this.parents().filter(function() {
73 return (/(auto|scroll)/).test($.css(this,'overflow')+$.css(this,'overflow-y')+$.css(this,'overflow-x'));
74 }).eq(0);
75 }
76
77 return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent;
78 },
79
80 zIndex: function( zIndex ) {
81 if ( zIndex !== undefined ) {
82 return this.css( "zIndex", zIndex );
83 }
84
85 if ( this.length ) {
86 var elem = $( this[ 0 ] ), position, value;
87 while ( elem.length && elem[ 0 ] !== document ) {
88 // Ignore z-index if position is set to a value where z-index is ignored by the browser
89 // This makes behavior of this function consistent across browsers
90 // WebKit always returns auto if the element is positioned
91 position = elem.css( "position" );
92 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
93 // IE returns 0 when zIndex is not specified
94 // other browsers return a string
95 // we ignore the case of nested elements with an explicit value of 0
96 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
97 value = parseInt( elem.css( "zIndex" ), 10 );
98 if ( !isNaN( value ) && value !== 0 ) {
99 return value;
100 }
101 }
102 elem = elem.parent();
103 }
104 }
105
106 return 0;
107 },
108
109 uniqueId: function() {
110 return this.each(function() {
111 if ( !this.id ) {
112 this.id = "ui-id-" + (++uuid);
113 }
114 });
115 },
116
117 removeUniqueId: function() {
118 return this.each(function() {
119 if ( runiqueId.test( this.id ) ) {
120 $( this ).removeAttr( "id" );
121 }
122 });
123 }
124 });
125
126 // selectors
127 function focusable( element, isTabIndexNotNaN ) {
128 var map, mapName, img,
129 nodeName = element.nodeName.toLowerCase();
130 if ( "area" === nodeName ) {
131 map = element.parentNode;
132 mapName = map.name;
133 if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
134 return false;
135 }
136 img = $( "img[usemap=#" + mapName + "]" )[0];
137 return !!img && visible( img );
138 }
139 return ( /input|select|textarea|button|object/.test( nodeName ) ?
140 !element.disabled :
141 "a" === nodeName ?
142 element.href || isTabIndexNotNaN :
143 isTabIndexNotNaN) &&
144 // the element and all of its ancestors must be visible
145 visible( element );
146 }
147
148 function visible( element ) {
149 return $.expr.filters.visible( element ) &&
150 !$( element ).parents().andSelf().filter(function() {
151 return $.css( this, "visibility" ) === "hidden";
152 }).length;
153 }
154
155 $.extend( $.expr[ ":" ], {
156 data: $.expr.createPseudo ?
157 $.expr.createPseudo(function( dataName ) {
158 return function( elem ) {
159 return !!$.data( elem, dataName );
160 };
161 }) :
162 // support: jQuery <1.8
163 function( elem, i, match ) {
164 return !!$.data( elem, match[ 3 ] );
165 },
166
167 focusable: function( element ) {
168 return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
169 },
170
171 tabbable: function( element ) {
172 var tabIndex = $.attr( element, "tabindex" ),
173 isTabIndexNaN = isNaN( tabIndex );
174 return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
175 }
176 });
177
178 // support
179 $(function() {
180 var body = document.body,
181 div = body.appendChild( div = document.createElement( "div" ) );
182
183 // access offsetHeight before setting the style to prevent a layout bug
184 // in IE 9 which causes the element to continue to take up space even
185 // after it is removed from the DOM (#8026)
186 div.offsetHeight;
187
188 $.extend( div.style, {
189 minHeight: "100px",
190 height: "auto",
191 padding: 0,
192 borderWidth: 0
193 });
194
195 $.support.minHeight = div.offsetHeight === 100;
196 $.support.selectstart = "onselectstart" in div;
197
198 // set display to none to avoid a layout bug in IE
199 // http://dev.jquery.com/ticket/4014
200 body.removeChild( div ).style.display = "none";
201 });
202
203 // support: jQuery <1.8
204 if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
205 $.each( [ "Width", "Height" ], function( i, name ) {
206 var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
207 type = name.toLowerCase(),
208 orig = {
209 innerWidth: $.fn.innerWidth,
210 innerHeight: $.fn.innerHeight,
211 outerWidth: $.fn.outerWidth,
212 outerHeight: $.fn.outerHeight
213 };
214
215 function reduce( elem, size, border, margin ) {
216 $.each( side, function() {
217 size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
218 if ( border ) {
219 size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
220 }
221 if ( margin ) {
222 size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
223 }
224 });
225 return size;
226 }
227
228 $.fn[ "inner" + name ] = function( size ) {
229 if ( size === undefined ) {
230 return orig[ "inner" + name ].call( this );
231 }
232
233 return this.each(function() {
234 $( this ).css( type, reduce( this, size ) + "px" );
235 });
236 };
237
238 $.fn[ "outer" + name] = function( size, margin ) {
239 if ( typeof size !== "number" ) {
240 return orig[ "outer" + name ].call( this, size );
241 }
242
243 return this.each(function() {
244 $( this).css( type, reduce( this, size, true, margin ) + "px" );
245 });
246 };
247 });
248 }
249
250 // support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
251 if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
252 $.fn.removeData = (function( removeData ) {
253 return function( key ) {
254 if ( arguments.length ) {
255 return removeData.call( this, $.camelCase( key ) );
256 } else {
257 return removeData.call( this );
258 }
259 };
260 })( $.fn.removeData );
261 }
262
263
264
265
266
267 // deprecated
268
269 (function() {
270 var uaMatch = /msie ([\w.]+)/.exec( navigator.userAgent.toLowerCase() ) || [];
271 $.ui.ie = uaMatch.length ? true : false;
272 $.ui.ie6 = parseFloat( uaMatch[ 1 ], 10 ) === 6;
273 })();
274
275 $.fn.extend({
276 disableSelection: function() {
277 return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
278 ".ui-disableSelection", function( event ) {
279 event.preventDefault();
280 });
281 },
282
283 enableSelection: function() {
284 return this.unbind( ".ui-disableSelection" );
285 }
286 });
287
288 $.extend( $.ui, {
289 // $.ui.plugin is deprecated. Use the proxy pattern instead.
290 plugin: {
291 add: function( module, option, set ) {
292 var i,
293 proto = $.ui[ module ].prototype;
294 for ( i in set ) {
295 proto.plugins[ i ] = proto.plugins[ i ] || [];
296 proto.plugins[ i ].push( [ option, set[ i ] ] );
297 }
298 },
299 call: function( instance, name, args ) {
300 var i,
301 set = instance.plugins[ name ];
302 if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) {
303 return;
304 }
305
306 for ( i = 0; i < set.length; i++ ) {
307 if ( instance.options[ set[ i ][ 0 ] ] ) {
308 set[ i ][ 1 ].apply( instance.element, args );
309 }
310 }
311 }
312 },
313
314 contains: $.contains,
315
316 // only used by resizable
317 hasScroll: function( el, a ) {
318
319 //If overflow is hidden, the element might have extra content, but the user wants to hide it
320 if ( $( el ).css( "overflow" ) === "hidden") {
321 return false;
322 }
323
324 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
325 has = false;
326
327 if ( el[ scroll ] > 0 ) {
328 return true;
329 }
330
331 // TODO: determine which cases actually cause this to happen
332 // if the element doesn't have the scroll set, see if it's possible to
333 // set the scroll
334 el[ scroll ] = 1;
335 has = ( el[ scroll ] > 0 );
336 el[ scroll ] = 0;
337 return has;
338 },
339
340 // these are odd functions, fix the API or move into individual plugins
341 isOverAxis: function( x, reference, size ) {
342 //Determines when x coordinate is over "b" element axis
343 return ( x > reference ) && ( x < ( reference + size ) );
344 },
345 isOver: function( y, x, top, left, height, width ) {
346 //Determines when x, y coordinates is over "b" element
347 return $.ui.isOverAxis( y, top, height ) && $.ui.isOverAxis( x, left, width );
348 }
349 });
350
351 })( jQuery );
352 (function( $, undefined ) {
353
354 var uuid = 0,
355 slice = Array.prototype.slice,
356 _cleanData = $.cleanData;
357 $.cleanData = function( elems ) {
358 for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
359 try {
360 $( elem ).triggerHandler( "remove" );
361 // http://bugs.jquery.com/ticket/8235
362 } catch( e ) {}
363 }
364 _cleanData( elems );
365 };
366
367 $.widget = function( name, base, prototype ) {
368 var fullName, existingConstructor, constructor, basePrototype,
369 namespace = name.split( "." )[ 0 ];
370
371 name = name.split( "." )[ 1 ];
372 fullName = namespace + "-" + name;
373
374 if ( !prototype ) {
375 prototype = base;
376 base = $.Widget;
377 }
378
379 // create selector for plugin
380 $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
381 return !!$.data( elem, fullName );
382 };
383
384 $[ namespace ] = $[ namespace ] || {};
385 existingConstructor = $[ namespace ][ name ];
386 constructor = $[ namespace ][ name ] = function( options, element ) {
387 // allow instantiation without "new" keyword
388 if ( !this._createWidget ) {
389 return new constructor( options, element );
390 }
391
392 // allow instantiation without initializing for simple inheritance
393 // must use "new" keyword (the code above always passes args)
394 if ( arguments.length ) {
395 this._createWidget( options, element );
396 }
397 };
398 // extend with the existing constructor to carry over any static properties
399 $.extend( constructor, existingConstructor, {
400 version: prototype.version,
401 // copy the object used to create the prototype in case we need to
402 // redefine the widget later
403 _proto: $.extend( {}, prototype ),
404 // track widgets that inherit from this widget in case this widget is
405 // redefined after a widget inherits from it
406 _childConstructors: []
407 });
408
409 basePrototype = new base();
410 // we need to make the options hash a property directly on the new instance
411 // otherwise we'll modify the options hash on the prototype that we're
412 // inheriting from
413 basePrototype.options = $.widget.extend( {}, basePrototype.options );
414 $.each( prototype, function( prop, value ) {
415 if ( $.isFunction( value ) ) {
416 prototype[ prop ] = (function() {
417 var _super = function() {
418 return base.prototype[ prop ].apply( this, arguments );
419 },
420 _superApply = function( args ) {
421 return base.prototype[ prop ].apply( this, args );
422 };
423 return function() {
424 var __super = this._super,
425 __superApply = this._superApply,
426 returnValue;
427
428 this._super = _super;
429 this._superApply = _superApply;
430
431 returnValue = value.apply( this, arguments );
432
433 this._super = __super;
434 this._superApply = __superApply;
435
436 return returnValue;
437 };
438 })();
439 }
440 });
441 constructor.prototype = $.widget.extend( basePrototype, {
442 // TODO: remove support for widgetEventPrefix
443 // always use the name + a colon as the prefix, e.g., draggable:start
444 // don't prefix for widgets that aren't DOM-based
445 widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name
446 }, prototype, {
447 constructor: constructor,
448 namespace: namespace,
449 widgetName: name,
450 // TODO remove widgetBaseClass, see #8155
451 widgetBaseClass: fullName,
452 widgetFullName: fullName
453 });
454
455 // If this widget is being redefined then we need to find all widgets that
456 // are inheriting from it and redefine all of them so that they inherit from
457 // the new version of this widget. We're essentially trying to replace one
458 // level in the prototype chain.
459 if ( existingConstructor ) {
460 $.each( existingConstructor._childConstructors, function( i, child ) {
461 var childPrototype = child.prototype;
462
463 // redefine the child widget using the same prototype that was
464 // originally used, but inherit from the new version of the base
465 $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
466 });
467 // remove the list of existing child constructors from the old constructor
468 // so the old child constructors can be garbage collected
469 delete existingConstructor._childConstructors;
470 } else {
471 base._childConstructors.push( constructor );
472 }
473
474 $.widget.bridge( name, constructor );
475 };
476
477 $.widget.extend = function( target ) {
478 var input = slice.call( arguments, 1 ),
479 inputIndex = 0,
480 inputLength = input.length,
481 key,
482 value;
483 for ( ; inputIndex < inputLength; inputIndex++ ) {
484 for ( key in input[ inputIndex ] ) {
485 value = input[ inputIndex ][ key ];
486 if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
487 // Clone objects
488 if ( $.isPlainObject( value ) ) {
489 target[ key ] = $.isPlainObject( target[ key ] ) ?
490 $.widget.extend( {}, target[ key ], value ) :
491 // Don't extend strings, arrays, etc. with objects
492 $.widget.extend( {}, value );
493 // Copy everything else by reference
494 } else {
495 target[ key ] = value;
496 }
497 }
498 }
499 }
500 return target;
501 };
502
503 $.widget.bridge = function( name, object ) {
504 var fullName = object.prototype.widgetFullName || name;
505 $.fn[ name ] = function( options ) {
506 var isMethodCall = typeof options === "string",
507 args = slice.call( arguments, 1 ),
508 returnValue = this;
509
510 // allow multiple hashes to be passed on init
511 options = !isMethodCall && args.length ?
512 $.widget.extend.apply( null, [ options ].concat(args) ) :
513 options;
514
515 if ( isMethodCall ) {
516 this.each(function() {
517 var methodValue,
518 instance = $.data( this, fullName );
519 if ( !instance ) {
520 return $.error( "cannot call methods on " + name + " prior to initialization; " +
521 "attempted to call method '" + options + "'" );
522 }
523 if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
524 return $.error( "no such method '" + options + "' for " + name + " widget instance" );
525 }
526 methodValue = instance[ options ].apply( instance, args );
527 if ( methodValue !== instance && methodValue !== undefined ) {
528 returnValue = methodValue && methodValue.jquery ?
529 returnValue.pushStack( methodValue.get() ) :
530 methodValue;
531 return false;
532 }
533 });
534 } else {
535 this.each(function() {
536 var instance = $.data( this, fullName );
537 if ( instance ) {
538 instance.option( options || {} )._init();
539 } else {
540 $.data( this, fullName, new object( options, this ) );
541 }
542 });
543 }
544
545 return returnValue;
546 };
547 };
548
549 $.Widget = function( /* options, element */ ) {};
550 $.Widget._childConstructors = [];
551
552 $.Widget.prototype = {
553 widgetName: "widget",
554 widgetEventPrefix: "",
555 defaultElement: "<div>",
556 options: {
557 disabled: false,
558
559 // callbacks
560 create: null
561 },
562 _createWidget: function( options, element ) {
563 element = $( element || this.defaultElement || this )[ 0 ];
564 this.element = $( element );
565 this.uuid = uuid++;
566 this.eventNamespace = "." + this.widgetName + this.uuid;
567 this.options = $.widget.extend( {},
568 this.options,
569 this._getCreateOptions(),
570 options );
571
572 this.bindings = $();
573 this.hoverable = $();
574 this.focusable = $();
575
576 if ( element !== this ) {
577 // 1.9 BC for #7810
578 // TODO remove dual storage
579 $.data( element, this.widgetName, this );
580 $.data( element, this.widgetFullName, this );
581 this._on( true, this.element, {
582 remove: function( event ) {
583 if ( event.target === element ) {
584 this.destroy();
585 }
586 }
587 });
588 this.document = $( element.style ?
589 // element within the document
590 element.ownerDocument :
591 // element is window or document
592 element.document || element );
593 this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
594 }
595
596 this._create();
597 this._trigger( "create", null, this._getCreateEventData() );
598 this._init();
599 },
600 _getCreateOptions: $.noop,
601 _getCreateEventData: $.noop,
602 _create: $.noop,
603 _init: $.noop,
604
605 destroy: function() {
606 this._destroy();
607 // we can probably remove the unbind calls in 2.0
608 // all event bindings should go through this._on()
609 this.element
610 .unbind( this.eventNamespace )
611 // 1.9 BC for #7810
612 // TODO remove dual storage
613 .removeData( this.widgetName )
614 .removeData( this.widgetFullName )
615 // support: jquery <1.6.3
616 // http://bugs.jquery.com/ticket/9413
617 .removeData( $.camelCase( this.widgetFullName ) );
618 this.widget()
619 .unbind( this.eventNamespace )
620 .removeAttr( "aria-disabled" )
621 .removeClass(
622 this.widgetFullName + "-disabled " +
623 "ui-state-disabled" );
624
625 // clean up events and states
626 this.bindings.unbind( this.eventNamespace );
627 this.hoverable.removeClass( "ui-state-hover" );
628 this.focusable.removeClass( "ui-state-focus" );
629 },
630 _destroy: $.noop,
631
632 widget: function() {
633 return this.element;
634 },
635
636 option: function( key, value ) {
637 var options = key,
638 parts,
639 curOption,
640 i;
641
642 if ( arguments.length === 0 ) {
643 // don't return a reference to the internal hash
644 return $.widget.extend( {}, this.options );
645 }
646
647 if ( typeof key === "string" ) {
648 // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
649 options = {};
650 parts = key.split( "." );
651 key = parts.shift();
652 if ( parts.length ) {
653 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
654 for ( i = 0; i < parts.length - 1; i++ ) {
655 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
656 curOption = curOption[ parts[ i ] ];
657 }
658 key = parts.pop();
659 if ( value === undefined ) {
660 return curOption[ key ] === undefined ? null : curOption[ key ];
661 }
662 curOption[ key ] = value;
663 } else {
664 if ( value === undefined ) {
665 return this.options[ key ] === undefined ? null : this.options[ key ];
666 }
667 options[ key ] = value;
668 }
669 }
670
671 this._setOptions( options );
672
673 return this;
674 },
675 _setOptions: function( options ) {
676 var key;
677
678 for ( key in options ) {
679 this._setOption( key, options[ key ] );
680 }
681
682 return this;
683 },
684 _setOption: function( key, value ) {
685 this.options[ key ] = value;
686
687 if ( key === "disabled" ) {
688 this.widget()
689 .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value )
690 .attr( "aria-disabled", value );
691 this.hoverable.removeClass( "ui-state-hover" );
692 this.focusable.removeClass( "ui-state-focus" );
693 }
694
695 return this;
696 },
697
698 enable: function() {
699 return this._setOption( "disabled", false );
700 },
701 disable: function() {
702 return this._setOption( "disabled", true );
703 },
704
705 _on: function( suppressDisabledCheck, element, handlers ) {
706 var delegateElement,
707 instance = this;
708
709 // no suppressDisabledCheck flag, shuffle arguments
710 if ( typeof suppressDisabledCheck !== "boolean" ) {
711 handlers = element;
712 element = suppressDisabledCheck;
713 suppressDisabledCheck = false;
714 }
715
716 // no element argument, shuffle and use this.element
717 if ( !handlers ) {
718 handlers = element;
719 element = this.element;
720 delegateElement = this.widget();
721 } else {
722 // accept selectors, DOM elements
723 element = delegateElement = $( element );
724 this.bindings = this.bindings.add( element );
725 }
726
727 $.each( handlers, function( event, handler ) {
728 function handlerProxy() {
729 // allow widgets to customize the disabled handling
730 // - disabled as an array instead of boolean
731 // - disabled class as method for disabling individual parts
732 if ( !suppressDisabledCheck &&
733 ( instance.options.disabled === true ||
734 $( this ).hasClass( "ui-state-disabled" ) ) ) {
735 return;
736 }
737 return ( typeof handler === "string" ? instance[ handler ] : handler )
738 .apply( instance, arguments );
739 }
740
741 // copy the guid so direct unbinding works
742 if ( typeof handler !== "string" ) {
743 handlerProxy.guid = handler.guid =
744 handler.guid || handlerProxy.guid || $.guid++;
745 }
746
747 var match = event.match( /^(\w+)\s*(.*)$/ ),
748 eventName = match[1] + instance.eventNamespace,
749 selector = match[2];
750 if ( selector ) {
751 delegateElement.delegate( selector, eventName, handlerProxy );
752 } else {
753 element.bind( eventName, handlerProxy );
754 }
755 });
756 },
757
758 _off: function( element, eventName ) {
759 eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
760 element.unbind( eventName ).undelegate( eventName );
761 },
762
763 _delay: function( handler, delay ) {
764 function handlerProxy() {
765 return ( typeof handler === "string" ? instance[ handler ] : handler )
766 .apply( instance, arguments );
767 }
768 var instance = this;
769 return setTimeout( handlerProxy, delay || 0 );
770 },
771
772 _hoverable: function( element ) {
773 this.hoverable = this.hoverable.add( element );
774 this._on( element, {
775 mouseenter: function( event ) {
776 $( event.currentTarget ).addClass( "ui-state-hover" );
777 },
778 mouseleave: function( event ) {
779 $( event.currentTarget ).removeClass( "ui-state-hover" );
780 }
781 });
782 },
783
784 _focusable: function( element ) {
785 this.focusable = this.focusable.add( element );
786 this._on( element, {
787 focusin: function( event ) {
788 $( event.currentTarget ).addClass( "ui-state-focus" );
789 },
790 focusout: function( event ) {
791 $( event.currentTarget ).removeClass( "ui-state-focus" );
792 }
793 });
794 },
795
796 _trigger: function( type, event, data ) {
797 var prop, orig,
798 callback = this.options[ type ];
799
800 data = data || {};
801 event = $.Event( event );
802 event.type = ( type === this.widgetEventPrefix ?
803 type :
804 this.widgetEventPrefix + type ).toLowerCase();
805 // the original event may come from any element
806 // so we need to reset the target on the new event
807 event.target = this.element[ 0 ];
808
809 // copy original event properties over to the new event
810 orig = event.originalEvent;
811 if ( orig ) {
812 for ( prop in orig ) {
813 if ( !( prop in event ) ) {
814 event[ prop ] = orig[ prop ];
815 }
816 }
817 }
818
819 this.element.trigger( event, data );
820 return !( $.isFunction( callback ) &&
821 callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
822 event.isDefaultPrevented() );
823 }
824 };
825
826 $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
827 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
828 if ( typeof options === "string" ) {
829 options = { effect: options };
830 }
831 var hasOptions,
832 effectName = !options ?
833 method :
834 options === true || typeof options === "number" ?
835 defaultEffect :
836 options.effect || defaultEffect;
837 options = options || {};
838 if ( typeof options === "number" ) {
839 options = { duration: options };
840 }
841 hasOptions = !$.isEmptyObject( options );
842 options.complete = callback;
843 if ( options.delay ) {
844 element.delay( options.delay );
845 }
846 if ( hasOptions && $.effects && ( $.effects.effect[ effectName ] || $.uiBackCompat !== false && $.effects[ effectName ] ) ) {
847 element[ method ]( options );
848 } else if ( effectName !== method && element[ effectName ] ) {
849 element[ effectName ]( options.duration, options.easing, callback );
850 } else {
851 element.queue(function( next ) {
852 $( this )[ method ]();
853 if ( callback ) {
854 callback.call( element[ 0 ] );
855 }
856 next();
857 });
858 }
859 };
860 });
861
862 // DEPRECATED
863 if ( $.uiBackCompat !== false ) {
864 $.Widget.prototype._getCreateOptions = function() {
865 return $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ];
866 };
867 }
868
869 })( jQuery );
870 (function( $, undefined ) {
871
872 var mouseHandled = false;
873 $( document ).mouseup( function( e ) {
874 mouseHandled = false;
875 });
876
877 $.widget("ui.mouse", {
878 version: "1.9.2",
879 options: {
880 cancel: 'input,textarea,button,select,option',
881 distance: 1,
882 delay: 0
883 },
884 _mouseInit: function() {
885 var that = this;
886
887 this.element
888 .bind('mousedown.'+this.widgetName, function(event) {
889 return that._mouseDown(event);
890 })
891 .bind('click.'+this.widgetName, function(event) {
892 if (true === $.data(event.target, that.widgetName + '.preventClickEvent')) {
893 $.removeData(event.target, that.widgetName + '.preventClickEvent');
894 event.stopImmediatePropagation();
895 return false;
896 }
897 });
898
899 this.started = false;
900 },
901
902 // TODO: make sure destroying one instance of mouse doesn't mess with
903 // other instances of mouse
904 _mouseDestroy: function() {
905 this.element.unbind('.'+this.widgetName);
906 if ( this._mouseMoveDelegate ) {
907 $(document)
908 .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
909 .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
910 }
911 },
912
913 _mouseDown: function(event) {
914 // don't let more than one widget handle mouseStart
915 if( mouseHandled ) { return; }
916
917 // we may have missed mouseup (out of window)
918 (this._mouseStarted && this._mouseUp(event));
919
920 this._mouseDownEvent = event;
921
922 var that = this,
923 btnIsLeft = (event.which === 1),
924 // event.target.nodeName works around a bug in IE 8 with
925 // disabled inputs (#7620)
926 elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
927 if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
928 return true;
929 }
930
931 this.mouseDelayMet = !this.options.delay;
932 if (!this.mouseDelayMet) {
933 this._mouseDelayTimer = setTimeout(function() {
934 that.mouseDelayMet = true;
935 }, this.options.delay);
936 }
937
938 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
939 this._mouseStarted = (this._mouseStart(event) !== false);
940 if (!this._mouseStarted) {
941 event.preventDefault();
942 return true;
943 }
944 }
945
946 // Click event may never have fired (Gecko & Opera)
947 if (true === $.data(event.target, this.widgetName + '.preventClickEvent')) {
948 $.removeData(event.target, this.widgetName + '.preventClickEvent');
949 }
950
951 // these delegates are required to keep context
952 this._mouseMoveDelegate = function(event) {
953 return that._mouseMove(event);
954 };
955 this._mouseUpDelegate = function(event) {
956 return that._mouseUp(event);
957 };
958 $(document)
959 .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
960 .bind('mouseup.'+this.widgetName, this._mouseUpDelegate);
961
962 event.preventDefault();
963
964 mouseHandled = true;
965 return true;
966 },
967
968 _mouseMove: function(event) {
969 // IE mouseup check - mouseup happened when mouse was out of window
970 if ($.ui.ie && !(document.documentMode >= 9) && !event.button) {
971 return this._mouseUp(event);
972 }
973
974 if (this._mouseStarted) {
975 this._mouseDrag(event);
976 return event.preventDefault();
977 }
978
979 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
980 this._mouseStarted =
981 (this._mouseStart(this._mouseDownEvent, event) !== false);
982 (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
983 }
984
985 return !this._mouseStarted;
986 },
987
988 _mouseUp: function(event) {
989 $(document)
990 .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
991 .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
992
993 if (this._mouseStarted) {
994 this._mouseStarted = false;
995
996 if (event.target === this._mouseDownEvent.target) {
997 $.data(event.target, this.widgetName + '.preventClickEvent', true);
998 }
999
1000 this._mouseStop(event);
1001 }
1002
1003 return false;
1004 },
1005
1006 _mouseDistanceMet: function(event) {
1007 return (Math.max(
1008 Math.abs(this._mouseDownEvent.pageX - event.pageX),
1009 Math.abs(this._mouseDownEvent.pageY - event.pageY)
1010 ) >= this.options.distance
1011 );
1012 },
1013
1014 _mouseDelayMet: function(event) {
1015 return this.mouseDelayMet;
1016 },
1017
1018 // These are placeholder methods, to be overriden by extending plugin
1019 _mouseStart: function(event) {},
1020 _mouseDrag: function(event) {},
1021 _mouseStop: function(event) {},
1022 _mouseCapture: function(event) { return true; }
1023 });
1024
1025 })(jQuery);
1026 (function( $, undefined ) {
1027
1028 $.ui = $.ui || {};
1029
1030 var cachedScrollbarWidth,
1031 max = Math.max,
1032 abs = Math.abs,
1033 round = Math.round,
1034 rhorizontal = /left|center|right/,
1035 rvertical = /top|center|bottom/,
1036 roffset = /[\+\-]\d+%?/,
1037 rposition = /^\w+/,
1038 rpercent = /%$/,
1039 _position = $.fn.position;
1040
1041 function getOffsets( offsets, width, height ) {
1042 return [
1043 parseInt( offsets[ 0 ], 10 ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
1044 parseInt( offsets[ 1 ], 10 ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
1045 ];
1046 }
1047 function parseCss( element, property ) {
1048 return parseInt( $.css( element, property ), 10 ) || 0;
1049 }
1050
1051 $.position = {
1052 scrollbarWidth: function() {
1053 if ( cachedScrollbarWidth !== undefined ) {
1054 return cachedScrollbarWidth;
1055 }
1056 var w1, w2,
1057 div = $( "<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
1058 innerDiv = div.children()[0];
1059
1060 $( "body" ).append( div );
1061 w1 = innerDiv.offsetWidth;
1062 div.css( "overflow", "scroll" );
1063
1064 w2 = innerDiv.offsetWidth;
1065
1066 if ( w1 === w2 ) {
1067 w2 = div[0].clientWidth;
1068 }
1069
1070 div.remove();
1071
1072 return (cachedScrollbarWidth = w1 - w2);
1073 },
1074 getScrollInfo: function( within ) {
1075 var overflowX = within.isWindow ? "" : within.element.css( "overflow-x" ),
1076 overflowY = within.isWindow ? "" : within.element.css( "overflow-y" ),
1077 hasOverflowX = overflowX === "scroll" ||
1078 ( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
1079 hasOverflowY = overflowY === "scroll" ||
1080 ( overflowY === "auto" && within.height < within.element[0].scrollHeight );
1081 return {
1082 width: hasOverflowX ? $.position.scrollbarWidth() : 0,
1083 height: hasOverflowY ? $.position.scrollbarWidth() : 0
1084 };
1085 },
1086 getWithinInfo: function( element ) {
1087 var withinElement = $( element || window ),
1088 isWindow = $.isWindow( withinElement[0] );
1089 return {
1090 element: withinElement,
1091 isWindow: isWindow,
1092 offset: withinElement.offset() || { left: 0, top: 0 },
1093 scrollLeft: withinElement.scrollLeft(),
1094 scrollTop: withinElement.scrollTop(),
1095 width: isWindow ? withinElement.width() : withinElement.outerWidth(),
1096 height: isWindow ? withinElement.height() : withinElement.outerHeight()
1097 };
1098 }
1099 };
1100
1101 $.fn.position = function( options ) {
1102 if ( !options || !options.of ) {
1103 return _position.apply( this, arguments );
1104 }
1105
1106 // make a copy, we don't want to modify arguments
1107 options = $.extend( {}, options );
1108
1109 var atOffset, targetWidth, targetHeight, targetOffset, basePosition,
1110 target = $( options.of ),
1111 within = $.position.getWithinInfo( options.within ),
1112 scrollInfo = $.position.getScrollInfo( within ),
1113 targetElem = target[0],
1114 collision = ( options.collision || "flip" ).split( " " ),
1115 offsets = {};
1116
1117 if ( targetElem.nodeType === 9 ) {
1118 targetWidth = target.width();
1119 targetHeight = target.height();
1120 targetOffset = { top: 0, left: 0 };
1121 } else if ( $.isWindow( targetElem ) ) {
1122 targetWidth = target.width();
1123 targetHeight = target.height();
1124 targetOffset = { top: target.scrollTop(), left: target.scrollLeft() };
1125 } else if ( targetElem.preventDefault ) {
1126 // force left top to allow flipping
1127 options.at = "left top";
1128 targetWidth = targetHeight = 0;
1129 targetOffset = { top: targetElem.pageY, left: targetElem.pageX };
1130 } else {
1131 targetWidth = target.outerWidth();
1132 targetHeight = target.outerHeight();
1133 targetOffset = target.offset();
1134 }
1135 // clone to reuse original targetOffset later
1136 basePosition = $.extend( {}, targetOffset );
1137
1138 // force my and at to have valid horizontal and vertical positions
1139 // if a value is missing or invalid, it will be converted to center
1140 $.each( [ "my", "at" ], function() {
1141 var pos = ( options[ this ] || "" ).split( " " ),
1142 horizontalOffset,
1143 verticalOffset;
1144
1145 if ( pos.length === 1) {
1146 pos = rhorizontal.test( pos[ 0 ] ) ?
1147 pos.concat( [ "center" ] ) :
1148 rvertical.test( pos[ 0 ] ) ?
1149 [ "center" ].concat( pos ) :
1150 [ "center", "center" ];
1151 }
1152 pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
1153 pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
1154
1155 // calculate offsets
1156 horizontalOffset = roffset.exec( pos[ 0 ] );
1157 verticalOffset = roffset.exec( pos[ 1 ] );
1158 offsets[ this ] = [
1159 horizontalOffset ? horizontalOffset[ 0 ] : 0,
1160 verticalOffset ? verticalOffset[ 0 ] : 0
1161 ];
1162
1163 // reduce to just the positions without the offsets
1164 options[ this ] = [
1165 rposition.exec( pos[ 0 ] )[ 0 ],
1166 rposition.exec( pos[ 1 ] )[ 0 ]
1167 ];
1168 });
1169
1170 // normalize collision option
1171 if ( collision.length === 1 ) {
1172 collision[ 1 ] = collision[ 0 ];
1173 }
1174
1175 if ( options.at[ 0 ] === "right" ) {
1176 basePosition.left += targetWidth;
1177 } else if ( options.at[ 0 ] === "center" ) {
1178 basePosition.left += targetWidth / 2;
1179 }
1180
1181 if ( options.at[ 1 ] === "bottom" ) {
1182 basePosition.top += targetHeight;
1183 } else if ( options.at[ 1 ] === "center" ) {
1184 basePosition.top += targetHeight / 2;
1185 }
1186
1187 atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
1188 basePosition.left += atOffset[ 0 ];
1189 basePosition.top += atOffset[ 1 ];
1190
1191 return this.each(function() {
1192 var collisionPosition, using,
1193 elem = $( this ),
1194 elemWidth = elem.outerWidth(),
1195 elemHeight = elem.outerHeight(),
1196 marginLeft = parseCss( this, "marginLeft" ),
1197 marginTop = parseCss( this, "marginTop" ),
1198 collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
1199 collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
1200 position = $.extend( {}, basePosition ),
1201 myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
1202
1203 if ( options.my[ 0 ] === "right" ) {
1204 position.left -= elemWidth;
1205 } else if ( options.my[ 0 ] === "center" ) {
1206 position.left -= elemWidth / 2;
1207 }
1208
1209 if ( options.my[ 1 ] === "bottom" ) {
1210 position.top -= elemHeight;
1211 } else if ( options.my[ 1 ] === "center" ) {
1212 position.top -= elemHeight / 2;
1213 }
1214
1215 position.left += myOffset[ 0 ];
1216 position.top += myOffset[ 1 ];
1217
1218 // if the browser doesn't support fractions, then round for consistent results
1219 if ( !$.support.offsetFractions ) {
1220 position.left = round( position.left );
1221 position.top = round( position.top );
1222 }
1223
1224 collisionPosition = {
1225 marginLeft: marginLeft,
1226 marginTop: marginTop
1227 };
1228
1229 $.each( [ "left", "top" ], function( i, dir ) {
1230 if ( $.ui.position[ collision[ i ] ] ) {
1231 $.ui.position[ collision[ i ] ][ dir ]( position, {
1232 targetWidth: targetWidth,
1233 targetHeight: targetHeight,
1234 elemWidth: elemWidth,
1235 elemHeight: elemHeight,
1236 collisionPosition: collisionPosition,
1237 collisionWidth: collisionWidth,
1238 collisionHeight: collisionHeight,
1239 offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
1240 my: options.my,
1241 at: options.at,
1242 within: within,
1243 elem : elem
1244 });
1245 }
1246 });
1247
1248 if ( $.fn.bgiframe ) {
1249 elem.bgiframe();
1250 }
1251
1252 if ( options.using ) {
1253 // adds feedback as second argument to using callback, if present
1254 using = function( props ) {
1255 var left = targetOffset.left - position.left,
1256 right = left + targetWidth - elemWidth,
1257 top = targetOffset.top - position.top,
1258 bottom = top + targetHeight - elemHeight,
1259 feedback = {
1260 target: {
1261 element: target,
1262 left: targetOffset.left,
1263 top: targetOffset.top,
1264 width: targetWidth,
1265 height: targetHeight
1266 },
1267 element: {
1268 element: elem,
1269 left: position.left,
1270 top: position.top,
1271 width: elemWidth,
1272 height: elemHeight
1273 },
1274 horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
1275 vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
1276 };
1277 if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
1278 feedback.horizontal = "center";
1279 }
1280 if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
1281 feedback.vertical = "middle";
1282 }
1283 if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
1284 feedback.important = "horizontal";
1285 } else {
1286 feedback.important = "vertical";
1287 }
1288 options.using.call( this, props, feedback );
1289 };
1290 }
1291
1292 elem.offset( $.extend( position, { using: using } ) );
1293 });
1294 };
1295
1296 $.ui.position = {
1297 fit: {
1298 left: function( position, data ) {
1299 var within = data.within,
1300 withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
1301 outerWidth = within.width,
1302 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1303 overLeft = withinOffset - collisionPosLeft,
1304 overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
1305 newOverRight;
1306
1307 // element is wider than within
1308 if ( data.collisionWidth > outerWidth ) {
1309 // element is initially over the left side of within
1310 if ( overLeft > 0 && overRight <= 0 ) {
1311 newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
1312 position.left += overLeft - newOverRight;
1313 // element is initially over right side of within
1314 } else if ( overRight > 0 && overLeft <= 0 ) {
1315 position.left = withinOffset;
1316 // element is initially over both left and right sides of within
1317 } else {
1318 if ( overLeft > overRight ) {
1319 position.left = withinOffset + outerWidth - data.collisionWidth;
1320 } else {
1321 position.left = withinOffset;
1322 }
1323 }
1324 // too far left -> align with left edge
1325 } else if ( overLeft > 0 ) {
1326 position.left += overLeft;
1327 // too far right -> align with right edge
1328 } else if ( overRight > 0 ) {
1329 position.left -= overRight;
1330 // adjust based on position and margin
1331 } else {
1332 position.left = max( position.left - collisionPosLeft, position.left );
1333 }
1334 },
1335 top: function( position, data ) {
1336 var within = data.within,
1337 withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
1338 outerHeight = data.within.height,
1339 collisionPosTop = position.top - data.collisionPosition.marginTop,
1340 overTop = withinOffset - collisionPosTop,
1341 overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
1342 newOverBottom;
1343
1344 // element is taller than within
1345 if ( data.collisionHeight > outerHeight ) {
1346 // element is initially over the top of within
1347 if ( overTop > 0 && overBottom <= 0 ) {
1348 newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
1349 position.top += overTop - newOverBottom;
1350 // element is initially over bottom of within
1351 } else if ( overBottom > 0 && overTop <= 0 ) {
1352 position.top = withinOffset;
1353 // element is initially over both top and bottom of within
1354 } else {
1355 if ( overTop > overBottom ) {
1356 position.top = withinOffset + outerHeight - data.collisionHeight;
1357 } else {
1358 position.top = withinOffset;
1359 }
1360 }
1361 // too far up -> align with top
1362 } else if ( overTop > 0 ) {
1363 position.top += overTop;
1364 // too far down -> align with bottom edge
1365 } else if ( overBottom > 0 ) {
1366 position.top -= overBottom;
1367 // adjust based on position and margin
1368 } else {
1369 position.top = max( position.top - collisionPosTop, position.top );
1370 }
1371 }
1372 },
1373 flip: {
1374 left: function( position, data ) {
1375 var within = data.within,
1376 withinOffset = within.offset.left + within.scrollLeft,
1377 outerWidth = within.width,
1378 offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
1379 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1380 overLeft = collisionPosLeft - offsetLeft,
1381 overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
1382 myOffset = data.my[ 0 ] === "left" ?
1383 -data.elemWidth :
1384 data.my[ 0 ] === "right" ?
1385 data.elemWidth :
1386 0,
1387 atOffset = data.at[ 0 ] === "left" ?
1388 data.targetWidth :
1389 data.at[ 0 ] === "right" ?
1390 -data.targetWidth :
1391 0,
1392 offset = -2 * data.offset[ 0 ],
1393 newOverRight,
1394 newOverLeft;
1395
1396 if ( overLeft < 0 ) {
1397 newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
1398 if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
1399 position.left += myOffset + atOffset + offset;
1400 }
1401 }
1402 else if ( overRight > 0 ) {
1403 newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
1404 if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
1405 position.left += myOffset + atOffset + offset;
1406 }
1407 }
1408 },
1409 top: function( position, data ) {
1410 var within = data.within,
1411 withinOffset = within.offset.top + within.scrollTop,
1412 outerHeight = within.height,
1413 offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
1414 collisionPosTop = position.top - data.collisionPosition.marginTop,
1415 overTop = collisionPosTop - offsetTop,
1416 overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
1417 top = data.my[ 1 ] === "top",
1418 myOffset = top ?
1419 -data.elemHeight :
1420 data.my[ 1 ] === "bottom" ?
1421 data.elemHeight :
1422 0,
1423 atOffset = data.at[ 1 ] === "top" ?
1424 data.targetHeight :
1425 data.at[ 1 ] === "bottom" ?
1426 -data.targetHeight :
1427 0,
1428 offset = -2 * data.offset[ 1 ],
1429 newOverTop,
1430 newOverBottom;
1431 if ( overTop < 0 ) {
1432 newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
1433 if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) {
1434 position.top += myOffset + atOffset + offset;
1435 }
1436 }
1437 else if ( overBottom > 0 ) {
1438 newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
1439 if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) {
1440 position.top += myOffset + atOffset + offset;
1441 }
1442 }
1443 }
1444 },
1445 flipfit: {
1446 left: function() {
1447 $.ui.position.flip.left.apply( this, arguments );
1448 $.ui.position.fit.left.apply( this, arguments );
1449 },
1450 top: function() {
1451 $.ui.position.flip.top.apply( this, arguments );
1452 $.ui.position.fit.top.apply( this, arguments );
1453 }
1454 }
1455 };
1456
1457 // fraction support test
1458 (function () {
1459 var testElement, testElementParent, testElementStyle, offsetLeft, i,
1460 body = document.getElementsByTagName( "body" )[ 0 ],
1461 div = document.createElement( "div" );
1462
1463 //Create a "fake body" for testing based on method used in jQuery.support
1464 testElement = document.createElement( body ? "div" : "body" );
1465 testElementStyle = {
1466 visibility: "hidden",
1467 width: 0,
1468 height: 0,
1469 border: 0,
1470 margin: 0,
1471 background: "none"
1472 };
1473 if ( body ) {
1474 $.extend( testElementStyle, {
1475 position: "absolute",
1476 left: "-1000px",
1477 top: "-1000px"
1478 });
1479 }
1480 for ( i in testElementStyle ) {
1481 testElement.style[ i ] = testElementStyle[ i ];
1482 }
1483 testElement.appendChild( div );
1484 testElementParent = body || document.documentElement;
1485 testElementParent.insertBefore( testElement, testElementParent.firstChild );
1486
1487 div.style.cssText = "position: absolute; left: 10.7432222px;";
1488
1489 offsetLeft = $( div ).offset().left;
1490 $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11;
1491
1492 testElement.innerHTML = "";
1493 testElementParent.removeChild( testElement );
1494 })();
1495
1496 // DEPRECATED
1497 if ( $.uiBackCompat !== false ) {
1498 // offset option
1499 (function( $ ) {
1500 var _position = $.fn.position;
1501 $.fn.position = function( options ) {
1502 if ( !options || !options.offset ) {
1503 return _position.call( this, options );
1504 }
1505 var offset = options.offset.split( " " ),
1506 at = options.at.split( " " );
1507 if ( offset.length === 1 ) {
1508 offset[ 1 ] = offset[ 0 ];
1509 }
1510 if ( /^\d/.test( offset[ 0 ] ) ) {
1511 offset[ 0 ] = "+" + offset[ 0 ];
1512 }
1513 if ( /^\d/.test( offset[ 1 ] ) ) {
1514 offset[ 1 ] = "+" + offset[ 1 ];
1515 }
1516 if ( at.length === 1 ) {
1517 if ( /left|center|right/.test( at[ 0 ] ) ) {
1518 at[ 1 ] = "center";
1519 } else {
1520 at[ 1 ] = at[ 0 ];
1521 at[ 0 ] = "center";
1522 }
1523 }
1524 return _position.call( this, $.extend( options, {
1525 at: at[ 0 ] + offset[ 0 ] + " " + at[ 1 ] + offset[ 1 ],
1526 offset: undefined
1527 } ) );
1528 };
1529 }( jQuery ) );
1530 }
1531
1532 }( jQuery ) );
1533 (function( $, undefined ) {
1534
1535 $.widget("ui.draggable", $.ui.mouse, {
1536 version: "1.9.2",
1537 widgetEventPrefix: "drag",
1538 options: {
1539 addClasses: true,
1540 appendTo: "parent",
1541 axis: false,
1542 connectToSortable: false,
1543 containment: false,
1544 cursor: "auto",
1545 cursorAt: false,
1546 grid: false,
1547 handle: false,
1548 helper: "original",
1549 iframeFix: false,
1550 opacity: false,
1551 refreshPositions: false,
1552 revert: false,
1553 revertDuration: 500,
1554 scope: "default",
1555 scroll: true,
1556 scrollSensitivity: 20,
1557 scrollSpeed: 20,
1558 snap: false,
1559 snapMode: "both",
1560 snapTolerance: 20,
1561 stack: false,
1562 zIndex: false
1563 },
1564 _create: function() {
1565
1566 if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position")))
1567 this.element[0].style.position = 'relative';
1568
1569 (this.options.addClasses && this.element.addClass("ui-draggable"));
1570 (this.options.disabled && this.element.addClass("ui-draggable-disabled"));
1571
1572 this._mouseInit();
1573
1574 },
1575
1576 _destroy: function() {
1577 this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
1578 this._mouseDestroy();
1579 },
1580
1581 _mouseCapture: function(event) {
1582
1583 var o = this.options;
1584
1585 // among others, prevent a drag on a resizable-handle
1586 if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle'))
1587 return false;
1588
1589 //Quit if we're not on a valid handle
1590 this.handle = this._getHandle(event);
1591 if (!this.handle)
1592 return false;
1593
1594 $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
1595 $('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>')
1596 .css({
1597 width: this.offsetWidth+"px", height: this.offsetHeight+"px",
1598 position: "absolute", opacity: "0.001", zIndex: 1000
1599 })
1600 .css($(this).offset())
1601 .appendTo("body");
1602 });
1603
1604 return true;
1605
1606 },
1607
1608 _mouseStart: function(event) {
1609
1610 var o = this.options;
1611
1612 //Create and append the visible helper
1613 this.helper = this._createHelper(event);
1614
1615 this.helper.addClass("ui-draggable-dragging");
1616
1617 //Cache the helper size
1618 this._cacheHelperProportions();
1619
1620 //If ddmanager is used for droppables, set the global draggable
1621 if($.ui.ddmanager)
1622 $.ui.ddmanager.current = this;
1623
1624 /*
1625 * - Position generation -
1626 * This block generates everything position related - it's the core of draggables.
1627 */
1628
1629 //Cache the margins of the original element
1630 this._cacheMargins();
1631
1632 //Store the helper's css position
1633 this.cssPosition = this.helper.css("position");
1634 this.scrollParent = this.helper.scrollParent();
1635
1636 //The element's absolute position on the page minus margins
1637 this.offset = this.positionAbs = this.element.offset();
1638 this.offset = {
1639 top: this.offset.top - this.margins.top,
1640 left: this.offset.left - this.margins.left
1641 };
1642
1643 $.extend(this.offset, {
1644 click: { //Where the click happened, relative to the element
1645 left: event.pageX - this.offset.left,
1646 top: event.pageY - this.offset.top
1647 },
1648 parent: this._getParentOffset(),
1649 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
1650 });
1651
1652 //Generate the original position
1653 this.originalPosition = this.position = this._generatePosition(event);
1654 this.originalPageX = event.pageX;
1655 this.originalPageY = event.pageY;
1656
1657 //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
1658 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
1659
1660 //Set a containment if given in the options
1661 if(o.containment)
1662 this._setContainment();
1663
1664 //Trigger event + callbacks
1665 if(this._trigger("start", event) === false) {
1666 this._clear();
1667 return false;
1668 }
1669
1670 //Recache the helper size
1671 this._cacheHelperProportions();
1672
1673 //Prepare the droppable offsets
1674 if ($.ui.ddmanager && !o.dropBehaviour)
1675 $.ui.ddmanager.prepareOffsets(this, event);
1676
1677
1678 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
1679
1680 //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
1681 if ( $.ui.ddmanager ) $.ui.ddmanager.dragStart(this, event);
1682
1683 return true;
1684 },
1685
1686 _mouseDrag: function(event, noPropagation) {
1687
1688 //Compute the helpers position
1689 this.position = this._generatePosition(event);
1690 this.positionAbs = this._convertPositionTo("absolute");
1691
1692 //Call plugins and callbacks and use the resulting position if something is returned
1693 if (!noPropagation) {
1694 var ui = this._uiHash();
1695 if(this._trigger('drag', event, ui) === false) {
1696 this._mouseUp({});
1697 return false;
1698 }
1699 this.position = ui.position;
1700 }
1701
1702 if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
1703 if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
1704 if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
1705
1706 return false;
1707 },
1708
1709 _mouseStop: function(event) {
1710
1711 //If we are using droppables, inform the manager about the drop
1712 var dropped = false;
1713 if ($.ui.ddmanager && !this.options.dropBehaviour)
1714 dropped = $.ui.ddmanager.drop(this, event);
1715
1716 //if a drop comes from outside (a sortable)
1717 if(this.dropped) {
1718 dropped = this.dropped;
1719 this.dropped = false;
1720 }
1721
1722 //if the original element is no longer in the DOM don't bother to continue (see #8269)
1723 var element = this.element[0], elementInDom = false;
1724 while ( element && (element = element.parentNode) ) {
1725 if (element == document ) {
1726 elementInDom = true;
1727 }
1728 }
1729 if ( !elementInDom && this.options.helper === "original" )
1730 return false;
1731
1732 if((this.options.revert == "invalid" && !dropped) || (this.options.revert == "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) {
1733 var that = this;
1734 $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
1735 if(that._trigger("stop", event) !== false) {
1736 that._clear();
1737 }
1738 });
1739 } else {
1740 if(this._trigger("stop", event) !== false) {
1741 this._clear();
1742 }
1743 }
1744
1745 return false;
1746 },
1747
1748 _mouseUp: function(event) {
1749 //Remove frame helpers
1750 $("div.ui-draggable-iframeFix").each(function() {
1751 this.parentNode.removeChild(this);
1752 });
1753
1754 //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
1755 if( $.ui.ddmanager ) $.ui.ddmanager.dragStop(this, event);
1756
1757 return $.ui.mouse.prototype._mouseUp.call(this, event);
1758 },
1759
1760 cancel: function() {
1761
1762 if(this.helper.is(".ui-draggable-dragging")) {
1763 this._mouseUp({});
1764 } else {
1765 this._clear();
1766 }
1767
1768 return this;
1769
1770 },
1771
1772 _getHandle: function(event) {
1773
1774 var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false;
1775 $(this.options.handle, this.element)
1776 .find("*")
1777 .andSelf()
1778 .each(function() {
1779 if(this == event.target) handle = true;
1780 });
1781
1782 return handle;
1783
1784 },
1785
1786 _createHelper: function(event) {
1787
1788 var o = this.options;
1789 var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone().removeAttr('id') : this.element);
1790
1791 if(!helper.parents('body').length)
1792 helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo));
1793
1794 if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position")))
1795 helper.css("position", "absolute");
1796
1797 return helper;
1798
1799 },
1800
1801 _adjustOffsetFromHelper: function(obj) {
1802 if (typeof obj == 'string') {
1803 obj = obj.split(' ');
1804 }
1805 if ($.isArray(obj)) {
1806 obj = {left: +obj[0], top: +obj[1] || 0};
1807 }
1808 if ('left' in obj) {
1809 this.offset.click.left = obj.left + this.margins.left;
1810 }
1811 if ('right' in obj) {
1812 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
1813 }
1814 if ('top' in obj) {
1815 this.offset.click.top = obj.top + this.margins.top;
1816 }
1817 if ('bottom' in obj) {
1818 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
1819 }
1820 },
1821
1822 _getParentOffset: function() {
1823
1824 //Get the offsetParent and cache its position
1825 this.offsetParent = this.helper.offsetParent();
1826 var po = this.offsetParent.offset();
1827
1828 // This is a special case where we need to modify a offset calculated on start, since the following happened:
1829 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
1830 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
1831 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
1832 if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
1833 po.left += this.scrollParent.scrollLeft();
1834 po.top += this.scrollParent.scrollTop();
1835 }
1836
1837 if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information
1838 || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.ui.ie)) //Ugly IE fix
1839 po = { top: 0, left: 0 };
1840
1841 return {
1842 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
1843 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
1844 };
1845
1846 },
1847
1848 _getRelativeOffset: function() {
1849
1850 if(this.cssPosition == "relative") {
1851 var p = this.element.position();
1852 return {
1853 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
1854 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
1855 };
1856 } else {
1857 return { top: 0, left: 0 };
1858 }
1859
1860 },
1861
1862 _cacheMargins: function() {
1863 this.margins = {
1864 left: (parseInt(this.element.css("marginLeft"),10) || 0),
1865 top: (parseInt(this.element.css("marginTop"),10) || 0),
1866 right: (parseInt(this.element.css("marginRight"),10) || 0),
1867 bottom: (parseInt(this.element.css("marginBottom"),10) || 0)
1868 };
1869 },
1870
1871 _cacheHelperProportions: function() {
1872 this.helperProportions = {
1873 width: this.helper.outerWidth(),
1874 height: this.helper.outerHeight()
1875 };
1876 },
1877
1878 _setContainment: function() {
1879
1880 var o = this.options;
1881 if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
1882 if(o.containment == 'document' || o.containment == 'window') this.containment = [
1883 o.containment == 'document' ? 0 : $(window).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
1884 o.containment == 'document' ? 0 : $(window).scrollTop() - this.offset.relative.top - this.offset.parent.top,
1885 (o.containment == 'document' ? 0 : $(window).scrollLeft()) + $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left,
1886 (o.containment == 'document' ? 0 : $(window).scrollTop()) + ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
1887 ];
1888
1889 if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) {
1890 var c = $(o.containment);
1891 var ce = c[0]; if(!ce) return;
1892 var co = c.offset();
1893 var over = ($(ce).css("overflow") != 'hidden');
1894
1895 this.containment = [
1896 (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0),
1897 (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0),
1898 (over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left - this.margins.right,
1899 (over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - this.margins.bottom
1900 ];
1901 this.relative_container = c;
1902
1903 } else if(o.containment.constructor == Array) {
1904 this.containment = o.containment;
1905 }
1906
1907 },
1908
1909 _convertPositionTo: function(d, pos) {
1910
1911 if(!pos) pos = this.position;
1912 var mod = d == "absolute" ? 1 : -1;
1913 var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
1914
1915 return {
1916 top: (
1917 pos.top // The absolute mouse position
1918 + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent
1919 + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border)
1920 - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
1921 ),
1922 left: (
1923 pos.left // The absolute mouse position
1924 + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent
1925 + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border)
1926 - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
1927 )
1928 };
1929
1930 },
1931
1932 _generatePosition: function(event) {
1933
1934 var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
1935 var pageX = event.pageX;
1936 var pageY = event.pageY;
1937
1938 /*
1939 * - Position constraining -
1940 * Constrain the position to a mix of grid, containment.
1941 */
1942
1943 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
1944 var containment;
1945 if(this.containment) {
1946 if (this.relative_container){
1947 var co = this.relative_container.offset();
1948 containment = [ this.containment[0] + co.left,
1949 this.containment[1] + co.top,
1950 this.containment[2] + co.left,
1951 this.containment[3] + co.top ];
1952 }
1953 else {
1954 containment = this.containment;
1955 }
1956
1957 if(event.pageX - this.offset.click.left < containment[0]) pageX = containment[0] + this.offset.click.left;
1958 if(event.pageY - this.offset.click.top < containment[1]) pageY = containment[1] + this.offset.click.top;
1959 if(event.pageX - this.offset.click.left > containment[2]) pageX = containment[2] + this.offset.click.left;
1960 if(event.pageY - this.offset.click.top > containment[3]) pageY = containment[3] + this.offset.click.top;
1961 }
1962
1963 if(o.grid) {
1964 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
1965 var top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
1966 pageY = containment ? (!(top - this.offset.click.top < containment[1] || top - this.offset.click.top > containment[3]) ? top : (!(top - this.offset.click.top < containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
1967
1968 var left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
1969 pageX = containment ? (!(left - this.offset.click.left < containment[0] || left - this.offset.click.left > containment[2]) ? left : (!(left - this.offset.click.left < containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
1970 }
1971
1972 }
1973
1974 return {
1975 top: (
1976 pageY // The absolute mouse position
1977 - this.offset.click.top // Click offset (relative to the element)
1978 - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent
1979 - this.offset.parent.top // The offsetParent's offset without borders (offset + border)
1980 + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
1981 ),
1982 left: (
1983 pageX // The absolute mouse position
1984 - this.offset.click.left // Click offset (relative to the element)
1985 - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent
1986 - this.offset.parent.left // The offsetParent's offset without borders (offset + border)
1987 + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
1988 )
1989 };
1990
1991 },
1992
1993 _clear: function() {
1994 this.helper.removeClass("ui-draggable-dragging");
1995 if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove();
1996 //if($.ui.ddmanager) $.ui.ddmanager.current = null;
1997 this.helper = null;
1998 this.cancelHelperRemoval = false;
1999 },
2000
2001 // From now on bulk stuff - mainly helpers
2002
2003 _trigger: function(type, event, ui) {
2004 ui = ui || this._uiHash();
2005 $.ui.plugin.call(this, type, [event, ui]);
2006 if(type == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins
2007 return $.Widget.prototype._trigger.call(this, type, event, ui);
2008 },
2009
2010 plugins: {},
2011
2012 _uiHash: function(event) {
2013 return {
2014 helper: this.helper,
2015 position: this.position,
2016 originalPosition: this.originalPosition,
2017 offset: this.positionAbs
2018 };
2019 }
2020
2021 });
2022
2023 $.ui.plugin.add("draggable", "connectToSortable", {
2024 start: function(event, ui) {
2025
2026 var inst = $(this).data("draggable"), o = inst.options,
2027 uiSortable = $.extend({}, ui, { item: inst.element });
2028 inst.sortables = [];
2029 $(o.connectToSortable).each(function() {
2030 var sortable = $.data(this, 'sortable');
2031 if (sortable && !sortable.options.disabled) {
2032 inst.sortables.push({
2033 instance: sortable,
2034 shouldRevert: sortable.options.revert
2035 });
2036 sortable.refreshPositions(); // Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page).
2037 sortable._trigger("activate", event, uiSortable);
2038 }
2039 });
2040
2041 },
2042 stop: function(event, ui) {
2043
2044 //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
2045 var inst = $(this).data("draggable"),
2046 uiSortable = $.extend({}, ui, { item: inst.element });
2047
2048 $.each(inst.sortables, function() {
2049 if(this.instance.isOver) {
2050
2051 this.instance.isOver = 0;
2052
2053 inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
2054 this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
2055
2056 //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid'
2057 if(this.shouldRevert) this.instance.options.revert = true;
2058
2059 //Trigger the stop of the sortable
2060 this.instance._mouseStop(event);
2061
2062 this.instance.options.helper = this.instance.options._helper;
2063
2064 //If the helper has been the original item, restore properties in the sortable
2065 if(inst.options.helper == 'original')
2066 this.instance.currentItem.css({ top: 'auto', left: 'auto' });
2067
2068 } else {
2069 this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
2070 this.instance._trigger("deactivate", event, uiSortable);
2071 }
2072
2073 });
2074
2075 },
2076 drag: function(event, ui) {
2077
2078 var inst = $(this).data("draggable"), that = this;
2079
2080 var checkPos = function(o) {
2081 var dyClick = this.offset.click.top, dxClick = this.offset.click.left;
2082 var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left;
2083 var itemHeight = o.height, itemWidth = o.width;
2084 var itemTop = o.top, itemLeft = o.left;
2085
2086 return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth);
2087 };
2088
2089 $.each(inst.sortables, function(i) {
2090
2091 var innermostIntersecting = false;
2092 var thisSortable = this;
2093 //Copy over some variables to allow calling the sortable's native _intersectsWith
2094 this.instance.positionAbs = inst.positionAbs;
2095 this.instance.helperProportions = inst.helperProportions;
2096 this.instance.offset.click = inst.offset.click;
2097
2098 if(this.instance._intersectsWith(this.instance.containerCache)) {
2099 innermostIntersecting = true;
2100 $.each(inst.sortables, function () {
2101 this.instance.positionAbs = inst.positionAbs;
2102 this.instance.helperProportions = inst.helperProportions;
2103 this.instance.offset.click = inst.offset.click;
2104 if (this != thisSortable
2105 && this.instance._intersectsWith(this.instance.containerCache)
2106 && $.ui.contains(thisSortable.instance.element[0], this.instance.element[0]))
2107 innermostIntersecting = false;
2108 return innermostIntersecting;
2109 });
2110 }
2111
2112
2113 if(innermostIntersecting) {
2114 //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
2115 if(!this.instance.isOver) {
2116
2117 this.instance.isOver = 1;
2118 //Now we fake the start of dragging for the sortable instance,
2119 //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
2120 //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one)
2121 this.instance.currentItem = $(that).clone().removeAttr('id').appendTo(this.instance.element).data("sortable-item", true);
2122 this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
2123 this.instance.options.helper = function() { return ui.helper[0]; };
2124
2125 event.target = this.instance.currentItem[0];
2126 this.instance._mouseCapture(event, true);
2127 this.instance._mouseStart(event, true, true);
2128
2129 //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
2130 this.instance.offset.click.top = inst.offset.click.top;
2131 this.instance.offset.click.left = inst.offset.click.left;
2132 this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
2133 this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
2134
2135 inst._trigger("toSortable", event);
2136 inst.dropped = this.instance.element; //draggable revert needs that
2137 //hack so receive/update callbacks work (mostly)
2138 inst.currentItem = inst.element;
2139 this.instance.fromOutside = inst;
2140
2141 }
2142
2143 //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable
2144 if(this.instance.currentItem) this.instance._mouseDrag(event);
2145
2146 } else {
2147
2148 //If it doesn't intersect with the sortable, and it intersected before,
2149 //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
2150 if(this.instance.isOver) {
2151
2152 this.instance.isOver = 0;
2153 this.instance.cancelHelperRemoval = true;
2154
2155 //Prevent reverting on this forced stop
2156 this.instance.options.revert = false;
2157
2158 // The out event needs to be triggered independently
2159 this.instance._trigger('out', event, this.instance._uiHash(this.instance));
2160
2161 this.instance._mouseStop(event, true);
2162 this.instance.options.helper = this.instance.options._helper;
2163
2164 //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
2165 this.instance.currentItem.remove();
2166 if(this.instance.placeholder) this.instance.placeholder.remove();
2167
2168 inst._trigger("fromSortable", event);
2169 inst.dropped = false; //draggable revert needs that
2170 }
2171
2172 };
2173
2174 });
2175
2176 }
2177 });
2178
2179 $.ui.plugin.add("draggable", "cursor", {
2180 start: function(event, ui) {
2181 var t = $('body'), o = $(this).data('draggable').options;
2182 if (t.css("cursor")) o._cursor = t.css("cursor");
2183 t.css("cursor", o.cursor);
2184 },
2185 stop: function(event, ui) {
2186 var o = $(this).data('draggable').options;
2187 if (o._cursor) $('body').css("cursor", o._cursor);
2188 }
2189 });
2190
2191 $.ui.plugin.add("draggable", "opacity", {
2192 start: function(event, ui) {
2193 var t = $(ui.helper), o = $(this).data('draggable').options;
2194 if(t.css("opacity")) o._opacity = t.css("opacity");
2195 t.css('opacity', o.opacity);
2196 },
2197 stop: function(event, ui) {
2198 var o = $(this).data('draggable').options;
2199 if(o._opacity) $(ui.helper).css('opacity', o._opacity);
2200 }
2201 });
2202
2203 $.ui.plugin.add("draggable", "scroll", {
2204 start: function(event, ui) {
2205 var i = $(this).data("draggable");
2206 if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset();
2207 },
2208 drag: function(event, ui) {
2209
2210 var i = $(this).data("draggable"), o = i.options, scrolled = false;
2211
2212 if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') {
2213
2214 if(!o.axis || o.axis != 'x') {
2215 if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
2216 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
2217 else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity)
2218 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
2219 }
2220
2221 if(!o.axis || o.axis != 'y') {
2222 if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
2223 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
2224 else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity)
2225 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
2226 }
2227
2228 } else {
2229
2230 if(!o.axis || o.axis != 'x') {
2231 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
2232 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
2233 else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
2234 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
2235 }
2236
2237 if(!o.axis || o.axis != 'y') {
2238 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
2239 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
2240 else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
2241 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
2242 }
2243
2244 }
2245
2246 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
2247 $.ui.ddmanager.prepareOffsets(i, event);
2248
2249 }
2250 });
2251
2252 $.ui.plugin.add("draggable", "snap", {
2253 start: function(event, ui) {
2254
2255 var i = $(this).data("draggable"), o = i.options;
2256 i.snapElements = [];
2257
2258 $(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) : o.snap).each(function() {
2259 var $t = $(this); var $o = $t.offset();
2260 if(this != i.element[0]) i.snapElements.push({
2261 item: this,
2262 width: $t.outerWidth(), height: $t.outerHeight(),
2263 top: $o.top, left: $o.left
2264 });
2265 });
2266
2267 },
2268 drag: function(event, ui) {
2269
2270 var inst = $(this).data("draggable"), o = inst.options;
2271 var d = o.snapTolerance;
2272
2273 var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
2274 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
2275
2276 for (var i = inst.snapElements.length - 1; i >= 0; i--){
2277
2278 var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width,
2279 t = inst.snapElements[i].top, b = t + inst.snapElements[i].height;
2280
2281 //Yes, I know, this is insane ;)
2282 if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) {
2283 if(inst.snapElements[i].snapping) (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
2284 inst.snapElements[i].snapping = false;
2285 continue;
2286 }
2287
2288 if(o.snapMode != 'inner') {
2289 var ts = Math.abs(t - y2) <= d;
2290 var bs = Math.abs(b - y1) <= d;
2291 var ls = Math.abs(l - x2) <= d;
2292 var rs = Math.abs(r - x1) <= d;
2293 if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
2294 if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
2295 if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
2296 if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
2297 }
2298
2299 var first = (ts || bs || ls || rs);
2300
2301 if(o.snapMode != 'outer') {
2302 var ts = Math.abs(t - y1) <= d;
2303 var bs = Math.abs(b - y2) <= d;
2304 var ls = Math.abs(l - x1) <= d;
2305 var rs = Math.abs(r - x2) <= d;
2306 if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
2307 if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
2308 if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
2309 if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
2310 }
2311
2312 if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first))
2313 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
2314 inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
2315
2316 };
2317
2318 }
2319 });
2320
2321 $.ui.plugin.add("draggable", "stack", {
2322 start: function(event, ui) {
2323
2324 var o = $(this).data("draggable").options;
2325
2326 var group = $.makeArray($(o.stack)).sort(function(a,b) {
2327 return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0);
2328 });
2329 if (!group.length) { return; }
2330
2331 var min = parseInt(group[0].style.zIndex) || 0;
2332 $(group).each(function(i) {
2333 this.style.zIndex = min + i;
2334 });
2335
2336 this[0].style.zIndex = min + group.length;
2337
2338 }
2339 });
2340
2341 $.ui.plugin.add("draggable", "zIndex", {
2342 start: function(event, ui) {
2343 var t = $(ui.helper), o = $(this).data("draggable").options;
2344 if(t.css("zIndex")) o._zIndex = t.css("zIndex");
2345 t.css('zIndex', o.zIndex);
2346 },
2347 stop: function(event, ui) {
2348 var o = $(this).data("draggable").options;
2349 if(o._zIndex) $(ui.helper).css('zIndex', o._zIndex);
2350 }
2351 });
2352
2353 })(jQuery);
2354 (function( $, undefined ) {
2355
2356 $.widget("ui.droppable", {
2357 version: "1.9.2",
2358 widgetEventPrefix: "drop",
2359 options: {
2360 accept: '*',
2361 activeClass: false,
2362 addClasses: true,
2363 greedy: false,
2364 hoverClass: false,
2365 scope: 'default',
2366 tolerance: 'intersect'
2367 },
2368 _create: function() {
2369
2370 var o = this.options, accept = o.accept;
2371 this.isover = 0; this.isout = 1;
2372
2373 this.accept = $.isFunction(accept) ? accept : function(d) {
2374 return d.is(accept);
2375 };
2376
2377 //Store the droppable's proportions
2378 this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight };
2379
2380 // Add the reference and positions to the manager
2381 $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || [];
2382 $.ui.ddmanager.droppables[o.scope].push(this);
2383
2384 (o.addClasses && this.element.addClass("ui-droppable"));
2385
2386 },
2387
2388 _destroy: function() {
2389 var drop = $.ui.ddmanager.droppables[this.options.scope];
2390 for ( var i = 0; i < drop.length; i++ )
2391 if ( drop[i] == this )
2392 drop.splice(i, 1);
2393
2394 this.element.removeClass("ui-droppable ui-droppable-disabled");
2395 },
2396
2397 _setOption: function(key, value) {
2398
2399 if(key == 'accept') {
2400 this.accept = $.isFunction(value) ? value : function(d) {
2401 return d.is(value);
2402 };
2403 }
2404 $.Widget.prototype._setOption.apply(this, arguments);
2405 },
2406
2407 _activate: function(event) {
2408 var draggable = $.ui.ddmanager.current;
2409 if(this.options.activeClass) this.element.addClass(this.options.activeClass);
2410 (draggable && this._trigger('activate', event, this.ui(draggable)));
2411 },
2412
2413 _deactivate: function(event) {
2414 var draggable = $.ui.ddmanager.current;
2415 if(this.options.activeClass) this.element.removeClass(this.options.activeClass);
2416 (draggable && this._trigger('deactivate', event, this.ui(draggable)));
2417 },
2418
2419 _over: function(event) {
2420
2421 var draggable = $.ui.ddmanager.current;
2422 if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element
2423
2424 if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
2425 if(this.options.hoverClass) this.element.addClass(this.options.hoverClass);
2426 this._trigger('over', event, this.ui(draggable));
2427 }
2428
2429 },
2430
2431 _out: function(event) {
2432
2433 var draggable = $.ui.ddmanager.current;
2434 if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element
2435
2436 if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
2437 if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass);
2438 this._trigger('out', event, this.ui(draggable));
2439 }
2440
2441 },
2442
2443 _drop: function(event,custom) {
2444
2445 var draggable = custom || $.ui.ddmanager.current;
2446 if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element
2447
2448 var childrenIntersection = false;
2449 this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function() {
2450 var inst = $.data(this, 'droppable');
2451 if(
2452 inst.options.greedy
2453 && !inst.options.disabled
2454 && inst.options.scope == draggable.options.scope
2455 && inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element))
2456 && $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)
2457 ) { childrenIntersection = true; return false; }
2458 });
2459 if(childrenIntersection) return false;
2460
2461 if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
2462 if(this.options.activeClass) this.element.removeClass(this.options.activeClass);
2463 if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass);
2464 this._trigger('drop', event, this.ui(draggable));
2465 return this.element;
2466 }
2467
2468 return false;
2469
2470 },
2471
2472 ui: function(c) {
2473 return {
2474 draggable: (c.currentItem || c.element),
2475 helper: c.helper,
2476 position: c.position,
2477 offset: c.positionAbs
2478 };
2479 }
2480
2481 });
2482
2483 $.ui.intersect = function(draggable, droppable, toleranceMode) {
2484
2485 if (!droppable.offset) return false;
2486
2487 var x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width,
2488 y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height;
2489 var l = droppable.offset.left, r = l + droppable.proportions.width,
2490 t = droppable.offset.top, b = t + droppable.proportions.height;
2491
2492 switch (toleranceMode) {
2493 case 'fit':
2494 return (l <= x1 && x2 <= r
2495 && t <= y1 && y2 <= b);
2496 break;
2497 case 'intersect':
2498 return (l < x1 + (draggable.helperProportions.width / 2) // Right Half
2499 && x2 - (draggable.helperProportions.width / 2) < r // Left Half
2500 && t < y1 + (draggable.helperProportions.height / 2) // Bottom Half
2501 && y2 - (draggable.helperProportions.height / 2) < b ); // Top Half
2502 break;
2503 case 'pointer':
2504 var draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left),
2505 draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top),
2506 isOver = $.ui.isOver(draggableTop, draggableLeft, t, l, droppable.proportions.height, droppable.proportions.width);
2507 return isOver;
2508 break;
2509 case 'touch':
2510 return (
2511 (y1 >= t && y1 <= b) || // Top edge touching
2512 (y2 >= t && y2 <= b) || // Bottom edge touching
2513 (y1 < t && y2 > b) // Surrounded vertically
2514 ) && (
2515 (x1 >= l && x1 <= r) || // Left edge touching
2516 (x2 >= l && x2 <= r) || // Right edge touching
2517 (x1 < l && x2 > r) // Surrounded horizontally
2518 );
2519 break;
2520 default:
2521 return false;
2522 break;
2523 }
2524
2525 };
2526
2527 /*
2528 This manager tracks offsets of draggables and droppables
2529 */
2530 $.ui.ddmanager = {
2531 current: null,
2532 droppables: { 'default': [] },
2533 prepareOffsets: function(t, event) {
2534
2535 var m = $.ui.ddmanager.droppables[t.options.scope] || [];
2536 var type = event ? event.type : null; // workaround for #2317
2537 var list = (t.currentItem || t.element).find(":data(droppable)").andSelf();
2538
2539 droppablesLoop: for (var i = 0; i < m.length; i++) {
2540
2541 if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) continue; //No disabled and non-accepted
2542 for (var j=0; j < list.length; j++) { if(list[j] == m[i].element[0]) { m[i].proportions.height = 0; continue droppablesLoop; } }; //Filter out elements in the current dragged item
2543 m[i].visible = m[i].element.css("display") != "none"; if(!m[i].visible) continue; //If the element is not visible, continue
2544
2545 if(type == "mousedown") m[i]._activate.call(m[i], event); //Activate the droppable if used directly from draggables
2546
2547 m[i].offset = m[i].element.offset();
2548 m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight };
2549
2550 }
2551
2552 },
2553 drop: function(draggable, event) {
2554
2555 var dropped = false;
2556 $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
2557
2558 if(!this.options) return;
2559 if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance))
2560 dropped = this._drop.call(this, event) || dropped;
2561
2562 if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
2563 this.isout = 1; this.isover = 0;
2564 this._deactivate.call(this, event);
2565 }
2566
2567 });
2568 return dropped;
2569
2570 },
2571 dragStart: function( draggable, event ) {
2572 //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
2573 draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
2574 if( !draggable.options.refreshPositions ) $.ui.ddmanager.prepareOffsets( draggable, event );
2575 });
2576 },
2577 drag: function(draggable, event) {
2578
2579 //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
2580 if(draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event);
2581
2582 //Run through all droppables and check their positions based on specific tolerance options
2583 $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
2584
2585 if(this.options.disabled || this.greedyChild || !this.visible) return;
2586 var intersects = $.ui.intersect(draggable, this, this.options.tolerance);
2587
2588 var c = !intersects && this.isover == 1 ? 'isout' : (intersects && this.isover == 0 ? 'isover' : null);
2589 if(!c) return;
2590
2591 var parentInstance;
2592 if (this.options.greedy) {
2593 // find droppable parents with same scope
2594 var scope = this.options.scope;
2595 var parent = this.element.parents(':data(droppable)').filter(function () {
2596 return $.data(this, 'droppable').options.scope === scope;
2597 });
2598
2599 if (parent.length) {
2600 parentInstance = $.data(parent[0], 'droppable');
2601 parentInstance.greedyChild = (c == 'isover' ? 1 : 0);
2602 }
2603 }
2604
2605 // we just moved into a greedy child
2606 if (parentInstance && c == 'isover') {
2607 parentInstance['isover'] = 0;
2608 parentInstance['isout'] = 1;
2609 parentInstance._out.call(parentInstance, event);
2610 }
2611
2612 this[c] = 1; this[c == 'isout' ? 'isover' : 'isout'] = 0;
2613 this[c == "isover" ? "_over" : "_out"].call(this, event);
2614
2615 // we just moved out of a greedy child
2616 if (parentInstance && c == 'isout') {
2617 parentInstance['isout'] = 0;
2618 parentInstance['isover'] = 1;
2619 parentInstance._over.call(parentInstance, event);
2620 }
2621 });
2622
2623 },
2624 dragStop: function( draggable, event ) {
2625 draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
2626 //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
2627 if( !draggable.options.refreshPositions ) $.ui.ddmanager.prepareOffsets( draggable, event );
2628 }
2629 };
2630
2631 })(jQuery);
2632 (function( $, undefined ) {
2633
2634 $.widget("ui.resizable", $.ui.mouse, {
2635 version: "1.9.2",
2636 widgetEventPrefix: "resize",
2637 options: {
2638 alsoResize: false,
2639 animate: false,
2640 animateDuration: "slow",
2641 animateEasing: "swing",
2642 aspectRatio: false,
2643 autoHide: false,
2644 containment: false,
2645 ghost: false,
2646 grid: false,
2647 handles: "e,s,se",
2648 helper: false,
2649 maxHeight: null,
2650 maxWidth: null,
2651 minHeight: 10,
2652 minWidth: 10,
2653 zIndex: 1000
2654 },
2655 _create: function() {
2656
2657 var that = this, o = this.options;
2658 this.element.addClass("ui-resizable");
2659
2660 $.extend(this, {
2661 _aspectRatio: !!(o.aspectRatio),
2662 aspectRatio: o.aspectRatio,
2663 originalElement: this.element,
2664 _proportionallyResizeElements: [],
2665 _helper: o.helper || o.ghost || o.animate ? o.helper || 'ui-resizable-helper' : null
2666 });
2667
2668 //Wrap the element if it cannot hold child nodes
2669 if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {
2670
2671 //Create a wrapper element and set the wrapper to the new current internal element
2672 this.element.wrap(
2673 $('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({
2674 position: this.element.css('position'),
2675 width: this.element.outerWidth(),
2676 height: this.element.outerHeight(),
2677 top: this.element.css('top'),
2678 left: this.element.css('left')
2679 })
2680 );
2681
2682 //Overwrite the original this.element
2683 this.element = this.element.parent().data(
2684 "resizable", this.element.data('resizable')
2685 );
2686
2687 this.elementIsWrapper = true;
2688
2689 //Move margins to the wrapper
2690 this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") });
2691 this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});
2692
2693 //Prevent Safari textarea resize
2694 this.originalResizeStyle = this.originalElement.css('resize');
2695 this.originalElement.css('resize', 'none');
2696
2697 //Push the actual element to our proportionallyResize internal array
2698 this._proportionallyResizeElements.push(this.originalElement.css({ position: 'static', zoom: 1, display: 'block' }));
2699
2700 // avoid IE jump (hard set the margin)
2701 this.originalElement.css({ margin: this.originalElement.css('margin') });
2702
2703 // fix handlers offset
2704 this._proportionallyResize();
2705
2706 }
2707
2708 this.handles = o.handles || (!$('.ui-resizable-handle', this.element).length ? "e,s,se" : { n: '.ui-resizable-n', e: '.ui-resizable-e', s: '.ui-resizable-s', w: '.ui-resizable-w', se: '.ui-resizable-se', sw: '.ui-resizable-sw', ne: '.ui-resizable-ne', nw: '.ui-resizable-nw' });
2709 if(this.handles.constructor == String) {
2710
2711 if(this.handles == 'all') this.handles = 'n,e,s,w,se,sw,ne,nw';
2712 var n = this.handles.split(","); this.handles = {};
2713
2714 for(var i = 0; i < n.length; i++) {
2715
2716 var handle = $.trim(n[i]), hname = 'ui-resizable-'+handle;
2717 var axis = $('<div class="ui-resizable-handle ' + hname + '"></div>');
2718
2719 // Apply zIndex to all handles - see #7960
2720 axis.css({ zIndex: o.zIndex });
2721
2722 //TODO : What's going on here?
2723 if ('se' == handle) {
2724 axis.addClass('ui-icon ui-icon-gripsmall-diagonal-se');
2725 };
2726
2727 //Insert into internal handles object and append to element
2728 this.handles[handle] = '.ui-resizable-'+handle;
2729 this.element.append(axis);
2730 }
2731
2732 }
2733
2734 this._renderAxis = function(target) {
2735
2736 target = target || this.element;
2737
2738 for(var i in this.handles) {
2739
2740 if(this.handles[i].constructor == String)
2741 this.handles[i] = $(this.handles[i], this.element).show();
2742
2743 //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)
2744 if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {
2745
2746 var axis = $(this.handles[i], this.element), padWrapper = 0;
2747
2748 //Checking the correct pad and border
2749 padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
2750
2751 //The padding type i have to apply...
2752 var padPos = [ 'padding',
2753 /ne|nw|n/.test(i) ? 'Top' :
2754 /se|sw|s/.test(i) ? 'Bottom' :
2755 /^e$/.test(i) ? 'Right' : 'Left' ].join("");
2756
2757 target.css(padPos, padWrapper);
2758
2759 this._proportionallyResize();
2760
2761 }
2762
2763 //TODO: What's that good for? There's not anything to be executed left
2764 if(!$(this.handles[i]).length)
2765 continue;
2766
2767 }
2768 };
2769
2770 //TODO: make renderAxis a prototype function
2771 this._renderAxis(this.element);
2772
2773 this._handles = $('.ui-resizable-handle', this.element)
2774 .disableSelection();
2775
2776 //Matching axis name
2777 this._handles.mouseover(function() {
2778 if (!that.resizing) {
2779 if (this.className)
2780 var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
2781 //Axis, default = se
2782 that.axis = axis && axis[1] ? axis[1] : 'se';
2783 }
2784 });
2785
2786 //If we want to auto hide the elements
2787 if (o.autoHide) {
2788 this._handles.hide();
2789 $(this.element)
2790 .addClass("ui-resizable-autohide")
2791 .mouseenter(function() {
2792 if (o.disabled) return;
2793 $(this).removeClass("ui-resizable-autohide");
2794 that._handles.show();
2795 })
2796 .mouseleave(function(){
2797 if (o.disabled) return;
2798 if (!that.resizing) {
2799 $(this).addClass("ui-resizable-autohide");
2800 that._handles.hide();
2801 }
2802 });
2803 }
2804
2805 //Initialize the mouse interaction
2806 this._mouseInit();
2807
2808 },
2809
2810 _destroy: function() {
2811
2812 this._mouseDestroy();
2813
2814 var _destroy = function(exp) {
2815 $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
2816 .removeData("resizable").removeData("ui-resizable").unbind(".resizable").find('.ui-resizable-handle').remove();
2817 };
2818
2819 //TODO: Unwrap at same DOM position
2820 if (this.elementIsWrapper) {
2821 _destroy(this.element);
2822 var wrapper = this.element;
2823 this.originalElement.css({
2824 position: wrapper.css('position'),
2825 width: wrapper.outerWidth(),
2826 height: wrapper.outerHeight(),
2827 top: wrapper.css('top'),
2828 left: wrapper.css('left')
2829 }).insertAfter( wrapper );
2830 wrapper.remove();
2831 }
2832
2833 this.originalElement.css('resize', this.originalResizeStyle);
2834 _destroy(this.originalElement);
2835
2836 return this;
2837 },
2838
2839 _mouseCapture: function(event) {
2840 var handle = false;
2841 for (var i in this.handles) {
2842 if ($(this.handles[i])[0] == event.target) {
2843 handle = true;
2844 }
2845 }
2846
2847 return !this.options.disabled && handle;
2848 },
2849
2850 _mouseStart: function(event) {
2851
2852 var o = this.options, iniPos = this.element.position(), el = this.element;
2853
2854 this.resizing = true;
2855 this.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() };
2856
2857 // bugfix for http://dev.jquery.com/ticket/1749
2858 if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) {
2859 el.css({ position: 'absolute', top: iniPos.top, left: iniPos.left });
2860 }
2861
2862 this._renderProxy();
2863
2864 var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top'));
2865
2866 if (o.containment) {
2867 curleft += $(o.containment).scrollLeft() || 0;
2868 curtop += $(o.containment).scrollTop() || 0;
2869 }
2870
2871 //Store needed variables
2872 this.offset = this.helper.offset();
2873 this.position = { left: curleft, top: curtop };
2874 this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
2875 this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
2876 this.originalPosition = { left: curleft, top: curtop };
2877 this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };
2878 this.originalMousePosition = { left: event.pageX, top: event.pageY };
2879
2880 //Aspect Ratio
2881 this.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1);
2882
2883 var cursor = $('.ui-resizable-' + this.axis).css('cursor');
2884 $('body').css('cursor', cursor == 'auto' ? this.axis + '-resize' : cursor);
2885
2886 el.addClass("ui-resizable-resizing");
2887 this._propagate("start", event);
2888 return true;
2889 },
2890
2891 _mouseDrag: function(event) {
2892
2893 //Increase performance, avoid regex
2894 var el = this.helper, o = this.options, props = {},
2895 that = this, smp = this.originalMousePosition, a = this.axis;
2896
2897 var dx = (event.pageX-smp.left)||0, dy = (event.pageY-smp.top)||0;
2898 var trigger = this._change[a];
2899 if (!trigger) return false;
2900
2901 // Calculate the attrs that will be change
2902 var data = trigger.apply(this, [event, dx, dy]);
2903
2904 // Put this in the mouseDrag handler since the user can start pressing shift while resizing
2905 this._updateVirtualBoundaries(event.shiftKey);
2906 if (this._aspectRatio || event.shiftKey)
2907 data = this._updateRatio(data, event);
2908
2909 data = this._respectSize(data, event);
2910
2911 // plugins callbacks need to be called first
2912 this._propagate("resize", event);
2913
2914 el.css({
2915 top: this.position.top + "px", left: this.position.left + "px",
2916 width: this.size.width + "px", height: this.size.height + "px"
2917 });
2918
2919 if (!this._helper && this._proportionallyResizeElements.length)
2920 this._proportionallyResize();
2921
2922 this._updateCache(data);
2923
2924 // calling the user callback at the end
2925 this._trigger('resize', event, this.ui());
2926
2927 return false;
2928 },
2929
2930 _mouseStop: function(event) {
2931
2932 this.resizing = false;
2933 var o = this.options, that = this;
2934
2935 if(this._helper) {
2936 var pr = this._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName),
2937 soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : that.sizeDiff.height,
2938 soffsetw = ista ? 0 : that.sizeDiff.width;
2939
2940 var s = { width: (that.helper.width() - soffsetw), height: (that.helper.height() - soffseth) },
2941 left = (parseInt(that.element.css('left'), 10) + (that.position.left - that.originalPosition.left)) || null,
2942 top = (parseInt(that.element.css('top'), 10) + (that.position.top - that.originalPosition.top)) || null;
2943
2944 if (!o.animate)
2945 this.element.css($.extend(s, { top: top, left: left }));
2946
2947 that.helper.height(that.size.height);
2948 that.helper.width(that.size.width);
2949
2950 if (this._helper && !o.animate) this._proportionallyResize();
2951 }
2952
2953 $('body').css('cursor', 'auto');
2954
2955 this.element.removeClass("ui-resizable-resizing");
2956
2957 this._propagate("stop", event);
2958
2959 if (this._helper) this.helper.remove();
2960 return false;
2961
2962 },
2963
2964 _updateVirtualBoundaries: function(forceAspectRatio) {
2965 var o = this.options, pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b;
2966
2967 b = {
2968 minWidth: isNumber(o.minWidth) ? o.minWidth : 0,
2969 maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity,
2970 minHeight: isNumber(o.minHeight) ? o.minHeight : 0,
2971 maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity
2972 };
2973
2974 if(this._aspectRatio || forceAspectRatio) {
2975 // We want to create an enclosing box whose aspect ration is the requested one
2976 // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension
2977 pMinWidth = b.minHeight * this.aspectRatio;
2978 pMinHeight = b.minWidth / this.aspectRatio;
2979 pMaxWidth = b.maxHeight * this.aspectRatio;
2980 pMaxHeight = b.maxWidth / this.aspectRatio;
2981
2982 if(pMinWidth > b.minWidth) b.minWidth = pMinWidth;
2983 if(pMinHeight > b.minHeight) b.minHeight = pMinHeight;
2984 if(pMaxWidth < b.maxWidth) b.maxWidth = pMaxWidth;
2985 if(pMaxHeight < b.maxHeight) b.maxHeight = pMaxHeight;
2986 }
2987 this._vBoundaries = b;
2988 },
2989
2990 _updateCache: function(data) {
2991 var o = this.options;
2992 this.offset = this.helper.offset();
2993 if (isNumber(data.left)) this.position.left = data.left;
2994 if (isNumber(data.top)) this.position.top = data.top;
2995 if (isNumber(data.height)) this.size.height = data.height;
2996 if (isNumber(data.width)) this.size.width = data.width;
2997 },
2998
2999 _updateRatio: function(data, event) {
3000
3001 var o = this.options, cpos = this.position, csize = this.size, a = this.axis;
3002
3003 if (isNumber(data.height)) data.width = (data.height * this.aspectRatio);
3004 else if (isNumber(data.width)) data.height = (data.width / this.aspectRatio);
3005
3006 if (a == 'sw') {
3007 data.left = cpos.left + (csize.width - data.width);
3008 data.top = null;
3009 }
3010 if (a == 'nw') {
3011 data.top = cpos.top + (csize.height - data.height);
3012 data.left = cpos.left + (csize.width - data.width);
3013 }
3014
3015 return data;
3016 },
3017
3018 _respectSize: function(data, event) {
3019
3020 var el = this.helper, o = this._vBoundaries, pRatio = this._aspectRatio || event.shiftKey, a = this.axis,
3021 ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
3022 isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height);
3023
3024 if (isminw) data.width = o.minWidth;
3025 if (isminh) data.height = o.minHeight;
3026 if (ismaxw) data.width = o.maxWidth;
3027 if (ismaxh) data.height = o.maxHeight;
3028
3029 var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height;
3030 var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
3031
3032 if (isminw && cw) data.left = dw - o.minWidth;
3033 if (ismaxw && cw) data.left = dw - o.maxWidth;
3034 if (isminh && ch) data.top = dh - o.minHeight;
3035 if (ismaxh && ch) data.top = dh - o.maxHeight;
3036
3037 // fixing jump error on top/left - bug #2330
3038 var isNotwh = !data.width && !data.height;
3039 if (isNotwh && !data.left && data.top) data.top = null;
3040 else if (isNotwh && !data.top && data.left) data.left = null;
3041
3042 return data;
3043 },
3044
3045 _proportionallyResize: function() {
3046
3047 var o = this.options;
3048 if (!this._proportionallyResizeElements.length) return;
3049 var element = this.helper || this.element;
3050
3051 for (var i=0; i < this._proportionallyResizeElements.length; i++) {
3052
3053 var prel = this._proportionallyResizeElements[i];
3054
3055 if (!this.borderDif) {
3056 var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')],
3057 p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')];
3058
3059 this.borderDif = $.map(b, function(v, i) {
3060 var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0;
3061 return border + padding;
3062 });
3063 }
3064
3065 prel.css({
3066 height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0,
3067 width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0
3068 });
3069
3070 };
3071
3072 },
3073
3074 _renderProxy: function() {
3075
3076 var el = this.element, o = this.options;
3077 this.elementOffset = el.offset();
3078
3079 if(this._helper) {
3080
3081 this.helper = this.helper || $('<div style="overflow:hidden;"></div>');
3082
3083 // fix ie6 offset TODO: This seems broken
3084 var ie6offset = ($.ui.ie6 ? 1 : 0),
3085 pxyoffset = ( $.ui.ie6 ? 2 : -1 );
3086
3087 this.helper.addClass(this._helper).css({
3088 width: this.element.outerWidth() + pxyoffset,
3089 height: this.element.outerHeight() + pxyoffset,
3090 position: 'absolute',
3091 left: this.elementOffset.left - ie6offset +'px',
3092 top: this.elementOffset.top - ie6offset +'px',
3093 zIndex: ++o.zIndex //TODO: Don't modify option
3094 });
3095
3096 this.helper
3097 .appendTo("body")
3098 .disableSelection();
3099
3100 } else {
3101 this.helper = this.element;
3102 }
3103
3104 },
3105
3106 _change: {
3107 e: function(event, dx, dy) {
3108 return { width: this.originalSize.width + dx };
3109 },
3110 w: function(event, dx, dy) {
3111 var o = this.options, cs = this.originalSize, sp = this.originalPosition;
3112 return { left: sp.left + dx, width: cs.width - dx };
3113 },
3114 n: function(event, dx, dy) {
3115 var o = this.options, cs = this.originalSize, sp = this.originalPosition;
3116 return { top: sp.top + dy, height: cs.height - dy };
3117 },
3118 s: function(event, dx, dy) {
3119 return { height: this.originalSize.height + dy };
3120 },
3121 se: function(event, dx, dy) {
3122 return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
3123 },
3124 sw: function(event, dx, dy) {
3125 return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
3126 },
3127 ne: function(event, dx, dy) {
3128 return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
3129 },
3130 nw: function(event, dx, dy) {
3131 return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
3132 }
3133 },
3134
3135 _propagate: function(n, event) {
3136 $.ui.plugin.call(this, n, [event, this.ui()]);
3137 (n != "resize" && this._trigger(n, event, this.ui()));
3138 },
3139
3140 plugins: {},
3141
3142 ui: function() {
3143 return {
3144 originalElement: this.originalElement,
3145 element: this.element,
3146 helper: this.helper,
3147 position: this.position,
3148 size: this.size,
3149 originalSize: this.originalSize,
3150 originalPosition: this.originalPosition
3151 };
3152 }
3153
3154 });
3155
3156 /*
3157 * Resizable Extensions
3158 */
3159
3160 $.ui.plugin.add("resizable", "alsoResize", {
3161
3162 start: function (event, ui) {
3163 var that = $(this).data("resizable"), o = that.options;
3164
3165 var _store = function (exp) {
3166 $(exp).each(function() {
3167 var el = $(this);
3168 el.data("resizable-alsoresize", {
3169 width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
3170 left: parseInt(el.css('left'), 10), top: parseInt(el.css('top'), 10)
3171 });
3172 });
3173 };
3174
3175 if (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) {
3176 if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); }
3177 else { $.each(o.alsoResize, function (exp) { _store(exp); }); }
3178 }else{
3179 _store(o.alsoResize);
3180 }
3181 },
3182
3183 resize: function (event, ui) {
3184 var that = $(this).data("resizable"), o = that.options, os = that.originalSize, op = that.originalPosition;
3185
3186 var delta = {
3187 height: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0,
3188 top: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0
3189 },
3190
3191 _alsoResize = function (exp, c) {
3192 $(exp).each(function() {
3193 var el = $(this), start = $(this).data("resizable-alsoresize"), style = {},
3194 css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ['width', 'height'] : ['width', 'height', 'top', 'left'];
3195
3196 $.each(css, function (i, prop) {
3197 var sum = (start[prop]||0) + (delta[prop]||0);
3198 if (sum && sum >= 0)
3199 style[prop] = sum || null;
3200 });
3201
3202 el.css(style);
3203 });
3204 };
3205
3206 if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) {
3207 $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); });
3208 }else{
3209 _alsoResize(o.alsoResize);
3210 }
3211 },
3212
3213 stop: function (event, ui) {
3214 $(this).removeData("resizable-alsoresize");
3215 }
3216 });
3217
3218 $.ui.plugin.add("resizable", "animate", {
3219
3220 stop: function(event, ui) {
3221 var that = $(this).data("resizable"), o = that.options;
3222
3223 var pr = that._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName),
3224 soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : that.sizeDiff.height,
3225 soffsetw = ista ? 0 : that.sizeDiff.width;
3226
3227 var style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) },
3228 left = (parseInt(that.element.css('left'), 10) + (that.position.left - that.originalPosition.left)) || null,
3229 top = (parseInt(that.element.css('top'), 10) + (that.position.top - that.originalPosition.top)) || null;
3230
3231 that.element.animate(
3232 $.extend(style, top && left ? { top: top, left: left } : {}), {
3233 duration: o.animateDuration,
3234 easing: o.animateEasing,
3235 step: function() {
3236
3237 var data = {
3238 width: parseInt(that.element.css('width'), 10),
3239 height: parseInt(that.element.css('height'), 10),
3240 top: parseInt(that.element.css('top'), 10),
3241 left: parseInt(that.element.css('left'), 10)
3242 };
3243
3244 if (pr && pr.length) $(pr[0]).css({ width: data.width, height: data.height });
3245
3246 // propagating resize, and updating values for each animation step
3247 that._updateCache(data);
3248 that._propagate("resize", event);
3249
3250 }
3251 }
3252 );
3253 }
3254
3255 });
3256
3257 $.ui.plugin.add("resizable", "containment", {
3258
3259 start: function(event, ui) {
3260 var that = $(this).data("resizable"), o = that.options, el = that.element;
3261 var oc = o.containment, ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc;
3262 if (!ce) return;
3263
3264 that.containerElement = $(ce);
3265
3266 if (/document/.test(oc) || oc == document) {
3267 that.containerOffset = { left: 0, top: 0 };
3268 that.containerPosition = { left: 0, top: 0 };
3269
3270 that.parentData = {
3271 element: $(document), left: 0, top: 0,
3272 width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight
3273 };
3274 }
3275
3276 // i'm a node, so compute top, left, right, bottom
3277 else {
3278 var element = $(ce), p = [];
3279 $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); });
3280
3281 that.containerOffset = element.offset();
3282 that.containerPosition = element.position();
3283 that.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) };
3284
3285 var co = that.containerOffset, ch = that.containerSize.height, cw = that.containerSize.width,
3286 width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch);
3287
3288 that.parentData = {
3289 element: ce, left: co.left, top: co.top, width: width, height: height
3290 };
3291 }
3292 },
3293
3294 resize: function(event, ui) {
3295 var that = $(this).data("resizable"), o = that.options,
3296 ps = that.containerSize, co = that.containerOffset, cs = that.size, cp = that.position,
3297 pRatio = that._aspectRatio || event.shiftKey, cop = { top:0, left:0 }, ce = that.containerElement;
3298
3299 if (ce[0] != document && (/static/).test(ce.css('position'))) cop = co;
3300
3301 if (cp.left < (that._helper ? co.left : 0)) {
3302 that.size.width = that.size.width + (that._helper ? (that.position.left - co.left) : (that.position.left - cop.left));
3303 if (pRatio) that.size.height = that.size.width / that.aspectRatio;
3304 that.position.left = o.helper ? co.left : 0;
3305 }
3306
3307 if (cp.top < (that._helper ? co.top : 0)) {
3308 that.size.height = that.size.height + (that._helper ? (that.position.top - co.top) : that.position.top);
3309 if (pRatio) that.size.width = that.size.height * that.aspectRatio;
3310 that.position.top = that._helper ? co.top : 0;
3311 }
3312
3313 that.offset.left = that.parentData.left+that.position.left;
3314 that.offset.top = that.parentData.top+that.position.top;
3315
3316 var woset = Math.abs( (that._helper ? that.offset.left - cop.left : (that.offset.left - cop.left)) + that.sizeDiff.width ),
3317 hoset = Math.abs( (that._helper ? that.offset.top - cop.top : (that.offset.top - co.top)) + that.sizeDiff.height );
3318
3319 var isParent = that.containerElement.get(0) == that.element.parent().get(0),
3320 isOffsetRelative = /relative|absolute/.test(that.containerElement.css('position'));
3321
3322 if(isParent && isOffsetRelative) woset -= that.parentData.left;
3323
3324 if (woset + that.size.width >= that.parentData.width) {
3325 that.size.width = that.parentData.width - woset;
3326 if (pRatio) that.size.height = that.size.width / that.aspectRatio;
3327 }
3328
3329 if (hoset + that.size.height >= that.parentData.height) {
3330 that.size.height = that.parentData.height - hoset;
3331 if (pRatio) that.size.width = that.size.height * that.aspectRatio;
3332 }
3333 },
3334
3335 stop: function(event, ui){
3336 var that = $(this).data("resizable"), o = that.options, cp = that.position,
3337 co = that.containerOffset, cop = that.containerPosition, ce = that.containerElement;
3338
3339 var helper = $(that.helper), ho = helper.offset(), w = helper.outerWidth() - that.sizeDiff.width, h = helper.outerHeight() - that.sizeDiff.height;
3340
3341 if (that._helper && !o.animate && (/relative/).test(ce.css('position')))
3342 $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
3343
3344 if (that._helper && !o.animate && (/static/).test(ce.css('position')))
3345 $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
3346
3347 }
3348 });
3349
3350 $.ui.plugin.add("resizable", "ghost", {
3351
3352 start: function(event, ui) {
3353
3354 var that = $(this).data("resizable"), o = that.options, cs = that.size;
3355
3356 that.ghost = that.originalElement.clone();
3357 that.ghost
3358 .css({ opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 })
3359 .addClass('ui-resizable-ghost')
3360 .addClass(typeof o.ghost == 'string' ? o.ghost : '');
3361
3362 that.ghost.appendTo(that.helper);
3363
3364 },
3365
3366 resize: function(event, ui){
3367 var that = $(this).data("resizable"), o = that.options;
3368 if (that.ghost) that.ghost.css({ position: 'relative', height: that.size.height, width: that.size.width });
3369 },
3370
3371 stop: function(event, ui){
3372 var that = $(this).data("resizable"), o = that.options;
3373 if (that.ghost && that.helper) that.helper.get(0).removeChild(that.ghost.get(0));
3374 }
3375
3376 });
3377
3378 $.ui.plugin.add("resizable", "grid", {
3379
3380 resize: function(event, ui) {
3381 var that = $(this).data("resizable"), o = that.options, cs = that.size, os = that.originalSize, op = that.originalPosition, a = that.axis, ratio = o._aspectRatio || event.shiftKey;
3382 o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid;
3383 var ox = Math.round((cs.width - os.width) / (o.grid[0]||1)) * (o.grid[0]||1), oy = Math.round((cs.height - os.height) / (o.grid[1]||1)) * (o.grid[1]||1);
3384
3385 if (/^(se|s|e)$/.test(a)) {
3386 that.size.width = os.width + ox;
3387 that.size.height = os.height + oy;
3388 }
3389 else if (/^(ne)$/.test(a)) {
3390 that.size.width = os.width + ox;
3391 that.size.height = os.height + oy;
3392 that.position.top = op.top - oy;
3393 }
3394 else if (/^(sw)$/.test(a)) {
3395 that.size.width = os.width + ox;
3396 that.size.height = os.height + oy;
3397 that.position.left = op.left - ox;
3398 }
3399 else {
3400 that.size.width = os.width + ox;
3401 that.size.height = os.height + oy;
3402 that.position.top = op.top - oy;
3403 that.position.left = op.left - ox;
3404 }
3405 }
3406
3407 });
3408
3409 var num = function(v) {
3410 return parseInt(v, 10) || 0;
3411 };
3412
3413 var isNumber = function(value) {
3414 return !isNaN(parseInt(value, 10));
3415 };
3416
3417 })(jQuery);
3418 (function( $, undefined ) {
3419
3420 $.widget("ui.selectable", $.ui.mouse, {
3421 version: "1.9.2",
3422 options: {
3423 appendTo: 'body',
3424 autoRefresh: true,
3425 distance: 0,
3426 filter: '*',
3427 tolerance: 'touch'
3428 },
3429 _create: function() {
3430 var that = this;
3431
3432 this.element.addClass("ui-selectable");
3433
3434 this.dragged = false;
3435
3436 // cache selectee children based on filter
3437 var selectees;
3438 this.refresh = function() {
3439 selectees = $(that.options.filter, that.element[0]);
3440 selectees.addClass("ui-selectee");
3441 selectees.each(function() {
3442 var $this = $(this);
3443 var pos = $this.offset();
3444 $.data(this, "selectable-item", {
3445 element: this,
3446 $element: $this,
3447 left: pos.left,
3448 top: pos.top,
3449 right: pos.left + $this.outerWidth(),
3450 bottom: pos.top + $this.outerHeight(),
3451 startselected: false,
3452 selected: $this.hasClass('ui-selected'),
3453 selecting: $this.hasClass('ui-selecting'),
3454 unselecting: $this.hasClass('ui-unselecting')
3455 });
3456 });
3457 };
3458 this.refresh();
3459
3460 this.selectees = selectees.addClass("ui-selectee");
3461
3462 this._mouseInit();
3463
3464 this.helper = $("<div class='ui-selectable-helper'></div>");
3465 },
3466
3467 _destroy: function() {
3468 this.selectees
3469 .removeClass("ui-selectee")
3470 .removeData("selectable-item");
3471 this.element
3472 .removeClass("ui-selectable ui-selectable-disabled");
3473 this._mouseDestroy();
3474 },
3475
3476 _mouseStart: function(event) {
3477 var that = this;
3478
3479 this.opos = [event.pageX, event.pageY];
3480
3481 if (this.options.disabled)
3482 return;
3483
3484 var options = this.options;
3485
3486 this.selectees = $(options.filter, this.element[0]);
3487
3488 this._trigger("start", event);
3489
3490 $(options.appendTo).append(this.helper);
3491 // position helper (lasso)
3492 this.helper.css({
3493 "left": event.clientX,
3494 "top": event.clientY,
3495 "width": 0,
3496 "height": 0
3497 });
3498
3499 if (options.autoRefresh) {
3500 this.refresh();
3501 }
3502
3503 this.selectees.filter('.ui-selected').each(function() {
3504 var selectee = $.data(this, "selectable-item");
3505 selectee.startselected = true;
3506 if (!event.metaKey && !event.ctrlKey) {
3507 selectee.$element.removeClass('ui-selected');
3508 selectee.selected = false;
3509 selectee.$element.addClass('ui-unselecting');
3510 selectee.unselecting = true;
3511 // selectable UNSELECTING callback
3512 that._trigger("unselecting", event, {
3513 unselecting: selectee.element
3514 });
3515 }
3516 });
3517
3518 $(event.target).parents().andSelf().each(function() {
3519 var selectee = $.data(this, "selectable-item");
3520 if (selectee) {
3521 var doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass('ui-selected');
3522 selectee.$element
3523 .removeClass(doSelect ? "ui-unselecting" : "ui-selected")
3524 .addClass(doSelect ? "ui-selecting" : "ui-unselecting");
3525 selectee.unselecting = !doSelect;
3526 selectee.selecting = doSelect;
3527 selectee.selected = doSelect;
3528 // selectable (UN)SELECTING callback
3529 if (doSelect) {
3530 that._trigger("selecting", event, {
3531 selecting: selectee.element
3532 });
3533 } else {
3534 that._trigger("unselecting", event, {
3535 unselecting: selectee.element
3536 });
3537 }
3538 return false;
3539 }
3540 });
3541
3542 },
3543
3544 _mouseDrag: function(event) {
3545 var that = this;
3546 this.dragged = true;
3547
3548 if (this.options.disabled)
3549 return;
3550
3551 var options = this.options;
3552
3553 var x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY;
3554 if (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; }
3555 if (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; }
3556 this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1});
3557
3558 this.selectees.each(function() {
3559 var selectee = $.data(this, "selectable-item");
3560 //prevent helper from being selected if appendTo: selectable
3561 if (!selectee || selectee.element == that.element[0])
3562 return;
3563 var hit = false;
3564 if (options.tolerance == 'touch') {
3565 hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
3566 } else if (options.tolerance == 'fit') {
3567 hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
3568 }
3569
3570 if (hit) {
3571 // SELECT
3572 if (selectee.selected) {
3573 selectee.$element.removeClass('ui-selected');
3574 selectee.selected = false;
3575 }
3576 if (selectee.unselecting) {
3577 selectee.$element.removeClass('ui-unselecting');
3578 selectee.unselecting = false;
3579 }
3580 if (!selectee.selecting) {
3581 selectee.$element.addClass('ui-selecting');
3582 selectee.selecting = true;
3583 // selectable SELECTING callback
3584 that._trigger("selecting", event, {
3585 selecting: selectee.element
3586 });
3587 }
3588 } else {
3589 // UNSELECT
3590 if (selectee.selecting) {
3591 if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
3592 selectee.$element.removeClass('ui-selecting');
3593 selectee.selecting = false;
3594 selectee.$element.addClass('ui-selected');
3595 selectee.selected = true;
3596 } else {
3597 selectee.$element.removeClass('ui-selecting');
3598 selectee.selecting = false;
3599 if (selectee.startselected) {
3600 selectee.$element.addClass('ui-unselecting');
3601 selectee.unselecting = true;
3602 }
3603 // selectable UNSELECTING callback
3604 that._trigger("unselecting", event, {
3605 unselecting: selectee.element
3606 });
3607 }
3608 }
3609 if (selectee.selected) {
3610 if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
3611 selectee.$element.removeClass('ui-selected');
3612 selectee.selected = false;
3613
3614 selectee.$element.addClass('ui-unselecting');
3615 selectee.unselecting = true;
3616 // selectable UNSELECTING callback
3617 that._trigger("unselecting", event, {
3618 unselecting: selectee.element
3619 });
3620 }
3621 }
3622 }
3623 });
3624
3625 return false;
3626 },
3627
3628 _mouseStop: function(event) {
3629 var that = this;
3630
3631 this.dragged = false;
3632
3633 var options = this.options;
3634
3635 $('.ui-unselecting', this.element[0]).each(function() {
3636 var selectee = $.data(this, "selectable-item");
3637 selectee.$element.removeClass('ui-unselecting');
3638 selectee.unselecting = false;
3639 selectee.startselected = false;
3640 that._trigger("unselected", event, {
3641 unselected: selectee.element
3642 });
3643 });
3644 $('.ui-selecting', this.element[0]).each(function() {
3645 var selectee = $.data(this, "selectable-item");
3646 selectee.$element.removeClass('ui-selecting').addClass('ui-selected');
3647 selectee.selecting = false;
3648 selectee.selected = true;
3649 selectee.startselected = true;
3650 that._trigger("selected", event, {
3651 selected: selectee.element
3652 });
3653 });
3654 this._trigger("stop", event);
3655
3656 this.helper.remove();
3657
3658 return false;
3659 }
3660
3661 });
3662
3663 })(jQuery);
3664 (function( $, undefined ) {
3665
3666 $.widget("ui.sortable", $.ui.mouse, {
3667 version: "1.9.2",
3668 widgetEventPrefix: "sort",
3669 ready: false,
3670 options: {
3671 appendTo: "parent",
3672 axis: false,
3673 connectWith: false,
3674 containment: false,
3675 cursor: 'auto',
3676 cursorAt: false,
3677 dropOnEmpty: true,
3678 forcePlaceholderSize: false,
3679 forceHelperSize: false,
3680 grid: false,
3681 handle: false,
3682 helper: "original",
3683 items: '> *',
3684 opacity: false,
3685 placeholder: false,
3686 revert: false,
3687 scroll: true,
3688 scrollSensitivity: 20,
3689 scrollSpeed: 20,
3690 scope: "default",
3691 tolerance: "intersect",
3692 zIndex: 1000
3693 },
3694 _create: function() {
3695
3696 var o = this.options;
3697 this.containerCache = {};
3698 this.element.addClass("ui-sortable");
3699
3700 //Get the items
3701 this.refresh();
3702
3703 //Let's determine if the items are being displayed horizontally
3704 this.floating = this.items.length ? o.axis === 'x' || (/left|right/).test(this.items[0].item.css('float')) || (/inline|table-cell/).test(this.items[0].item.css('display')) : false;
3705
3706 //Let's determine the parent's offset
3707 this.offset = this.element.offset();
3708
3709 //Initialize mouse events for interaction
3710 this._mouseInit();
3711
3712 //We're ready to go
3713 this.ready = true
3714
3715 },
3716
3717 _destroy: function() {
3718 this.element
3719 .removeClass("ui-sortable ui-sortable-disabled");
3720 this._mouseDestroy();
3721
3722 for ( var i = this.items.length - 1; i >= 0; i-- )
3723 this.items[i].item.removeData(this.widgetName + "-item");
3724
3725 return this;
3726 },
3727
3728 _setOption: function(key, value){
3729 if ( key === "disabled" ) {
3730 this.options[ key ] = value;
3731
3732 this.widget().toggleClass( "ui-sortable-disabled", !!value );
3733 } else {
3734 // Don't call widget base _setOption for disable as it adds ui-state-disabled class
3735 $.Widget.prototype._setOption.apply(this, arguments);
3736 }
3737 },
3738
3739 _mouseCapture: function(event, overrideHandle) {
3740 var that = this;
3741
3742 if (this.reverting) {
3743 return false;
3744 }
3745
3746 if(this.options.disabled || this.options.type == 'static') return false;
3747
3748 //We have to refresh the items data once first
3749 this._refreshItems(event);
3750
3751 //Find out if the clicked node (or one of its parents) is a actual item in this.items
3752 var currentItem = null, nodes = $(event.target).parents().each(function() {
3753 if($.data(this, that.widgetName + '-item') == that) {
3754 currentItem = $(this);
3755 return false;
3756 }
3757 });
3758 if($.data(event.target, that.widgetName + '-item') == that) currentItem = $(event.target);
3759
3760 if(!currentItem) return false;
3761 if(this.options.handle && !overrideHandle) {
3762 var validHandle = false;
3763
3764 $(this.options.handle, currentItem).find("*").andSelf().each(function() { if(this == event.target) validHandle = true; });
3765 if(!validHandle) return false;
3766 }
3767
3768 this.currentItem = currentItem;
3769 this._removeCurrentsFromItems();
3770 return true;
3771
3772 },
3773
3774 _mouseStart: function(event, overrideHandle, noActivation) {
3775
3776 var o = this.options;
3777 this.currentContainer = this;
3778
3779 //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
3780 this.refreshPositions();
3781
3782 //Create and append the visible helper
3783 this.helper = this._createHelper(event);
3784
3785 //Cache the helper size
3786 this._cacheHelperProportions();
3787
3788 /*
3789 * - Position generation -
3790 * This block generates everything position related - it's the core of draggables.
3791 */
3792
3793 //Cache the margins of the original element
3794 this._cacheMargins();
3795
3796 //Get the next scrolling parent
3797 this.scrollParent = this.helper.scrollParent();
3798
3799 //The element's absolute position on the page minus margins
3800 this.offset = this.currentItem.offset();
3801 this.offset = {
3802 top: this.offset.top - this.margins.top,
3803 left: this.offset.left - this.margins.left
3804 };
3805
3806 $.extend(this.offset, {
3807 click: { //Where the click happened, relative to the element
3808 left: event.pageX - this.offset.left,
3809 top: event.pageY - this.offset.top
3810 },
3811 parent: this._getParentOffset(),
3812 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
3813 });
3814
3815 // Only after we got the offset, we can change the helper's position to absolute
3816 // TODO: Still need to figure out a way to make relative sorting possible
3817 this.helper.css("position", "absolute");
3818 this.cssPosition = this.helper.css("position");
3819
3820 //Generate the original position
3821 this.originalPosition = this._generatePosition(event);
3822 this.originalPageX = event.pageX;
3823 this.originalPageY = event.pageY;
3824
3825 //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
3826 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
3827
3828 //Cache the former DOM position
3829 this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
3830
3831 //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
3832 if(this.helper[0] != this.currentItem[0]) {
3833 this.currentItem.hide();
3834 }
3835
3836 //Create the placeholder
3837 this._createPlaceholder();
3838
3839 //Set a containment if given in the options
3840 if(o.containment)
3841 this._setContainment();
3842
3843 if(o.cursor) { // cursor option
3844 if ($('body').css("cursor")) this._storedCursor = $('body').css("cursor");
3845 $('body').css("cursor", o.cursor);
3846 }
3847
3848 if(o.opacity) { // opacity option
3849 if (this.helper.css("opacity")) this._storedOpacity = this.helper.css("opacity");
3850 this.helper.css("opacity", o.opacity);
3851 }
3852
3853 if(o.zIndex) { // zIndex option
3854 if (this.helper.css("zIndex")) this._storedZIndex = this.helper.css("zIndex");
3855 this.helper.css("zIndex", o.zIndex);
3856 }
3857
3858 //Prepare scrolling
3859 if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML')
3860 this.overflowOffset = this.scrollParent.offset();
3861
3862 //Call callbacks
3863 this._trigger("start", event, this._uiHash());
3864
3865 //Recache the helper size
3866 if(!this._preserveHelperProportions)
3867 this._cacheHelperProportions();
3868
3869
3870 //Post 'activate' events to possible containers
3871 if(!noActivation) {
3872 for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i]._trigger("activate", event, this._uiHash(this)); }
3873 }
3874
3875 //Prepare possible droppables
3876 if($.ui.ddmanager)
3877 $.ui.ddmanager.current = this;
3878
3879 if ($.ui.ddmanager && !o.dropBehaviour)
3880 $.ui.ddmanager.prepareOffsets(this, event);
3881
3882 this.dragging = true;
3883
3884 this.helper.addClass("ui-sortable-helper");
3885 this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
3886 return true;
3887
3888 },
3889
3890 _mouseDrag: function(event) {
3891
3892 //Compute the helpers position
3893 this.position = this._generatePosition(event);
3894 this.positionAbs = this._convertPositionTo("absolute");
3895
3896 if (!this.lastPositionAbs) {
3897 this.lastPositionAbs = this.positionAbs;
3898 }
3899
3900 //Do scrolling
3901 if(this.options.scroll) {
3902 var o = this.options, scrolled = false;
3903 if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') {
3904
3905 if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
3906 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
3907 else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity)
3908 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
3909
3910 if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
3911 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
3912 else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity)
3913 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
3914
3915 } else {
3916
3917 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
3918 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
3919 else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
3920 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
3921
3922 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
3923 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
3924 else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
3925 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
3926
3927 }
3928
3929 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
3930 $.ui.ddmanager.prepareOffsets(this, event);
3931 }
3932
3933 //Regenerate the absolute position used for position checks
3934 this.positionAbs = this._convertPositionTo("absolute");
3935
3936 //Set the helper position
3937 if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
3938 if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
3939
3940 //Rearrange
3941 for (var i = this.items.length - 1; i >= 0; i--) {
3942
3943 //Cache variables and intersection, continue if no intersection
3944 var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item);
3945 if (!intersection) continue;
3946
3947 // Only put the placeholder inside the current Container, skip all
3948 // items form other containers. This works because when moving
3949 // an item from one container to another the
3950 // currentContainer is switched before the placeholder is moved.
3951 //
3952 // Without this moving items in "sub-sortables" can cause the placeholder to jitter
3953 // beetween the outer and inner container.
3954 if (item.instance !== this.currentContainer) continue;
3955
3956 if (itemElement != this.currentItem[0] //cannot intersect with itself
3957 && this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before
3958 && !$.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked
3959 && (this.options.type == 'semi-dynamic' ? !$.contains(this.element[0], itemElement) : true)
3960 //&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container
3961 ) {
3962
3963 this.direction = intersection == 1 ? "down" : "up";
3964
3965 if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) {
3966 this._rearrange(event, item);
3967 } else {
3968 break;
3969 }
3970
3971 this._trigger("change", event, this._uiHash());
3972 break;
3973 }
3974 }
3975
3976 //Post events to containers
3977 this._contactContainers(event);
3978
3979 //Interconnect with droppables
3980 if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
3981
3982 //Call callbacks
3983 this._trigger('sort', event, this._uiHash());
3984
3985 this.lastPositionAbs = this.positionAbs;
3986 return false;
3987
3988 },
3989
3990 _mouseStop: function(event, noPropagation) {
3991
3992 if(!event) return;
3993
3994 //If we are using droppables, inform the manager about the drop
3995 if ($.ui.ddmanager && !this.options.dropBehaviour)
3996 $.ui.ddmanager.drop(this, event);
3997
3998 if(this.options.revert) {
3999 var that = this;
4000 var cur = this.placeholder.offset();
4001
4002 this.reverting = true;
4003
4004 $(this.helper).animate({
4005 left: cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft),
4006 top: cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop)
4007 }, parseInt(this.options.revert, 10) || 500, function() {
4008 that._clear(event);
4009 });
4010 } else {
4011 this._clear(event, noPropagation);
4012 }
4013
4014 return false;
4015
4016 },
4017
4018 cancel: function() {
4019
4020 if(this.dragging) {
4021
4022 this._mouseUp({ target: null });
4023
4024 if(this.options.helper == "original")
4025 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
4026 else
4027 this.currentItem.show();
4028
4029 //Post deactivating events to containers
4030 for (var i = this.containers.length - 1; i >= 0; i--){
4031 this.containers[i]._trigger("deactivate", null, this._uiHash(this));
4032 if(this.containers[i].containerCache.over) {
4033 this.containers[i]._trigger("out", null, this._uiHash(this));
4034 this.containers[i].containerCache.over = 0;
4035 }
4036 }
4037
4038 }
4039
4040 if (this.placeholder) {
4041 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
4042 if(this.placeholder[0].parentNode) this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
4043 if(this.options.helper != "original" && this.helper && this.helper[0].parentNode) this.helper.remove();
4044
4045 $.extend(this, {
4046 helper: null,
4047 dragging: false,
4048 reverting: false,
4049 _noFinalSort: null
4050 });
4051
4052 if(this.domPosition.prev) {
4053 $(this.domPosition.prev).after(this.currentItem);
4054 } else {
4055 $(this.domPosition.parent).prepend(this.currentItem);
4056 }
4057 }
4058
4059 return this;
4060
4061 },
4062
4063 serialize: function(o) {
4064
4065 var items = this._getItemsAsjQuery(o && o.connected);
4066 var str = []; o = o || {};
4067
4068 $(items).each(function() {
4069 var res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
4070 if(res) str.push((o.key || res[1]+'[]')+'='+(o.key && o.expression ? res[1] : res[2]));
4071 });
4072
4073 if(!str.length && o.key) {
4074 str.push(o.key + '=');
4075 }
4076
4077 return str.join('&');
4078
4079 },
4080
4081 toArray: function(o) {
4082
4083 var items = this._getItemsAsjQuery(o && o.connected);
4084 var ret = []; o = o || {};
4085
4086 items.each(function() { ret.push($(o.item || this).attr(o.attribute || 'id') || ''); });
4087 return ret;
4088
4089 },
4090
4091 /* Be careful with the following core functions */
4092 _intersectsWith: function(item) {
4093
4094 var x1 = this.positionAbs.left,
4095 x2 = x1 + this.helperProportions.width,
4096 y1 = this.positionAbs.top,
4097 y2 = y1 + this.helperProportions.height;
4098
4099 var l = item.left,
4100 r = l + item.width,
4101 t = item.top,
4102 b = t + item.height;
4103
4104 var dyClick = this.offset.click.top,
4105 dxClick = this.offset.click.left;
4106
4107 var isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r;
4108
4109 if( this.options.tolerance == "pointer"
4110 || this.options.forcePointerForContainers
4111 || (this.options.tolerance != "pointer" && this.helperProportions[this.floating ? 'width' : 'height'] > item[this.floating ? 'width' : 'height'])
4112 ) {
4113 return isOverElement;
4114 } else {
4115
4116 return (l < x1 + (this.helperProportions.width / 2) // Right Half
4117 && x2 - (this.helperProportions.width / 2) < r // Left Half
4118 && t < y1 + (this.helperProportions.height / 2) // Bottom Half
4119 && y2 - (this.helperProportions.height / 2) < b ); // Top Half
4120
4121 }
4122 },
4123
4124 _intersectsWithPointer: function(item) {
4125
4126 var isOverElementHeight = (this.options.axis === 'x') || $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
4127 isOverElementWidth = (this.options.axis === 'y') || $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
4128 isOverElement = isOverElementHeight && isOverElementWidth,
4129 verticalDirection = this._getDragVerticalDirection(),
4130 horizontalDirection = this._getDragHorizontalDirection();
4131
4132 if (!isOverElement)
4133 return false;
4134
4135 return this.floating ?
4136 ( ((horizontalDirection && horizontalDirection == "right") || verticalDirection == "down") ? 2 : 1 )
4137 : ( verticalDirection && (verticalDirection == "down" ? 2 : 1) );
4138
4139 },
4140
4141 _intersectsWithSides: function(item) {
4142
4143 var isOverBottomHalf = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
4144 isOverRightHalf = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
4145 verticalDirection = this._getDragVerticalDirection(),
4146 horizontalDirection = this._getDragHorizontalDirection();
4147
4148 if (this.floating && horizontalDirection) {
4149 return ((horizontalDirection == "right" && isOverRightHalf) || (horizontalDirection == "left" && !isOverRightHalf));
4150 } else {
4151 return verticalDirection && ((verticalDirection == "down" && isOverBottomHalf) || (verticalDirection == "up" && !isOverBottomHalf));
4152 }
4153
4154 },
4155
4156 _getDragVerticalDirection: function() {
4157 var delta = this.positionAbs.top - this.lastPositionAbs.top;
4158 return delta != 0 && (delta > 0 ? "down" : "up");
4159 },
4160
4161 _getDragHorizontalDirection: function() {
4162 var delta = this.positionAbs.left - this.lastPositionAbs.left;
4163 return delta != 0 && (delta > 0 ? "right" : "left");
4164 },
4165
4166 refresh: function(event) {
4167 this._refreshItems(event);
4168 this.refreshPositions();
4169 return this;
4170 },
4171
4172 _connectWith: function() {
4173 var options = this.options;
4174 return options.connectWith.constructor == String
4175 ? [options.connectWith]
4176 : options.connectWith;
4177 },
4178
4179 _getItemsAsjQuery: function(connected) {
4180
4181 var items = [];
4182 var queries = [];
4183 var connectWith = this._connectWith();
4184
4185 if(connectWith && connected) {
4186 for (var i = connectWith.length - 1; i >= 0; i--){
4187 var cur = $(connectWith[i]);
4188 for (var j = cur.length - 1; j >= 0; j--){
4189 var inst = $.data(cur[j], this.widgetName);
4190 if(inst && inst != this && !inst.options.disabled) {
4191 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]);
4192 }
4193 };
4194 };
4195 }
4196
4197 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]);
4198
4199 for (var i = queries.length - 1; i >= 0; i--){
4200 queries[i][0].each(function() {
4201 items.push(this);
4202 });
4203 };
4204
4205 return $(items);
4206
4207 },
4208
4209 _removeCurrentsFromItems: function() {
4210
4211 var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
4212
4213 this.items = $.grep(this.items, function (item) {
4214 for (var j=0; j < list.length; j++) {
4215 if(list[j] == item.item[0])
4216 return false;
4217 };
4218 return true;
4219 });
4220
4221 },
4222
4223 _refreshItems: function(event) {
4224
4225 this.items = [];
4226 this.containers = [this];
4227 var items = this.items;
4228 var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]];
4229 var connectWith = this._connectWith();
4230
4231 if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
4232 for (var i = connectWith.length - 1; i >= 0; i--){
4233 var cur = $(connectWith[i]);
4234 for (var j = cur.length - 1; j >= 0; j--){
4235 var inst = $.data(cur[j], this.widgetName);
4236 if(inst && inst != this && !inst.options.disabled) {
4237 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
4238 this.containers.push(inst);
4239 }
4240 };
4241 };
4242 }
4243
4244 for (var i = queries.length - 1; i >= 0; i--) {
4245 var targetData = queries[i][1];
4246 var _queries = queries[i][0];
4247
4248 for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) {
4249 var item = $(_queries[j]);
4250
4251 item.data(this.widgetName + '-item', targetData); // Data for target checking (mouse manager)
4252
4253 items.push({
4254 item: item,
4255 instance: targetData,
4256 width: 0, height: 0,
4257 left: 0, top: 0
4258 });
4259 };
4260 };
4261
4262 },
4263
4264 refreshPositions: function(fast) {
4265
4266 //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
4267 if(this.offsetParent && this.helper) {
4268 this.offset.parent = this._getParentOffset();
4269 }
4270
4271 for (var i = this.items.length - 1; i >= 0; i--){
4272 var item = this.items[i];
4273
4274 //We ignore calculating positions of all connected containers when we're not over them
4275 if(item.instance != this.currentContainer && this.currentContainer && item.item[0] != this.currentItem[0])
4276 continue;
4277
4278 var t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
4279
4280 if (!fast) {
4281 item.width = t.outerWidth();
4282 item.height = t.outerHeight();
4283 }
4284
4285 var p = t.offset();
4286 item.left = p.left;
4287 item.top = p.top;
4288 };
4289
4290 if(this.options.custom && this.options.custom.refreshContainers) {
4291 this.options.custom.refreshContainers.call(this);
4292 } else {
4293 for (var i = this.containers.length - 1; i >= 0; i--){
4294 var p = this.containers[i].element.offset();
4295 this.containers[i].containerCache.left = p.left;
4296 this.containers[i].containerCache.top = p.top;
4297 this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
4298 this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
4299 };
4300 }
4301
4302 return this;
4303 },
4304
4305 _createPlaceholder: function(that) {
4306 that = that || this;
4307 var o = that.options;
4308
4309 if(!o.placeholder || o.placeholder.constructor == String) {
4310 var className = o.placeholder;
4311 o.placeholder = {
4312 element: function() {
4313
4314 var el = $(document.createElement(that.currentItem[0].nodeName))
4315 .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
4316 .removeClass("ui-sortable-helper")[0];
4317
4318 if(!className)
4319 el.style.visibility = "hidden";
4320
4321 return el;
4322 },
4323 update: function(container, p) {
4324
4325 // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
4326 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
4327 if(className && !o.forcePlaceholderSize) return;
4328
4329 //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
4330 if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css('paddingTop')||0, 10) - parseInt(that.currentItem.css('paddingBottom')||0, 10)); };
4331 if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css('paddingLeft')||0, 10) - parseInt(that.currentItem.css('paddingRight')||0, 10)); };
4332 }
4333 };
4334 }
4335
4336 //Create the placeholder
4337 that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));
4338
4339 //Append it after the actual current item
4340 that.currentItem.after(that.placeholder);
4341
4342 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
4343 o.placeholder.update(that, that.placeholder);
4344
4345 },
4346
4347 _contactContainers: function(event) {
4348
4349 // get innermost container that intersects with item
4350 var innermostContainer = null, innermostIndex = null;
4351
4352
4353 for (var i = this.containers.length - 1; i >= 0; i--){
4354
4355 // never consider a container that's located within the item itself
4356 if($.contains(this.currentItem[0], this.containers[i].element[0]))
4357 continue;
4358
4359 if(this._intersectsWith(this.containers[i].containerCache)) {
4360
4361 // if we've already found a container and it's more "inner" than this, then continue
4362 if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0]))
4363 continue;
4364
4365 innermostContainer = this.containers[i];
4366 innermostIndex = i;
4367
4368 } else {
4369 // container doesn't intersect. trigger "out" event if necessary
4370 if(this.containers[i].containerCache.over) {
4371 this.containers[i]._trigger("out", event, this._uiHash(this));
4372 this.containers[i].containerCache.over = 0;
4373 }
4374 }
4375
4376 }
4377
4378 // if no intersecting containers found, return
4379 if(!innermostContainer) return;
4380
4381 // move the item into the container if it's not there already
4382 if(this.containers.length === 1) {
4383 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
4384 this.containers[innermostIndex].containerCache.over = 1;
4385 } else {
4386
4387 //When entering a new container, we will find the item with the least distance and append our item near it
4388 var dist = 10000; var itemWithLeastDistance = null;
4389 var posProperty = this.containers[innermostIndex].floating ? 'left' : 'top';
4390 var sizeProperty = this.containers[innermostIndex].floating ? 'width' : 'height';
4391 var base = this.positionAbs[posProperty] + this.offset.click[posProperty];
4392 for (var j = this.items.length - 1; j >= 0; j--) {
4393 if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) continue;
4394 if(this.items[j].item[0] == this.currentItem[0]) continue;
4395 var cur = this.items[j].item.offset()[posProperty];
4396 var nearBottom = false;
4397 if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){
4398 nearBottom = true;
4399 cur += this.items[j][sizeProperty];
4400 }
4401
4402 if(Math.abs(cur - base) < dist) {
4403 dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j];
4404 this.direction = nearBottom ? "up": "down";
4405 }
4406 }
4407
4408 if(!itemWithLeastDistance && !this.options.dropOnEmpty) //Check if dropOnEmpty is enabled
4409 return;
4410
4411 this.currentContainer = this.containers[innermostIndex];
4412 itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
4413 this._trigger("change", event, this._uiHash());
4414 this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
4415
4416 //Update the placeholder
4417 this.options.placeholder.update(this.currentContainer, this.placeholder);
4418
4419 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
4420 this.containers[innermostIndex].containerCache.over = 1;
4421 }
4422
4423
4424 },
4425
4426 _createHelper: function(event) {
4427
4428 var o = this.options;
4429 var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper == 'clone' ? this.currentItem.clone() : this.currentItem);
4430
4431 if(!helper.parents('body').length) //Add the helper to the DOM if that didn't happen already
4432 $(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
4433
4434 if(helper[0] == this.currentItem[0])
4435 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") };
4436
4437 if(helper[0].style.width == '' || o.forceHelperSize) helper.width(this.currentItem.width());
4438 if(helper[0].style.height == '' || o.forceHelperSize) helper.height(this.currentItem.height());
4439
4440 return helper;
4441
4442 },
4443
4444 _adjustOffsetFromHelper: function(obj) {
4445 if (typeof obj == 'string') {
4446 obj = obj.split(' ');
4447 }
4448 if ($.isArray(obj)) {
4449 obj = {left: +obj[0], top: +obj[1] || 0};
4450 }
4451 if ('left' in obj) {
4452 this.offset.click.left = obj.left + this.margins.left;
4453 }
4454 if ('right' in obj) {
4455 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
4456 }
4457 if ('top' in obj) {
4458 this.offset.click.top = obj.top + this.margins.top;
4459 }
4460 if ('bottom' in obj) {
4461 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
4462 }
4463 },
4464
4465 _getParentOffset: function() {
4466
4467
4468 //Get the offsetParent and cache its position
4469 this.offsetParent = this.helper.offsetParent();
4470 var po = this.offsetParent.offset();
4471
4472 // This is a special case where we need to modify a offset calculated on start, since the following happened:
4473 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
4474 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
4475 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
4476 if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
4477 po.left += this.scrollParent.scrollLeft();
4478 po.top += this.scrollParent.scrollTop();
4479 }
4480
4481 if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information
4482 || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.ui.ie)) //Ugly IE fix
4483 po = { top: 0, left: 0 };
4484
4485 return {
4486 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
4487 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
4488 };
4489
4490 },
4491
4492 _getRelativeOffset: function() {
4493
4494 if(this.cssPosition == "relative") {
4495 var p = this.currentItem.position();
4496 return {
4497 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
4498 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
4499 };
4500 } else {
4501 return { top: 0, left: 0 };
4502 }
4503
4504 },
4505
4506 _cacheMargins: function() {
4507 this.margins = {
4508 left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
4509 top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
4510 };
4511 },
4512
4513 _cacheHelperProportions: function() {
4514 this.helperProportions = {
4515 width: this.helper.outerWidth(),
4516 height: this.helper.outerHeight()
4517 };
4518 },
4519
4520 _setContainment: function() {
4521
4522 var o = this.options;
4523 if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
4524 if(o.containment == 'document' || o.containment == 'window') this.containment = [
4525 0 - this.offset.relative.left - this.offset.parent.left,
4526 0 - this.offset.relative.top - this.offset.parent.top,
4527 $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left,
4528 ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
4529 ];
4530
4531 if(!(/^(document|window|parent)$/).test(o.containment)) {
4532 var ce = $(o.containment)[0];
4533 var co = $(o.containment).offset();
4534 var over = ($(ce).css("overflow") != 'hidden');
4535
4536 this.containment = [
4537 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
4538 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
4539 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,
4540 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
4541 ];
4542 }
4543
4544 },
4545
4546 _convertPositionTo: function(d, pos) {
4547
4548 if(!pos) pos = this.position;
4549 var mod = d == "absolute" ? 1 : -1;
4550 var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
4551
4552 return {
4553 top: (
4554 pos.top // The absolute mouse position
4555 + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent
4556 + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border)
4557 - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
4558 ),
4559 left: (
4560 pos.left // The absolute mouse position
4561 + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent
4562 + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border)
4563 - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
4564 )
4565 };
4566
4567 },
4568
4569 _generatePosition: function(event) {
4570
4571 var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
4572
4573 // This is another very weird special case that only happens for relative elements:
4574 // 1. If the css position is relative
4575 // 2. and the scroll parent is the document or similar to the offset parent
4576 // we have to refresh the relative offset during the scroll so there are no jumps
4577 if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) {
4578 this.offset.relative = this._getRelativeOffset();
4579 }
4580
4581 var pageX = event.pageX;
4582 var pageY = event.pageY;
4583
4584 /*
4585 * - Position constraining -
4586 * Constrain the position to a mix of grid, containment.
4587 */
4588
4589 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
4590
4591 if(this.containment) {
4592 if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left;
4593 if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top;
4594 if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left;
4595 if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top;
4596 }
4597
4598 if(o.grid) {
4599 var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
4600 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;
4601
4602 var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
4603 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;
4604 }
4605
4606 }
4607
4608 return {
4609 top: (
4610 pageY // The absolute mouse position
4611 - this.offset.click.top // Click offset (relative to the element)
4612 - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent
4613 - this.offset.parent.top // The offsetParent's offset without borders (offset + border)
4614 + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
4615 ),
4616 left: (
4617 pageX // The absolute mouse position
4618 - this.offset.click.left // Click offset (relative to the element)
4619 - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent
4620 - this.offset.parent.left // The offsetParent's offset without borders (offset + border)
4621 + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
4622 )
4623 };
4624
4625 },
4626
4627 _rearrange: function(event, i, a, hardRefresh) {
4628
4629 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));
4630
4631 //Various things done here to improve the performance:
4632 // 1. we create a setTimeout, that calls refreshPositions
4633 // 2. on the instance, we have a counter variable, that get's higher after every append
4634 // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
4635 // 4. this lets only the last addition to the timeout stack through
4636 this.counter = this.counter ? ++this.counter : 1;
4637 var counter = this.counter;
4638
4639 this._delay(function() {
4640 if(counter == this.counter) this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
4641 });
4642
4643 },
4644
4645 _clear: function(event, noPropagation) {
4646
4647 this.reverting = false;
4648 // We delay all events that have to be triggered to after the point where the placeholder has been removed and
4649 // everything else normalized again
4650 var delayedTriggers = [];
4651
4652 // We first have to update the dom position of the actual currentItem
4653 // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
4654 if(!this._noFinalSort && this.currentItem.parent().length) this.placeholder.before(this.currentItem);
4655 this._noFinalSort = null;
4656
4657 if(this.helper[0] == this.currentItem[0]) {
4658 for(var i in this._storedCSS) {
4659 if(this._storedCSS[i] == 'auto' || this._storedCSS[i] == 'static') this._storedCSS[i] = '';
4660 }
4661 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
4662 } else {
4663 this.currentItem.show();
4664 }
4665
4666 if(this.fromOutside && !noPropagation) delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
4667 if((this.fromOutside || this.domPosition.prev != this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent != this.currentItem.parent()[0]) && !noPropagation) delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
4668
4669 // Check if the items Container has Changed and trigger appropriate
4670 // events.
4671 if (this !== this.currentContainer) {
4672 if(!noPropagation) {
4673 delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
4674 delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
4675 delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
4676 }
4677 }
4678
4679
4680 //Post events to containers
4681 for (var i = this.containers.length - 1; i >= 0; i--){
4682 if(!noPropagation) delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
4683 if(this.containers[i].containerCache.over) {
4684 delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
4685 this.containers[i].containerCache.over = 0;
4686 }
4687 }
4688
4689 //Do what was originally in plugins
4690 if(this._storedCursor) $('body').css("cursor", this._storedCursor); //Reset cursor
4691 if(this._storedOpacity) this.helper.css("opacity", this._storedOpacity); //Reset opacity
4692 if(this._storedZIndex) this.helper.css("zIndex", this._storedZIndex == 'auto' ? '' : this._storedZIndex); //Reset z-index
4693
4694 this.dragging = false;
4695 if(this.cancelHelperRemoval) {
4696 if(!noPropagation) {
4697 this._trigger("beforeStop", event, this._uiHash());
4698 for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events
4699 this._trigger("stop", event, this._uiHash());
4700 }
4701
4702 this.fromOutside = false;
4703 return false;
4704 }
4705
4706 if(!noPropagation) this._trigger("beforeStop", event, this._uiHash());
4707
4708 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
4709 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
4710
4711 if(this.helper[0] != this.currentItem[0]) this.helper.remove(); this.helper = null;
4712
4713 if(!noPropagation) {
4714 for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events
4715 this._trigger("stop", event, this._uiHash());
4716 }
4717
4718 this.fromOutside = false;
4719 return true;
4720
4721 },
4722
4723 _trigger: function() {
4724 if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
4725 this.cancel();
4726 }
4727 },
4728
4729 _uiHash: function(_inst) {
4730 var inst = _inst || this;
4731 return {
4732 helper: inst.helper,
4733 placeholder: inst.placeholder || $([]),
4734 position: inst.position,
4735 originalPosition: inst.originalPosition,
4736 offset: inst.positionAbs,
4737 item: inst.currentItem,
4738 sender: _inst ? _inst.element : null
4739 };
4740 }
4741
4742 });
4743
4744 })(jQuery);
4745 (function( $, undefined ) {
4746
4747 var uid = 0,
4748 hideProps = {},
4749 showProps = {};
4750
4751 hideProps.height = hideProps.paddingTop = hideProps.paddingBottom =
4752 hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide";
4753 showProps.height = showProps.paddingTop = showProps.paddingBottom =
4754 showProps.borderTopWidth = showProps.borderBottomWidth = "show";
4755
4756 $.widget( "ui.accordion", {
4757 version: "1.9.2",
4758 options: {
4759 active: 0,
4760 animate: {},
4761 collapsible: false,
4762 event: "click",
4763 header: "> li > :first-child,> :not(li):even",
4764 heightStyle: "auto",
4765 icons: {
4766 activeHeader: "ui-icon-triangle-1-s",
4767 header: "ui-icon-triangle-1-e"
4768 },
4769
4770 // callbacks
4771 activate: null,
4772 beforeActivate: null
4773 },
4774
4775 _create: function() {
4776 var accordionId = this.accordionId = "ui-accordion-" +
4777 (this.element.attr( "id" ) || ++uid),
4778 options = this.options;
4779
4780 this.prevShow = this.prevHide = $();
4781 this.element.addClass( "ui-accordion ui-widget ui-helper-reset" );
4782
4783 this.headers = this.element.find( options.header )
4784 .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" );
4785 this._hoverable( this.headers );
4786 this._focusable( this.headers );
4787
4788 this.headers.next()
4789 .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
4790 .hide();
4791
4792 // don't allow collapsible: false and active: false / null
4793 if ( !options.collapsible && (options.active === false || options.active == null) ) {
4794 options.active = 0;
4795 }
4796 // handle negative values
4797 if ( options.active < 0 ) {
4798 options.active += this.headers.length;
4799 }
4800 this.active = this._findActive( options.active )
4801 .addClass( "ui-accordion-header-active ui-state-active" )
4802 .toggleClass( "ui-corner-all ui-corner-top" );
4803 this.active.next()
4804 .addClass( "ui-accordion-content-active" )
4805 .show();
4806
4807 this._createIcons();
4808 this.refresh();
4809
4810 // ARIA
4811 this.element.attr( "role", "tablist" );
4812
4813 this.headers
4814 .attr( "role", "tab" )
4815 .each(function( i ) {
4816 var header = $( this ),
4817 headerId = header.attr( "id" ),
4818 panel = header.next(),
4819 panelId = panel.attr( "id" );
4820 if ( !headerId ) {
4821 headerId = accordionId + "-header-" + i;
4822 header.attr( "id", headerId );
4823 }
4824 if ( !panelId ) {
4825 panelId = accordionId + "-panel-" + i;
4826 panel.attr( "id", panelId );
4827 }
4828 header.attr( "aria-controls", panelId );
4829 panel.attr( "aria-labelledby", headerId );
4830 })
4831 .next()
4832 .attr( "role", "tabpanel" );
4833
4834 this.headers
4835 .not( this.active )
4836 .attr({
4837 "aria-selected": "false",
4838 tabIndex: -1
4839 })
4840 .next()
4841 .attr({
4842 "aria-expanded": "false",
4843 "aria-hidden": "true"
4844 })
4845 .hide();
4846
4847 // make sure at least one header is in the tab order
4848 if ( !this.active.length ) {
4849 this.headers.eq( 0 ).attr( "tabIndex", 0 );
4850 } else {
4851 this.active.attr({
4852 "aria-selected": "true",
4853 tabIndex: 0
4854 })
4855 .next()
4856 .attr({
4857 "aria-expanded": "true",
4858 "aria-hidden": "false"
4859 });
4860 }
4861
4862 this._on( this.headers, { keydown: "_keydown" });
4863 this._on( this.headers.next(), { keydown: "_panelKeyDown" });
4864 this._setupEvents( options.event );
4865 },
4866
4867 _getCreateEventData: function() {
4868 return {
4869 header: this.active,
4870 content: !this.active.length ? $() : this.active.next()
4871 };
4872 },
4873
4874 _createIcons: function() {
4875 var icons = this.options.icons;
4876 if ( icons ) {
4877 $( "<span>" )
4878 .addClass( "ui-accordion-header-icon ui-icon " + icons.header )
4879 .prependTo( this.headers );
4880 this.active.children( ".ui-accordion-header-icon" )
4881 .removeClass( icons.header )
4882 .addClass( icons.activeHeader );
4883 this.headers.addClass( "ui-accordion-icons" );
4884 }
4885 },
4886
4887 _destroyIcons: function() {
4888 this.headers
4889 .removeClass( "ui-accordion-icons" )
4890 .children( ".ui-accordion-header-icon" )
4891 .remove();
4892 },
4893
4894 _destroy: function() {
4895 var contents;
4896
4897 // clean up main element
4898 this.element
4899 .removeClass( "ui-accordion ui-widget ui-helper-reset" )
4900 .removeAttr( "role" );
4901
4902 // clean up headers
4903 this.headers
4904 .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" )
4905 .removeAttr( "role" )
4906 .removeAttr( "aria-selected" )
4907 .removeAttr( "aria-controls" )
4908 .removeAttr( "tabIndex" )
4909 .each(function() {
4910 if ( /^ui-accordion/.test( this.id ) ) {
4911 this.removeAttribute( "id" );
4912 }
4913 });
4914 this._destroyIcons();
4915
4916 // clean up content panels
4917 contents = this.headers.next()
4918 .css( "display", "" )
4919 .removeAttr( "role" )
4920 .removeAttr( "aria-expanded" )
4921 .removeAttr( "aria-hidden" )
4922 .removeAttr( "aria-labelledby" )
4923 .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" )
4924 .each(function() {
4925 if ( /^ui-accordion/.test( this.id ) ) {
4926 this.removeAttribute( "id" );
4927 }
4928 });
4929 if ( this.options.heightStyle !== "content" ) {
4930 contents.css( "height", "" );
4931 }
4932 },
4933
4934 _setOption: function( key, value ) {
4935 if ( key === "active" ) {
4936 // _activate() will handle invalid values and update this.options
4937 this._activate( value );
4938 return;
4939 }
4940
4941 if ( key === "event" ) {
4942 if ( this.options.event ) {
4943 this._off( this.headers, this.options.event );
4944 }
4945 this._setupEvents( value );
4946 }
4947
4948 this._super( key, value );
4949
4950 // setting collapsible: false while collapsed; open first panel
4951 if ( key === "collapsible" && !value && this.options.active === false ) {
4952 this._activate( 0 );
4953 }
4954
4955 if ( key === "icons" ) {
4956 this._destroyIcons();
4957 if ( value ) {
4958 this._createIcons();
4959 }
4960 }
4961
4962 // #5332 - opacity doesn't cascade to positioned elements in IE
4963 // so we need to add the disabled class to the headers and panels
4964 if ( key === "disabled" ) {
4965 this.headers.add( this.headers.next() )
4966 .toggleClass( "ui-state-disabled", !!value );
4967 }
4968 },
4969
4970 _keydown: function( event ) {
4971 if ( event.altKey || event.ctrlKey ) {
4972 return;
4973 }
4974
4975 var keyCode = $.ui.keyCode,
4976 length = this.headers.length,
4977 currentIndex = this.headers.index( event.target ),
4978 toFocus = false;
4979
4980 switch ( event.keyCode ) {
4981 case keyCode.RIGHT:
4982 case keyCode.DOWN:
4983 toFocus = this.headers[ ( currentIndex + 1 ) % length ];
4984 break;
4985 case keyCode.LEFT:
4986 case keyCode.UP:
4987 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
4988 break;
4989 case keyCode.SPACE:
4990 case keyCode.ENTER:
4991 this._eventHandler( event );
4992 break;
4993 case keyCode.HOME:
4994 toFocus = this.headers[ 0 ];
4995 break;
4996 case keyCode.END:
4997 toFocus = this.headers[ length - 1 ];
4998 break;
4999 }
5000
5001 if ( toFocus ) {
5002 $( event.target ).attr( "tabIndex", -1 );
5003 $( toFocus ).attr( "tabIndex", 0 );
5004 toFocus.focus();
5005 event.preventDefault();
5006 }
5007 },
5008
5009 _panelKeyDown : function( event ) {
5010 if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
5011 $( event.currentTarget ).prev().focus();
5012 }
5013 },
5014
5015 refresh: function() {
5016 var maxHeight, overflow,
5017 heightStyle = this.options.heightStyle,
5018 parent = this.element.parent();
5019
5020
5021 if ( heightStyle === "fill" ) {
5022 // IE 6 treats height like minHeight, so we need to turn off overflow
5023 // in order to get a reliable height
5024 // we use the minHeight support test because we assume that only
5025 // browsers that don't support minHeight will treat height as minHeight
5026 if ( !$.support.minHeight ) {
5027 overflow = parent.css( "overflow" );
5028 parent.css( "overflow", "hidden");
5029 }
5030 maxHeight = parent.height();
5031 this.element.siblings( ":visible" ).each(function() {
5032 var elem = $( this ),
5033 position = elem.css( "position" );
5034
5035 if ( position === "absolute" || position === "fixed" ) {
5036 return;
5037 }
5038 maxHeight -= elem.outerHeight( true );
5039 });
5040 if ( overflow ) {
5041 parent.css( "overflow", overflow );
5042 }
5043
5044 this.headers.each(function() {
5045 maxHeight -= $( this ).outerHeight( true );
5046 });
5047
5048 this.headers.next()
5049 .each(function() {
5050 $( this ).height( Math.max( 0, maxHeight -
5051 $( this ).innerHeight() + $( this ).height() ) );
5052 })
5053 .css( "overflow", "auto" );
5054 } else if ( heightStyle === "auto" ) {
5055 maxHeight = 0;
5056 this.headers.next()
5057 .each(function() {
5058 maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
5059 })
5060 .height( maxHeight );
5061 }
5062 },
5063
5064 _activate: function( index ) {
5065 var active = this._findActive( index )[ 0 ];
5066
5067 // trying to activate the already active panel
5068 if ( active === this.active[ 0 ] ) {
5069 return;
5070 }
5071
5072 // trying to collapse, simulate a click on the currently active header
5073 active = active || this.active[ 0 ];
5074
5075 this._eventHandler({
5076 target: active,
5077 currentTarget: active,
5078 preventDefault: $.noop
5079 });
5080 },
5081
5082 _findActive: function( selector ) {
5083 return typeof selector === "number" ? this.headers.eq( selector ) : $();
5084 },
5085
5086 _setupEvents: function( event ) {
5087 var events = {};
5088 if ( !event ) {
5089 return;
5090 }
5091 $.each( event.split(" "), function( index, eventName ) {
5092 events[ eventName ] = "_eventHandler";
5093 });
5094 this._on( this.headers, events );
5095 },
5096
5097 _eventHandler: function( event ) {
5098 var options = this.options,
5099 active = this.active,
5100 clicked = $( event.currentTarget ),
5101 clickedIsActive = clicked[ 0 ] === active[ 0 ],
5102 collapsing = clickedIsActive && options.collapsible,
5103 toShow = collapsing ? $() : clicked.next(),
5104 toHide = active.next(),
5105 eventData = {
5106 oldHeader: active,
5107 oldPanel: toHide,
5108 newHeader: collapsing ? $() : clicked,
5109 newPanel: toShow
5110 };
5111
5112 event.preventDefault();
5113
5114 if (
5115 // click on active header, but not collapsible
5116 ( clickedIsActive && !options.collapsible ) ||
5117 // allow canceling activation
5118 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
5119 return;
5120 }
5121
5122 options.active = collapsing ? false : this.headers.index( clicked );
5123
5124 // when the call to ._toggle() comes after the class changes
5125 // it causes a very odd bug in IE 8 (see #6720)
5126 this.active = clickedIsActive ? $() : clicked;
5127 this._toggle( eventData );
5128
5129 // switch classes
5130 // corner classes on the previously active header stay after the animation
5131 active.removeClass( "ui-accordion-header-active ui-state-active" );
5132 if ( options.icons ) {
5133 active.children( ".ui-accordion-header-icon" )
5134 .removeClass( options.icons.activeHeader )
5135 .addClass( options.icons.header );
5136 }
5137
5138 if ( !clickedIsActive ) {
5139 clicked
5140 .removeClass( "ui-corner-all" )
5141 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" );
5142 if ( options.icons ) {
5143 clicked.children( ".ui-accordion-header-icon" )
5144 .removeClass( options.icons.header )
5145 .addClass( options.icons.activeHeader );
5146 }
5147
5148 clicked
5149 .next()
5150 .addClass( "ui-accordion-content-active" );
5151 }
5152 },
5153
5154 _toggle: function( data ) {
5155 var toShow = data.newPanel,
5156 toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
5157
5158 // handle activating a panel during the animation for another activation
5159 this.prevShow.add( this.prevHide ).stop( true, true );
5160 this.prevShow = toShow;
5161 this.prevHide = toHide;
5162
5163 if ( this.options.animate ) {
5164 this._animate( toShow, toHide, data );
5165 } else {
5166 toHide.hide();
5167 toShow.show();
5168 this._toggleComplete( data );
5169 }
5170
5171 toHide.attr({
5172 "aria-expanded": "false",
5173 "aria-hidden": "true"
5174 });
5175 toHide.prev().attr( "aria-selected", "false" );
5176 // if we're switching panels, remove the old header from the tab order
5177 // if we're opening from collapsed state, remove the previous header from the tab order
5178 // if we're collapsing, then keep the collapsing header in the tab order
5179 if ( toShow.length && toHide.length ) {
5180 toHide.prev().attr( "tabIndex", -1 );
5181 } else if ( toShow.length ) {
5182 this.headers.filter(function() {
5183 return $( this ).attr( "tabIndex" ) === 0;
5184 })
5185 .attr( "tabIndex", -1 );
5186 }
5187
5188 toShow
5189 .attr({
5190 "aria-expanded": "true",
5191 "aria-hidden": "false"
5192 })
5193 .prev()
5194 .attr({
5195 "aria-selected": "true",
5196 tabIndex: 0
5197 });
5198 },
5199
5200 _animate: function( toShow, toHide, data ) {
5201 var total, easing, duration,
5202 that = this,
5203 adjust = 0,
5204 down = toShow.length &&
5205 ( !toHide.length || ( toShow.index() < toHide.index() ) ),
5206 animate = this.options.animate || {},
5207 options = down && animate.down || animate,
5208 complete = function() {
5209 that._toggleComplete( data );
5210 };
5211
5212 if ( typeof options === "number" ) {
5213 duration = options;
5214 }
5215 if ( typeof options === "string" ) {
5216 easing = options;
5217 }
5218 // fall back from options to animation in case of partial down settings
5219 easing = easing || options.easing || animate.easing;
5220 duration = duration || options.duration || animate.duration;
5221
5222 if ( !toHide.length ) {
5223 return toShow.animate( showProps, duration, easing, complete );
5224 }
5225 if ( !toShow.length ) {
5226 return toHide.animate( hideProps, duration, easing, complete );
5227 }
5228
5229 total = toShow.show().outerHeight();
5230 toHide.animate( hideProps, {
5231 duration: duration,
5232 easing: easing,
5233 step: function( now, fx ) {
5234 fx.now = Math.round( now );
5235 }
5236 });
5237 toShow
5238 .hide()
5239 .animate( showProps, {
5240 duration: duration,
5241 easing: easing,
5242 complete: complete,
5243 step: function( now, fx ) {
5244 fx.now = Math.round( now );
5245 if ( fx.prop !== "height" ) {
5246 adjust += fx.now;
5247 } else if ( that.options.heightStyle !== "content" ) {
5248 fx.now = Math.round( total - toHide.outerHeight() - adjust );
5249 adjust = 0;
5250 }
5251 }
5252 });
5253 },
5254
5255 _toggleComplete: function( data ) {
5256 var toHide = data.oldPanel;
5257
5258 toHide
5259 .removeClass( "ui-accordion-content-active" )
5260 .prev()
5261 .removeClass( "ui-corner-top" )
5262 .addClass( "ui-corner-all" );
5263
5264 // Work around for rendering bug in IE (#5421)
5265 if ( toHide.length ) {
5266 toHide.parent()[0].className = toHide.parent()[0].className;
5267 }
5268
5269 this._trigger( "activate", null, data );
5270 }
5271 });
5272
5273
5274
5275 // DEPRECATED
5276 if ( $.uiBackCompat !== false ) {
5277 // navigation options
5278 (function( $, prototype ) {
5279 $.extend( prototype.options, {
5280 navigation: false,
5281 navigationFilter: function() {
5282 return this.href.toLowerCase() === location.href.toLowerCase();
5283 }
5284 });
5285
5286 var _create = prototype._create;
5287 prototype._create = function() {
5288 if ( this.options.navigation ) {
5289 var that = this,
5290 headers = this.element.find( this.options.header ),
5291 content = headers.next(),
5292 current = headers.add( content )
5293 .find( "a" )
5294 .filter( this.options.navigationFilter )
5295 [ 0 ];
5296 if ( current ) {
5297 headers.add( content ).each( function( index ) {
5298 if ( $.contains( this, current ) ) {
5299 that.options.active = Math.floor( index / 2 );
5300 return false;
5301 }
5302 });
5303 }
5304 }
5305 _create.call( this );
5306 };
5307 }( jQuery, jQuery.ui.accordion.prototype ) );
5308
5309 // height options
5310 (function( $, prototype ) {
5311 $.extend( prototype.options, {
5312 heightStyle: null, // remove default so we fall back to old values
5313 autoHeight: true, // use heightStyle: "auto"
5314 clearStyle: false, // use heightStyle: "content"
5315 fillSpace: false // use heightStyle: "fill"
5316 });
5317
5318 var _create = prototype._create,
5319 _setOption = prototype._setOption;
5320
5321 $.extend( prototype, {
5322 _create: function() {
5323 this.options.heightStyle = this.options.heightStyle ||
5324 this._mergeHeightStyle();
5325
5326 _create.call( this );
5327 },
5328
5329 _setOption: function( key ) {
5330 if ( key === "autoHeight" || key === "clearStyle" || key === "fillSpace" ) {
5331 this.options.heightStyle = this._mergeHeightStyle();
5332 }
5333 _setOption.apply( this, arguments );
5334 },
5335
5336 _mergeHeightStyle: function() {
5337 var options = this.options;
5338
5339 if ( options.fillSpace ) {
5340 return "fill";
5341 }
5342
5343 if ( options.clearStyle ) {
5344 return "content";
5345 }
5346
5347 if ( options.autoHeight ) {
5348 return "auto";
5349 }
5350 }
5351 });
5352 }( jQuery, jQuery.ui.accordion.prototype ) );
5353
5354 // icon options
5355 (function( $, prototype ) {
5356 $.extend( prototype.options.icons, {
5357 activeHeader: null, // remove default so we fall back to old values
5358 headerSelected: "ui-icon-triangle-1-s"
5359 });
5360
5361 var _createIcons = prototype._createIcons;
5362 prototype._createIcons = function() {
5363 if ( this.options.icons ) {
5364 this.options.icons.activeHeader = this.options.icons.activeHeader ||
5365 this.options.icons.headerSelected;
5366 }
5367 _createIcons.call( this );
5368 };
5369 }( jQuery, jQuery.ui.accordion.prototype ) );
5370
5371 // expanded active option, activate method
5372 (function( $, prototype ) {
5373 prototype.activate = prototype._activate;
5374
5375 var _findActive = prototype._findActive;
5376 prototype._findActive = function( index ) {
5377 if ( index === -1 ) {
5378 index = false;
5379 }
5380 if ( index && typeof index !== "number" ) {
5381 index = this.headers.index( this.headers.filter( index ) );
5382 if ( index === -1 ) {
5383 index = false;
5384 }
5385 }
5386 return _findActive.call( this, index );
5387 };
5388 }( jQuery, jQuery.ui.accordion.prototype ) );
5389
5390 // resize method
5391 jQuery.ui.accordion.prototype.resize = jQuery.ui.accordion.prototype.refresh;
5392
5393 // change events
5394 (function( $, prototype ) {
5395 $.extend( prototype.options, {
5396 change: null,
5397 changestart: null
5398 });
5399
5400 var _trigger = prototype._trigger;
5401 prototype._trigger = function( type, event, data ) {
5402 var ret = _trigger.apply( this, arguments );
5403 if ( !ret ) {
5404 return false;
5405 }
5406
5407 if ( type === "beforeActivate" ) {
5408 ret = _trigger.call( this, "changestart", event, {
5409 oldHeader: data.oldHeader,
5410 oldContent: data.oldPanel,
5411 newHeader: data.newHeader,
5412 newContent: data.newPanel
5413 });
5414 } else if ( type === "activate" ) {
5415 ret = _trigger.call( this, "change", event, {
5416 oldHeader: data.oldHeader,
5417 oldContent: data.oldPanel,
5418 newHeader: data.newHeader,
5419 newContent: data.newPanel
5420 });
5421 }
5422 return ret;
5423 };
5424 }( jQuery, jQuery.ui.accordion.prototype ) );
5425
5426 // animated option
5427 // NOTE: this only provides support for "slide", "bounceslide", and easings
5428 // not the full $.ui.accordion.animations API
5429 (function( $, prototype ) {
5430 $.extend( prototype.options, {
5431 animate: null,
5432 animated: "slide"
5433 });
5434
5435 var _create = prototype._create;
5436 prototype._create = function() {
5437 var options = this.options;
5438 if ( options.animate === null ) {
5439 if ( !options.animated ) {
5440 options.animate = false;
5441 } else if ( options.animated === "slide" ) {
5442 options.animate = 300;
5443 } else if ( options.animated === "bounceslide" ) {
5444 options.animate = {
5445 duration: 200,
5446 down: {
5447 easing: "easeOutBounce",
5448 duration: 1000
5449 }
5450 };
5451 } else {
5452 options.animate = options.animated;
5453 }
5454 }
5455
5456 _create.call( this );
5457 };
5458 }( jQuery, jQuery.ui.accordion.prototype ) );
5459 }
5460
5461 })( jQuery );
5462 (function( $, undefined ) {
5463
5464 // used to prevent race conditions with remote data sources
5465 var requestIndex = 0;
5466
5467 $.widget( "ui.autocomplete", {
5468 version: "1.9.2",
5469 defaultElement: "<input>",
5470 options: {
5471 appendTo: "body",
5472 autoFocus: false,
5473 delay: 300,
5474 minLength: 1,
5475 position: {
5476 my: "left top",
5477 at: "left bottom",
5478 collision: "none"
5479 },
5480 source: null,
5481
5482 // callbacks
5483 change: null,
5484 close: null,
5485 focus: null,
5486 open: null,
5487 response: null,
5488 search: null,
5489 select: null
5490 },
5491
5492 pending: 0,
5493
5494 _create: function() {
5495 // Some browsers only repeat keydown events, not keypress events,
5496 // so we use the suppressKeyPress flag to determine if we've already
5497 // handled the keydown event. #7269
5498 // Unfortunately the code for & in keypress is the same as the up arrow,
5499 // so we use the suppressKeyPressRepeat flag to avoid handling keypress
5500 // events when we know the keydown event was used to modify the
5501 // search term. #7799
5502 var suppressKeyPress, suppressKeyPressRepeat, suppressInput;
5503
5504 this.isMultiLine = this._isMultiLine();
5505 this.valueMethod = this.element[ this.element.is( "input,textarea" ) ? "val" : "text" ];
5506 this.isNewMenu = true;
5507
5508 this.element
5509 .addClass( "ui-autocomplete-input" )
5510 .attr( "autocomplete", "off" );
5511
5512 this._on( this.element, {
5513 keydown: function( event ) {
5514 if ( this.element.prop( "readOnly" ) ) {
5515 suppressKeyPress = true;
5516 suppressInput = true;
5517 suppressKeyPressRepeat = true;
5518 return;
5519 }
5520
5521 suppressKeyPress = false;
5522 suppressInput = false;
5523 suppressKeyPressRepeat = false;
5524 var keyCode = $.ui.keyCode;
5525 switch( event.keyCode ) {
5526 case keyCode.PAGE_UP:
5527 suppressKeyPress = true;
5528 this._move( "previousPage", event );
5529 break;
5530 case keyCode.PAGE_DOWN:
5531 suppressKeyPress = true;
5532 this._move( "nextPage", event );
5533 break;
5534 case keyCode.UP:
5535 suppressKeyPress = true;
5536 this._keyEvent( "previous", event );
5537 break;
5538 case keyCode.DOWN:
5539 suppressKeyPress = true;
5540 this._keyEvent( "next", event );
5541 break;
5542 case keyCode.ENTER:
5543 case keyCode.NUMPAD_ENTER:
5544 // when menu is open and has focus
5545 if ( this.menu.active ) {
5546 // #6055 - Opera still allows the keypress to occur
5547 // which causes forms to submit
5548 suppressKeyPress = true;
5549 event.preventDefault();
5550 this.menu.select( event );
5551 }
5552 break;
5553 case keyCode.TAB:
5554 if ( this.menu.active ) {
5555 this.menu.select( event );
5556 }
5557 break;
5558 case keyCode.ESCAPE:
5559 if ( this.menu.element.is( ":visible" ) ) {
5560 this._value( this.term );
5561 this.close( event );
5562 // Different browsers have different default behavior for escape
5563 // Single press can mean undo or clear
5564 // Double press in IE means clear the whole form
5565 event.preventDefault();
5566 }
5567 break;
5568 default:
5569 suppressKeyPressRepeat = true;
5570 // search timeout should be triggered before the input value is changed
5571 this._searchTimeout( event );
5572 break;
5573 }
5574 },
5575 keypress: function( event ) {
5576 if ( suppressKeyPress ) {
5577 suppressKeyPress = false;
5578 event.preventDefault();
5579 return;
5580 }
5581 if ( suppressKeyPressRepeat ) {
5582 return;
5583 }
5584
5585 // replicate some key handlers to allow them to repeat in Firefox and Opera
5586 var keyCode = $.ui.keyCode;
5587 switch( event.keyCode ) {
5588 case keyCode.PAGE_UP:
5589 this._move( "previousPage", event );
5590 break;
5591 case keyCode.PAGE_DOWN:
5592 this._move( "nextPage", event );
5593 break;
5594 case keyCode.UP:
5595 this._keyEvent( "previous", event );
5596 break;
5597 case keyCode.DOWN:
5598 this._keyEvent( "next", event );
5599 break;
5600 }
5601 },
5602 input: function( event ) {
5603 if ( suppressInput ) {
5604 suppressInput = false;
5605 event.preventDefault();
5606 return;
5607 }
5608 this._searchTimeout( event );
5609 },
5610 focus: function() {
5611 this.selectedItem = null;
5612 this.previous = this._value();
5613 },
5614 blur: function( event ) {
5615 if ( this.cancelBlur ) {
5616 delete this.cancelBlur;
5617 return;
5618 }
5619
5620 clearTimeout( this.searching );
5621 this.close( event );
5622 this._change( event );
5623 }
5624 });
5625
5626 this._initSource();
5627 this.menu = $( "<ul>" )
5628 .addClass( "ui-autocomplete" )
5629 .appendTo( this.document.find( this.options.appendTo || "body" )[ 0 ] )
5630 .menu({
5631 // custom key handling for now
5632 input: $(),
5633 // disable ARIA support, the live region takes care of that
5634 role: null
5635 })
5636 .zIndex( this.element.zIndex() + 1 )
5637 .hide()
5638 .data( "menu" );
5639
5640 this._on( this.menu.element, {
5641 mousedown: function( event ) {
5642 // prevent moving focus out of the text field
5643 event.preventDefault();
5644
5645 // IE doesn't prevent moving focus even with event.preventDefault()
5646 // so we set a flag to know when we should ignore the blur event
5647 this.cancelBlur = true;
5648 this._delay(function() {
5649 delete this.cancelBlur;
5650 });
5651
5652 // clicking on the scrollbar causes focus to shift to the body
5653 // but we can't detect a mouseup or a click immediately afterward
5654 // so we have to track the next mousedown and close the menu if
5655 // the user clicks somewhere outside of the autocomplete
5656 var menuElement = this.menu.element[ 0 ];
5657 if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
5658 this._delay(function() {
5659 var that = this;
5660 this.document.one( "mousedown", function( event ) {
5661 if ( event.target !== that.element[ 0 ] &&
5662 event.target !== menuElement &&
5663 !$.contains( menuElement, event.target ) ) {
5664 that.close();
5665 }
5666 });
5667 });
5668 }
5669 },
5670 menufocus: function( event, ui ) {
5671 // #7024 - Prevent accidental activation of menu items in Firefox
5672 if ( this.isNewMenu ) {
5673 this.isNewMenu = false;
5674 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
5675 this.menu.blur();
5676
5677 this.document.one( "mousemove", function() {
5678 $( event.target ).trigger( event.originalEvent );
5679 });
5680
5681 return;
5682 }
5683 }
5684
5685 // back compat for _renderItem using item.autocomplete, via #7810
5686 // TODO remove the fallback, see #8156
5687 var item = ui.item.data( "ui-autocomplete-item" ) || ui.item.data( "item.autocomplete" );
5688 if ( false !== this._trigger( "focus", event, { item: item } ) ) {
5689 // use value to match what will end up in the input, if it was a key event
5690 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
5691 this._value( item.value );
5692 }
5693 } else {
5694 // Normally the input is populated with the item's value as the
5695 // menu is navigated, causing screen readers to notice a change and
5696 // announce the item. Since the focus event was canceled, this doesn't
5697 // happen, so we update the live region so that screen readers can
5698 // still notice the change and announce it.
5699 this.liveRegion.text( item.value );
5700 }
5701 },
5702 menuselect: function( event, ui ) {
5703 // back compat for _renderItem using item.autocomplete, via #7810
5704 // TODO remove the fallback, see #8156
5705 var item = ui.item.data( "ui-autocomplete-item" ) || ui.item.data( "item.autocomplete" ),
5706 previous = this.previous;
5707
5708 // only trigger when focus was lost (click on menu)
5709 if ( this.element[0] !== this.document[0].activeElement ) {
5710 this.element.focus();
5711 this.previous = previous;
5712 // #6109 - IE triggers two focus events and the second
5713 // is asynchronous, so we need to reset the previous
5714 // term synchronously and asynchronously :-(
5715 this._delay(function() {
5716 this.previous = previous;
5717 this.selectedItem = item;
5718 });
5719 }
5720
5721 if ( false !== this._trigger( "select", event, { item: item } ) ) {
5722 this._value( item.value );
5723 }
5724 // reset the term after the select event
5725 // this allows custom select handling to work properly
5726 this.term = this._value();
5727
5728 this.close( event );
5729 this.selectedItem = item;
5730 }
5731 });
5732
5733 this.liveRegion = $( "<span>", {
5734 role: "status",
5735 "aria-live": "polite"
5736 })
5737 .addClass( "ui-helper-hidden-accessible" )
5738 .insertAfter( this.element );
5739
5740 if ( $.fn.bgiframe ) {
5741 this.menu.element.bgiframe();
5742 }
5743
5744 // turning off autocomplete prevents the browser from remembering the
5745 // value when navigating through history, so we re-enable autocomplete
5746 // if the page is unloaded before the widget is destroyed. #7790
5747 this._on( this.window, {
5748 beforeunload: function() {
5749 this.element.removeAttr( "autocomplete" );
5750 }
5751 });
5752 },
5753
5754 _destroy: function() {
5755 clearTimeout( this.searching );
5756 this.element
5757 .removeClass( "ui-autocomplete-input" )
5758 .removeAttr( "autocomplete" );
5759 this.menu.element.remove();
5760 this.liveRegion.remove();
5761 },
5762
5763 _setOption: function( key, value ) {
5764 this._super( key, value );
5765 if ( key === "source" ) {
5766 this._initSource();
5767 }
5768 if ( key === "appendTo" ) {
5769 this.menu.element.appendTo( this.document.find( value || "body" )[0] );
5770 }
5771 if ( key === "disabled" && value && this.xhr ) {
5772 this.xhr.abort();
5773 }
5774 },
5775
5776 _isMultiLine: function() {
5777 // Textareas are always multi-line
5778 if ( this.element.is( "textarea" ) ) {
5779 return true;
5780 }
5781 // Inputs are always single-line, even if inside a contentEditable element
5782 // IE also treats inputs as contentEditable
5783 if ( this.element.is( "input" ) ) {
5784 return false;
5785 }
5786 // All other element types are determined by whether or not they're contentEditable
5787 return this.element.prop( "isContentEditable" );
5788 },
5789
5790 _initSource: function() {
5791 var array, url,
5792 that = this;
5793 if ( $.isArray(this.options.source) ) {
5794 array = this.options.source;
5795 this.source = function( request, response ) {
5796 response( $.ui.autocomplete.filter( array, request.term ) );
5797 };
5798 } else if ( typeof this.options.source === "string" ) {
5799 url = this.options.source;
5800 this.source = function( request, response ) {
5801 if ( that.xhr ) {
5802 that.xhr.abort();
5803 }
5804 that.xhr = $.ajax({
5805 url: url,
5806 data: request,
5807 dataType: "json",
5808 success: function( data ) {
5809 response( data );
5810 },
5811 error: function() {
5812 response( [] );
5813 }
5814 });
5815 };
5816 } else {
5817 this.source = this.options.source;
5818 }
5819 },
5820
5821 _searchTimeout: function( event ) {
5822 clearTimeout( this.searching );
5823 this.searching = this._delay(function() {
5824 // only search if the value has changed
5825 if ( this.term !== this._value() ) {
5826 this.selectedItem = null;
5827 this.search( null, event );
5828 }
5829 }, this.options.delay );
5830 },
5831
5832 search: function( value, event ) {
5833 value = value != null ? value : this._value();
5834
5835 // always save the actual value, not the one passed as an argument
5836 this.term = this._value();
5837
5838 if ( value.length < this.options.minLength ) {
5839 return this.close( event );
5840 }
5841
5842 if ( this._trigger( "search", event ) === false ) {
5843 return;
5844 }
5845
5846 return this._search( value );
5847 },
5848
5849 _search: function( value ) {
5850 this.pending++;
5851 this.element.addClass( "ui-autocomplete-loading" );
5852 this.cancelSearch = false;
5853
5854 this.source( { term: value }, this._response() );
5855 },
5856
5857 _response: function() {
5858 var that = this,
5859 index = ++requestIndex;
5860
5861 return function( content ) {
5862 if ( index === requestIndex ) {
5863 that.__response( content );
5864 }
5865
5866 that.pending--;
5867 if ( !that.pending ) {
5868 that.element.removeClass( "ui-autocomplete-loading" );
5869 }
5870 };
5871 },
5872
5873 __response: function( content ) {
5874 if ( content ) {
5875 content = this._normalize( content );
5876 }
5877 this._trigger( "response", null, { content: content } );
5878 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
5879 this._suggest( content );
5880 this._trigger( "open" );
5881 } else {
5882 // use ._close() instead of .close() so we don't cancel future searches
5883 this._close();
5884 }
5885 },
5886
5887 close: function( event ) {
5888 this.cancelSearch = true;
5889 this._close( event );
5890 },
5891
5892 _close: function( event ) {
5893 if ( this.menu.element.is( ":visible" ) ) {
5894 this.menu.element.hide();
5895 this.menu.blur();
5896 this.isNewMenu = true;
5897 this._trigger( "close", event );
5898 }
5899 },
5900
5901 _change: function( event ) {
5902 if ( this.previous !== this._value() ) {
5903 this._trigger( "change", event, { item: this.selectedItem } );
5904 }
5905 },
5906
5907 _normalize: function( items ) {
5908 // assume all items have the right format when the first item is complete
5909 if ( items.length && items[0].label && items[0].value ) {
5910 return items;
5911 }
5912 return $.map( items, function( item ) {
5913 if ( typeof item === "string" ) {
5914 return {
5915 label: item,
5916 value: item
5917 };
5918 }
5919 return $.extend({
5920 label: item.label || item.value,
5921 value: item.value || item.label
5922 }, item );
5923 });
5924 },
5925
5926 _suggest: function( items ) {
5927 var ul = this.menu.element
5928 .empty()
5929 .zIndex( this.element.zIndex() + 1 );
5930 this._renderMenu( ul, items );
5931 this.menu.refresh();
5932
5933 // size and position menu
5934 ul.show();
5935 this._resizeMenu();
5936 ul.position( $.extend({
5937 of: this.element
5938 }, this.options.position ));
5939
5940 if ( this.options.autoFocus ) {
5941 this.menu.next();
5942 }
5943 },
5944
5945 _resizeMenu: function() {
5946 var ul = this.menu.element;
5947 ul.outerWidth( Math.max(
5948 // Firefox wraps long text (possibly a rounding bug)
5949 // so we add 1px to avoid the wrapping (#7513)
5950 ul.width( "" ).outerWidth() + 1,
5951 this.element.outerWidth()
5952 ) );
5953 },
5954
5955 _renderMenu: function( ul, items ) {
5956 var that = this;
5957 $.each( items, function( index, item ) {
5958 that._renderItemData( ul, item );
5959 });
5960 },
5961
5962 _renderItemData: function( ul, item ) {
5963 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
5964 },
5965
5966 _renderItem: function( ul, item ) {
5967 return $( "<li>" )
5968 .append( $( "<a>" ).text( item.label ) )
5969 .appendTo( ul );
5970 },
5971
5972 _move: function( direction, event ) {
5973 if ( !this.menu.element.is( ":visible" ) ) {
5974 this.search( null, event );
5975 return;
5976 }
5977 if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
5978 this.menu.isLastItem() && /^next/.test( direction ) ) {
5979 this._value( this.term );
5980 this.menu.blur();
5981 return;
5982 }
5983 this.menu[ direction ]( event );
5984 },
5985
5986 widget: function() {
5987 return this.menu.element;
5988 },
5989
5990 _value: function() {
5991 return this.valueMethod.apply( this.element, arguments );
5992 },
5993
5994 _keyEvent: function( keyEvent, event ) {
5995 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
5996 this._move( keyEvent, event );
5997
5998 // prevents moving cursor to beginning/end of the text field in some browsers
5999 event.preventDefault();
6000 }
6001 }
6002 });
6003
6004 $.extend( $.ui.autocomplete, {
6005 escapeRegex: function( value ) {
6006 return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
6007 },
6008 filter: function(array, term) {
6009 var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
6010 return $.grep( array, function(value) {
6011 return matcher.test( value.label || value.value || value );
6012 });
6013 }
6014 });
6015
6016
6017 // live region extension, adding a `messages` option
6018 // NOTE: This is an experimental API. We are still investigating
6019 // a full solution for string manipulation and internationalization.
6020 $.widget( "ui.autocomplete", $.ui.autocomplete, {
6021 options: {
6022 messages: {
6023 noResults: "No search results.",
6024 results: function( amount ) {
6025 return amount + ( amount > 1 ? " results are" : " result is" ) +
6026 " available, use up and down arrow keys to navigate.";
6027 }
6028 }
6029 },
6030
6031 __response: function( content ) {
6032 var message;
6033 this._superApply( arguments );
6034 if ( this.options.disabled || this.cancelSearch ) {
6035 return;
6036 }
6037 if ( content && content.length ) {
6038 message = this.options.messages.results( content.length );
6039 } else {
6040 message = this.options.messages.noResults;
6041 }
6042 this.liveRegion.text( message );
6043 }
6044 });
6045
6046
6047 }( jQuery ));
6048 (function( $, undefined ) {
6049
6050 var lastActive, startXPos, startYPos, clickDragged,
6051 baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
6052 stateClasses = "ui-state-hover ui-state-active ",
6053 typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",
6054 formResetHandler = function() {
6055 var buttons = $( this ).find( ":ui-button" );
6056 setTimeout(function() {
6057 buttons.button( "refresh" );
6058 }, 1 );
6059 },
6060 radioGroup = function( radio ) {
6061 var name = radio.name,
6062 form = radio.form,
6063 radios = $( [] );
6064 if ( name ) {
6065 if ( form ) {
6066 radios = $( form ).find( "[name='" + name + "']" );
6067 } else {
6068 radios = $( "[name='" + name + "']", radio.ownerDocument )
6069 .filter(function() {
6070 return !this.form;
6071 });
6072 }
6073 }
6074 return radios;
6075 };
6076
6077 $.widget( "ui.button", {
6078 version: "1.9.2",
6079 defaultElement: "<button>",
6080 options: {
6081 disabled: null,
6082 text: true,
6083 label: null,
6084 icons: {
6085 primary: null,
6086 secondary: null
6087 }
6088 },
6089 _create: function() {
6090 this.element.closest( "form" )
6091 .unbind( "reset" + this.eventNamespace )
6092 .bind( "reset" + this.eventNamespace, formResetHandler );
6093
6094 if ( typeof this.options.disabled !== "boolean" ) {
6095 this.options.disabled = !!this.element.prop( "disabled" );
6096 } else {
6097 this.element.prop( "disabled", this.options.disabled );
6098 }
6099
6100 this._determineButtonType();
6101 this.hasTitle = !!this.buttonElement.attr( "title" );
6102
6103 var that = this,
6104 options = this.options,
6105 toggleButton = this.type === "checkbox" || this.type === "radio",
6106 activeClass = !toggleButton ? "ui-state-active" : "",
6107 focusClass = "ui-state-focus";
6108
6109 if ( options.label === null ) {
6110 options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html());
6111 }
6112
6113 this._hoverable( this.buttonElement );
6114
6115 this.buttonElement
6116 .addClass( baseClasses )
6117 .attr( "role", "button" )
6118 .bind( "mouseenter" + this.eventNamespace, function() {
6119 if ( options.disabled ) {
6120 return;
6121 }
6122 if ( this === lastActive ) {
6123 $( this ).addClass( "ui-state-active" );
6124 }
6125 })
6126 .bind( "mouseleave" + this.eventNamespace, function() {
6127 if ( options.disabled ) {
6128 return;
6129 }
6130 $( this ).removeClass( activeClass );
6131 })
6132 .bind( "click" + this.eventNamespace, function( event ) {
6133 if ( options.disabled ) {
6134 event.preventDefault();
6135 event.stopImmediatePropagation();
6136 }
6137 });
6138
6139 this.element
6140 .bind( "focus" + this.eventNamespace, function() {
6141 // no need to check disabled, focus won't be triggered anyway
6142 that.buttonElement.addClass( focusClass );
6143 })
6144 .bind( "blur" + this.eventNamespace, function() {
6145 that.buttonElement.removeClass( focusClass );
6146 });
6147
6148 if ( toggleButton ) {
6149 this.element.bind( "change" + this.eventNamespace, function() {
6150 if ( clickDragged ) {
6151 return;
6152 }
6153 that.refresh();
6154 });
6155 // if mouse moves between mousedown and mouseup (drag) set clickDragged flag
6156 // prevents issue where button state changes but checkbox/radio checked state
6157 // does not in Firefox (see ticket #6970)
6158 this.buttonElement
6159 .bind( "mousedown" + this.eventNamespace, function( event ) {
6160 if ( options.disabled ) {
6161 return;
6162 }
6163 clickDragged = false;
6164 startXPos = event.pageX;
6165 startYPos = event.pageY;
6166 })
6167 .bind( "mouseup" + this.eventNamespace, function( event ) {
6168 if ( options.disabled ) {
6169 return;
6170 }
6171 if ( startXPos !== event.pageX || startYPos !== event.pageY ) {
6172 clickDragged = true;
6173 }
6174 });
6175 }
6176
6177 if ( this.type === "checkbox" ) {
6178 this.buttonElement.bind( "click" + this.eventNamespace, function() {
6179 if ( options.disabled || clickDragged ) {
6180 return false;
6181 }
6182 $( this ).toggleClass( "ui-state-active" );
6183 that.buttonElement.attr( "aria-pressed", that.element[0].checked );
6184 });
6185 } else if ( this.type === "radio" ) {
6186 this.buttonElement.bind( "click" + this.eventNamespace, function() {
6187 if ( options.disabled || clickDragged ) {
6188 return false;
6189 }
6190 $( this ).addClass( "ui-state-active" );
6191 that.buttonElement.attr( "aria-pressed", "true" );
6192
6193 var radio = that.element[ 0 ];
6194 radioGroup( radio )
6195 .not( radio )
6196 .map(function() {
6197 return $( this ).button( "widget" )[ 0 ];
6198 })
6199 .removeClass( "ui-state-active" )
6200 .attr( "aria-pressed", "false" );
6201 });
6202 } else {
6203 this.buttonElement
6204 .bind( "mousedown" + this.eventNamespace, function() {
6205 if ( options.disabled ) {
6206 return false;
6207 }
6208 $( this ).addClass( "ui-state-active" );
6209 lastActive = this;
6210 that.document.one( "mouseup", function() {
6211 lastActive = null;
6212 });
6213 })
6214 .bind( "mouseup" + this.eventNamespace, function() {
6215 if ( options.disabled ) {
6216 return false;
6217 }
6218 $( this ).removeClass( "ui-state-active" );
6219 })
6220 .bind( "keydown" + this.eventNamespace, function(event) {
6221 if ( options.disabled ) {
6222 return false;
6223 }
6224 if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) {
6225 $( this ).addClass( "ui-state-active" );
6226 }
6227 })
6228 .bind( "keyup" + this.eventNamespace, function() {
6229 $( this ).removeClass( "ui-state-active" );
6230 });
6231
6232 if ( this.buttonElement.is("a") ) {
6233 this.buttonElement.keyup(function(event) {
6234 if ( event.keyCode === $.ui.keyCode.SPACE ) {
6235 // TODO pass through original event correctly (just as 2nd argument doesn't work)
6236 $( this ).click();
6237 }
6238 });
6239 }
6240 }
6241
6242 // TODO: pull out $.Widget's handling for the disabled option into
6243 // $.Widget.prototype._setOptionDisabled so it's easy to proxy and can
6244 // be overridden by individual plugins
6245 this._setOption( "disabled", options.disabled );
6246 this._resetButton();
6247 },
6248
6249 _determineButtonType: function() {
6250 var ancestor, labelSelector, checked;
6251
6252 if ( this.element.is("[type=checkbox]") ) {
6253 this.type = "checkbox";
6254 } else if ( this.element.is("[type=radio]") ) {
6255 this.type = "radio";
6256 } else if ( this.element.is("input") ) {
6257 this.type = "input";
6258 } else {
6259 this.type = "button";
6260 }
6261
6262 if ( this.type === "checkbox" || this.type === "radio" ) {
6263 // we don't search against the document in case the element
6264 // is disconnected from the DOM
6265 ancestor = this.element.parents().last();
6266 labelSelector = "label[for='" + this.element.attr("id") + "']";
6267 this.buttonElement = ancestor.find( labelSelector );
6268 if ( !this.buttonElement.length ) {
6269 ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
6270 this.buttonElement = ancestor.filter( labelSelector );
6271 if ( !this.buttonElement.length ) {
6272 this.buttonElement = ancestor.find( labelSelector );
6273 }
6274 }
6275 this.element.addClass( "ui-helper-hidden-accessible" );
6276
6277 checked = this.element.is( ":checked" );
6278 if ( checked ) {
6279 this.buttonElement.addClass( "ui-state-active" );
6280 }
6281 this.buttonElement.prop( "aria-pressed", checked );
6282 } else {
6283 this.buttonElement = this.element;
6284 }
6285 },
6286
6287 widget: function() {
6288 return this.buttonElement;
6289 },
6290
6291 _destroy: function() {
6292 this.element
6293 .removeClass( "ui-helper-hidden-accessible" );
6294 this.buttonElement
6295 .removeClass( baseClasses + " " + stateClasses + " " + typeClasses )
6296 .removeAttr( "role" )
6297 .removeAttr( "aria-pressed" )
6298 .html( this.buttonElement.find(".ui-button-text").html() );
6299
6300 if ( !this.hasTitle ) {
6301 this.buttonElement.removeAttr( "title" );
6302 }
6303 },
6304
6305 _setOption: function( key, value ) {
6306 this._super( key, value );
6307 if ( key === "disabled" ) {
6308 if ( value ) {
6309 this.element.prop( "disabled", true );
6310 } else {
6311 this.element.prop( "disabled", false );
6312 }
6313 return;
6314 }
6315 this._resetButton();
6316 },
6317
6318 refresh: function() {
6319 //See #8237 & #8828
6320 var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" );
6321
6322 if ( isDisabled !== this.options.disabled ) {
6323 this._setOption( "disabled", isDisabled );
6324 }
6325 if ( this.type === "radio" ) {
6326 radioGroup( this.element[0] ).each(function() {
6327 if ( $( this ).is( ":checked" ) ) {
6328 $( this ).button( "widget" )
6329 .addClass( "ui-state-active" )
6330 .attr( "aria-pressed", "true" );
6331 } else {
6332 $( this ).button( "widget" )
6333 .removeClass( "ui-state-active" )
6334 .attr( "aria-pressed", "false" );
6335 }
6336 });
6337 } else if ( this.type === "checkbox" ) {
6338 if ( this.element.is( ":checked" ) ) {
6339 this.buttonElement
6340 .addClass( "ui-state-active" )
6341 .attr( "aria-pressed", "true" );
6342 } else {
6343 this.buttonElement
6344 .removeClass( "ui-state-active" )
6345 .attr( "aria-pressed", "false" );
6346 }
6347 }
6348 },
6349
6350 _resetButton: function() {
6351 if ( this.type === "input" ) {
6352 if ( this.options.label ) {
6353 this.element.val( this.options.label );
6354 }
6355 return;
6356 }
6357 var buttonElement = this.buttonElement.removeClass( typeClasses ),
6358 buttonText = $( "<span></span>", this.document[0] )
6359 .addClass( "ui-button-text" )
6360 .html( this.options.label )
6361 .appendTo( buttonElement.empty() )
6362 .text(),
6363 icons = this.options.icons,
6364 multipleIcons = icons.primary && icons.secondary,
6365 buttonClasses = [];
6366
6367 if ( icons.primary || icons.secondary ) {
6368 if ( this.options.text ) {
6369 buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
6370 }
6371
6372 if ( icons.primary ) {
6373 buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
6374 }
6375
6376 if ( icons.secondary ) {
6377 buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
6378 }
6379
6380 if ( !this.options.text ) {
6381 buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );
6382
6383 if ( !this.hasTitle ) {
6384 buttonElement.attr( "title", $.trim( buttonText ) );
6385 }
6386 }
6387 } else {
6388 buttonClasses.push( "ui-button-text-only" );
6389 }
6390 buttonElement.addClass( buttonClasses.join( " " ) );
6391 }
6392 });
6393
6394 $.widget( "ui.buttonset", {
6395 version: "1.9.2",
6396 options: {
6397 items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(button)"
6398 },
6399
6400 _create: function() {
6401 this.element.addClass( "ui-buttonset" );
6402 },
6403
6404 _init: function() {
6405 this.refresh();
6406 },
6407
6408 _setOption: function( key, value ) {
6409 if ( key === "disabled" ) {
6410 this.buttons.button( "option", key, value );
6411 }
6412
6413 this._super( key, value );
6414 },
6415
6416 refresh: function() {
6417 var rtl = this.element.css( "direction" ) === "rtl";
6418
6419 this.buttons = this.element.find( this.options.items )
6420 .filter( ":ui-button" )
6421 .button( "refresh" )
6422 .end()
6423 .not( ":ui-button" )
6424 .button()
6425 .end()
6426 .map(function() {
6427 return $( this ).button( "widget" )[ 0 ];
6428 })
6429 .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
6430 .filter( ":first" )
6431 .addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
6432 .end()
6433 .filter( ":last" )
6434 .addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
6435 .end()
6436 .end();
6437 },
6438
6439 _destroy: function() {
6440 this.element.removeClass( "ui-buttonset" );
6441 this.buttons
6442 .map(function() {
6443 return $( this ).button( "widget" )[ 0 ];
6444 })
6445 .removeClass( "ui-corner-left ui-corner-right" )
6446 .end()
6447 .button( "destroy" );
6448 }
6449 });
6450
6451 }( jQuery ) );
6452 (function( $, undefined ) {
6453
6454 $.extend($.ui, { datepicker: { version: "1.9.2" } });
6455
6456 var PROP_NAME = 'datepicker';
6457 var dpuuid = new Date().getTime();
6458 var instActive;
6459
6460 /* Date picker manager.
6461 Use the singleton instance of this class, $.datepicker, to interact with the date picker.
6462 Settings for (groups of) date pickers are maintained in an instance object,
6463 allowing multiple different settings on the same page. */
6464
6465 function Datepicker() {
6466 this.debug = false; // Change this to true to start debugging
6467 this._curInst = null; // The current instance in use
6468 this._keyEvent = false; // If the last event was a key event
6469 this._disabledInputs = []; // List of date picker inputs that have been disabled
6470 this._datepickerShowing = false; // True if the popup picker is showing , false if not
6471 this._inDialog = false; // True if showing within a "dialog", false if not
6472 this._mainDivId = 'ui-datepicker-div'; // The ID of the main datepicker division
6473 this._inlineClass = 'ui-datepicker-inline'; // The name of the inline marker class
6474 this._appendClass = 'ui-datepicker-append'; // The name of the append marker class
6475 this._triggerClass = 'ui-datepicker-trigger'; // The name of the trigger marker class
6476 this._dialogClass = 'ui-datepicker-dialog'; // The name of the dialog marker class
6477 this._disableClass = 'ui-datepicker-disabled'; // The name of the disabled covering marker class
6478 this._unselectableClass = 'ui-datepicker-unselectable'; // The name of the unselectable cell marker class
6479 this._currentClass = 'ui-datepicker-current-day'; // The name of the current day marker class
6480 this._dayOverClass = 'ui-datepicker-days-cell-over'; // The name of the day hover marker class
6481 this.regional = []; // Available regional settings, indexed by language code
6482 this.regional[''] = { // Default regional settings
6483 closeText: 'Done', // Display text for close link
6484 prevText: 'Prev', // Display text for previous month link
6485 nextText: 'Next', // Display text for next month link
6486 currentText: 'Today', // Display text for current month link
6487 monthNames: ['January','February','March','April','May','June',
6488 'July','August','September','October','November','December'], // Names of months for drop-down and formatting
6489 monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting
6490 dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting
6491 dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting
6492 dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday
6493 weekHeader: 'Wk', // Column header for week of the year
6494 dateFormat: 'mm/dd/yy', // See format options on parseDate
6495 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
6496 isRTL: false, // True if right-to-left language, false if left-to-right
6497 showMonthAfterYear: false, // True if the year select precedes month, false for month then year
6498 yearSuffix: '' // Additional text to append to the year in the month headers
6499 };
6500 this._defaults = { // Global defaults for all the date picker instances
6501 showOn: 'focus', // 'focus' for popup on focus,
6502 // 'button' for trigger button, or 'both' for either
6503 showAnim: 'fadeIn', // Name of jQuery animation for popup
6504 showOptions: {}, // Options for enhanced animations
6505 defaultDate: null, // Used when field is blank: actual date,
6506 // +/-number for offset from today, null for today
6507 appendText: '', // Display text following the input box, e.g. showing the format
6508 buttonText: '...', // Text for trigger button
6509 buttonImage: '', // URL for trigger button image
6510 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
6511 hideIfNoPrevNext: false, // True to hide next/previous month links
6512 // if not applicable, false to just disable them
6513 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
6514 gotoCurrent: false, // True if today link goes back to current selection instead
6515 changeMonth: false, // True if month can be selected directly, false if only prev/next
6516 changeYear: false, // True if year can be selected directly, false if only prev/next
6517 yearRange: 'c-10:c+10', // Range of years to display in drop-down,
6518 // either relative to today's year (-nn:+nn), relative to currently displayed year
6519 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
6520 showOtherMonths: false, // True to show dates in other months, false to leave blank
6521 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
6522 showWeek: false, // True to show week of the year, false to not show it
6523 calculateWeek: this.iso8601Week, // How to calculate the week of the year,
6524 // takes a Date and returns the number of the week for it
6525 shortYearCutoff: '+10', // Short year values < this are in the current century,
6526 // > this are in the previous century,
6527 // string value starting with '+' for current year + value
6528 minDate: null, // The earliest selectable date, or null for no limit
6529 maxDate: null, // The latest selectable date, or null for no limit
6530 duration: 'fast', // Duration of display/closure
6531 beforeShowDay: null, // Function that takes a date and returns an array with
6532 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '',
6533 // [2] = cell title (optional), e.g. $.datepicker.noWeekends
6534 beforeShow: null, // Function that takes an input field and
6535 // returns a set of custom settings for the date picker
6536 onSelect: null, // Define a callback function when a date is selected
6537 onChangeMonthYear: null, // Define a callback function when the month or year is changed
6538 onClose: null, // Define a callback function when the datepicker is closed
6539 numberOfMonths: 1, // Number of months to show at a time
6540 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
6541 stepMonths: 1, // Number of months to step back/forward
6542 stepBigMonths: 12, // Number of months to step back/forward for the big links
6543 altField: '', // Selector for an alternate field to store selected dates into
6544 altFormat: '', // The date format to use for the alternate field
6545 constrainInput: true, // The input is constrained by the current date format
6546 showButtonPanel: false, // True to show button panel, false to not show it
6547 autoSize: false, // True to size the input for the date format, false to leave as is
6548 disabled: false // The initial disabled state
6549 };
6550 $.extend(this._defaults, this.regional['']);
6551 this.dpDiv = bindHover($('<div id="' + this._mainDivId + '" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'));
6552 }
6553
6554 $.extend(Datepicker.prototype, {
6555 /* Class name added to elements to indicate already configured with a date picker. */
6556 markerClassName: 'hasDatepicker',
6557
6558 //Keep track of the maximum number of rows displayed (see #7043)
6559 maxRows: 4,
6560
6561 /* Debug logging (if enabled). */
6562 log: function () {
6563 if (this.debug)
6564 console.log.apply('', arguments);
6565 },
6566
6567 // TODO rename to "widget" when switching to widget factory
6568 _widgetDatepicker: function() {
6569 return this.dpDiv;
6570 },
6571
6572 /* Override the default settings for all instances of the date picker.
6573 @param settings object - the new settings to use as defaults (anonymous object)
6574 @return the manager object */
6575 setDefaults: function(settings) {
6576 extendRemove(this._defaults, settings || {});
6577 return this;
6578 },
6579
6580 /* Attach the date picker to a jQuery selection.
6581 @param target element - the target input field or division or span
6582 @param settings object - the new settings to use for this date picker instance (anonymous) */
6583 _attachDatepicker: function(target, settings) {
6584 // check for settings on the control itself - in namespace 'date:'
6585 var inlineSettings = null;
6586 for (var attrName in this._defaults) {
6587 var attrValue = target.getAttribute('date:' + attrName);
6588 if (attrValue) {
6589 inlineSettings = inlineSettings || {};
6590 try {
6591 inlineSettings[attrName] = eval(attrValue);
6592 } catch (err) {
6593 inlineSettings[attrName] = attrValue;
6594 }
6595 }
6596 }
6597 var nodeName = target.nodeName.toLowerCase();
6598 var inline = (nodeName == 'div' || nodeName == 'span');
6599 if (!target.id) {
6600 this.uuid += 1;
6601 target.id = 'dp' + this.uuid;
6602 }
6603 var inst = this._newInst($(target), inline);
6604 inst.settings = $.extend({}, settings || {}, inlineSettings || {});
6605 if (nodeName == 'input') {
6606 this._connectDatepicker(target, inst);
6607 } else if (inline) {
6608 this._inlineDatepicker(target, inst);
6609 }
6610 },
6611
6612 /* Create a new instance object. */
6613 _newInst: function(target, inline) {
6614 var id = target[0].id.replace(/([^A-Za-z0-9_-])/g, '\\\\$1'); // escape jQuery meta chars
6615 return {id: id, input: target, // associated target
6616 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
6617 drawMonth: 0, drawYear: 0, // month being drawn
6618 inline: inline, // is datepicker inline or not
6619 dpDiv: (!inline ? this.dpDiv : // presentation div
6620 bindHover($('<div class="' + this._inlineClass + ' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')))};
6621 },
6622
6623 /* Attach the date picker to an input field. */
6624 _connectDatepicker: function(target, inst) {
6625 var input = $(target);
6626 inst.append = $([]);
6627 inst.trigger = $([]);
6628 if (input.hasClass(this.markerClassName))
6629 return;
6630 this._attachments(input, inst);
6631 input.addClass(this.markerClassName).keydown(this._doKeyDown).
6632 keypress(this._doKeyPress).keyup(this._doKeyUp).
6633 bind("setData.datepicker", function(event, key, value) {
6634 inst.settings[key] = value;
6635 }).bind("getData.datepicker", function(event, key) {
6636 return this._get(inst, key);
6637 });
6638 this._autoSize(inst);
6639 $.data(target, PROP_NAME, inst);
6640 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
6641 if( inst.settings.disabled ) {
6642 this._disableDatepicker( target );
6643 }
6644 },
6645
6646 /* Make attachments based on settings. */
6647 _attachments: function(input, inst) {
6648 var appendText = this._get(inst, 'appendText');
6649 var isRTL = this._get(inst, 'isRTL');
6650 if (inst.append)
6651 inst.append.remove();
6652 if (appendText) {
6653 inst.append = $('<span class="' + this._appendClass + '">' + appendText + '</span>');
6654 input[isRTL ? 'before' : 'after'](inst.append);
6655 }
6656 input.unbind('focus', this._showDatepicker);
6657 if (inst.trigger)
6658 inst.trigger.remove();
6659 var showOn = this._get(inst, 'showOn');
6660 if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field
6661 input.focus(this._showDatepicker);
6662 if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked
6663 var buttonText = this._get(inst, 'buttonText');
6664 var buttonImage = this._get(inst, 'buttonImage');
6665 inst.trigger = $(this._get(inst, 'buttonImageOnly') ?
6666 $('<img/>').addClass(this._triggerClass).
6667 attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
6668 $('<button type="button"></button>').addClass(this._triggerClass).
6669 html(buttonImage == '' ? buttonText : $('<img/>').attr(
6670 { src:buttonImage, alt:buttonText, title:buttonText })));
6671 input[isRTL ? 'before' : 'after'](inst.trigger);
6672 inst.trigger.click(function() {
6673 if ($.datepicker._datepickerShowing && $.datepicker._lastInput == input[0])
6674 $.datepicker._hideDatepicker();
6675 else if ($.datepicker._datepickerShowing && $.datepicker._lastInput != input[0]) {
6676 $.datepicker._hideDatepicker();
6677 $.datepicker._showDatepicker(input[0]);
6678 } else
6679 $.datepicker._showDatepicker(input[0]);
6680 return false;
6681 });
6682 }
6683 },
6684
6685 /* Apply the maximum length for the date format. */
6686 _autoSize: function(inst) {
6687 if (this._get(inst, 'autoSize') && !inst.inline) {
6688 var date = new Date(2009, 12 - 1, 20); // Ensure double digits
6689 var dateFormat = this._get(inst, 'dateFormat');
6690 if (dateFormat.match(/[DM]/)) {
6691 var findMax = function(names) {
6692 var max = 0;
6693 var maxI = 0;
6694 for (var i = 0; i < names.length; i++) {
6695 if (names[i].length > max) {
6696 max = names[i].length;
6697 maxI = i;
6698 }
6699 }
6700 return maxI;
6701 };
6702 date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
6703 'monthNames' : 'monthNamesShort'))));
6704 date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
6705 'dayNames' : 'dayNamesShort'))) + 20 - date.getDay());
6706 }
6707 inst.input.attr('size', this._formatDate(inst, date).length);
6708 }
6709 },
6710
6711 /* Attach an inline date picker to a div. */
6712 _inlineDatepicker: function(target, inst) {
6713 var divSpan = $(target);
6714 if (divSpan.hasClass(this.markerClassName))
6715 return;
6716 divSpan.addClass(this.markerClassName).append(inst.dpDiv).
6717 bind("setData.datepicker", function(event, key, value){
6718 inst.settings[key] = value;
6719 }).bind("getData.datepicker", function(event, key){
6720 return this._get(inst, key);
6721 });
6722 $.data(target, PROP_NAME, inst);
6723 this._setDate(inst, this._getDefaultDate(inst), true);
6724 this._updateDatepicker(inst);
6725 this._updateAlternate(inst);
6726 //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
6727 if( inst.settings.disabled ) {
6728 this._disableDatepicker( target );
6729 }
6730 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
6731 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
6732 inst.dpDiv.css( "display", "block" );
6733 },
6734
6735 /* Pop-up the date picker in a "dialog" box.
6736 @param input element - ignored
6737 @param date string or Date - the initial date to display
6738 @param onSelect function - the function to call when a date is selected
6739 @param settings object - update the dialog date picker instance's settings (anonymous object)
6740 @param pos int[2] - coordinates for the dialog's position within the screen or
6741 event - with x/y coordinates or
6742 leave empty for default (screen centre)
6743 @return the manager object */
6744 _dialogDatepicker: function(input, date, onSelect, settings, pos) {
6745 var inst = this._dialogInst; // internal instance
6746 if (!inst) {
6747 this.uuid += 1;
6748 var id = 'dp' + this.uuid;
6749 this._dialogInput = $('<input type="text" id="' + id +
6750 '" style="position: absolute; top: -100px; width: 0px;"/>');
6751 this._dialogInput.keydown(this._doKeyDown);
6752 $('body').append(this._dialogInput);
6753 inst = this._dialogInst = this._newInst(this._dialogInput, false);
6754 inst.settings = {};
6755 $.data(this._dialogInput[0], PROP_NAME, inst);
6756 }
6757 extendRemove(inst.settings, settings || {});
6758 date = (date && date.constructor == Date ? this._formatDate(inst, date) : date);
6759 this._dialogInput.val(date);
6760
6761 this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
6762 if (!this._pos) {
6763 var browserWidth = document.documentElement.clientWidth;
6764 var browserHeight = document.documentElement.clientHeight;
6765 var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
6766 var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
6767 this._pos = // should use actual width/height below
6768 [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
6769 }
6770
6771 // move input on screen for focus, but hidden behind dialog
6772 this._dialogInput.css('left', (this._pos[0] + 20) + 'px').css('top', this._pos[1] + 'px');
6773 inst.settings.onSelect = onSelect;
6774 this._inDialog = true;
6775 this.dpDiv.addClass(this._dialogClass);
6776 this._showDatepicker(this._dialogInput[0]);
6777 if ($.blockUI)
6778 $.blockUI(this.dpDiv);
6779 $.data(this._dialogInput[0], PROP_NAME, inst);
6780 return this;
6781 },
6782
6783 /* Detach a datepicker from its control.
6784 @param target element - the target input field or division or span */
6785 _destroyDatepicker: function(target) {
6786 var $target = $(target);
6787 var inst = $.data(target, PROP_NAME);
6788 if (!$target.hasClass(this.markerClassName)) {
6789 return;
6790 }
6791 var nodeName = target.nodeName.toLowerCase();
6792 $.removeData(target, PROP_NAME);
6793 if (nodeName == 'input') {
6794 inst.append.remove();
6795 inst.trigger.remove();
6796 $target.removeClass(this.markerClassName).
6797 unbind('focus', this._showDatepicker).
6798 unbind('keydown', this._doKeyDown).
6799 unbind('keypress', this._doKeyPress).
6800 unbind('keyup', this._doKeyUp);
6801 } else if (nodeName == 'div' || nodeName == 'span')
6802 $target.removeClass(this.markerClassName).empty();
6803 },
6804
6805 /* Enable the date picker to a jQuery selection.
6806 @param target element - the target input field or division or span */
6807 _enableDatepicker: function(target) {
6808 var $target = $(target);
6809 var inst = $.data(target, PROP_NAME);
6810 if (!$target.hasClass(this.markerClassName)) {
6811 return;
6812 }
6813 var nodeName = target.nodeName.toLowerCase();
6814 if (nodeName == 'input') {
6815 target.disabled = false;
6816 inst.trigger.filter('button').
6817 each(function() { this.disabled = false; }).end().
6818 filter('img').css({opacity: '1.0', cursor: ''});
6819 }
6820 else if (nodeName == 'div' || nodeName == 'span') {
6821 var inline = $target.children('.' + this._inlineClass);
6822 inline.children().removeClass('ui-state-disabled');
6823 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
6824 prop("disabled", false);
6825 }
6826 this._disabledInputs = $.map(this._disabledInputs,
6827 function(value) { return (value == target ? null : value); }); // delete entry
6828 },
6829
6830 /* Disable the date picker to a jQuery selection.
6831 @param target element - the target input field or division or span */
6832 _disableDatepicker: function(target) {
6833 var $target = $(target);
6834 var inst = $.data(target, PROP_NAME);
6835 if (!$target.hasClass(this.markerClassName)) {
6836 return;
6837 }
6838 var nodeName = target.nodeName.toLowerCase();
6839 if (nodeName == 'input') {
6840 target.disabled = true;
6841 inst.trigger.filter('button').
6842 each(function() { this.disabled = true; }).end().
6843 filter('img').css({opacity: '0.5', cursor: 'default'});
6844 }
6845 else if (nodeName == 'div' || nodeName == 'span') {
6846 var inline = $target.children('.' + this._inlineClass);
6847 inline.children().addClass('ui-state-disabled');
6848 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
6849 prop("disabled", true);
6850 }
6851 this._disabledInputs = $.map(this._disabledInputs,
6852 function(value) { return (value == target ? null : value); }); // delete entry
6853 this._disabledInputs[this._disabledInputs.length] = target;
6854 },
6855
6856 /* Is the first field in a jQuery collection disabled as a datepicker?
6857 @param target element - the target input field or division or span
6858 @return boolean - true if disabled, false if enabled */
6859 _isDisabledDatepicker: function(target) {
6860 if (!target) {
6861 return false;
6862 }
6863 for (var i = 0; i < this._disabledInputs.length; i++) {
6864 if (this._disabledInputs[i] == target)
6865 return true;
6866 }
6867 return false;
6868 },
6869
6870 /* Retrieve the instance data for the target control.
6871 @param target element - the target input field or division or span
6872 @return object - the associated instance data
6873 @throws error if a jQuery problem getting data */
6874 _getInst: function(target) {
6875 try {
6876 return $.data(target, PROP_NAME);
6877 }
6878 catch (err) {
6879 throw 'Missing instance data for this datepicker';
6880 }
6881 },
6882
6883 /* Update or retrieve the settings for a date picker attached to an input field or division.
6884 @param target element - the target input field or division or span
6885 @param name object - the new settings to update or
6886 string - the name of the setting to change or retrieve,
6887 when retrieving also 'all' for all instance settings or
6888 'defaults' for all global defaults
6889 @param value any - the new value for the setting
6890 (omit if above is an object or to retrieve a value) */
6891 _optionDatepicker: function(target, name, value) {
6892 var inst = this._getInst(target);
6893 if (arguments.length == 2 && typeof name == 'string') {
6894 return (name == 'defaults' ? $.extend({}, $.datepicker._defaults) :
6895 (inst ? (name == 'all' ? $.extend({}, inst.settings) :
6896 this._get(inst, name)) : null));
6897 }
6898 var settings = name || {};
6899 if (typeof name == 'string') {
6900 settings = {};
6901 settings[name] = value;
6902 }
6903 if (inst) {
6904 if (this._curInst == inst) {
6905 this._hideDatepicker();
6906 }
6907 var date = this._getDateDatepicker(target, true);
6908 var minDate = this._getMinMaxDate(inst, 'min');
6909 var maxDate = this._getMinMaxDate(inst, 'max');
6910 extendRemove(inst.settings, settings);
6911 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
6912 if (minDate !== null && settings['dateFormat'] !== undefined && settings['minDate'] === undefined)
6913 inst.settings.minDate = this._formatDate(inst, minDate);
6914 if (maxDate !== null && settings['dateFormat'] !== undefined && settings['maxDate'] === undefined)
6915 inst.settings.maxDate = this._formatDate(inst, maxDate);
6916 this._attachments($(target), inst);
6917 this._autoSize(inst);
6918 this._setDate(inst, date);
6919 this._updateAlternate(inst);
6920 this._updateDatepicker(inst);
6921 }
6922 },
6923
6924 // change method deprecated
6925 _changeDatepicker: function(target, name, value) {
6926 this._optionDatepicker(target, name, value);
6927 },
6928
6929 /* Redraw the date picker attached to an input field or division.
6930 @param target element - the target input field or division or span */
6931 _refreshDatepicker: function(target) {
6932 var inst = this._getInst(target);
6933 if (inst) {
6934 this._updateDatepicker(inst);
6935 }
6936 },
6937
6938 /* Set the dates for a jQuery selection.
6939 @param target element - the target input field or division or span
6940 @param date Date - the new date */
6941 _setDateDatepicker: function(target, date) {
6942 var inst = this._getInst(target);
6943 if (inst) {
6944 this._setDate(inst, date);
6945 this._updateDatepicker(inst);
6946 this._updateAlternate(inst);
6947 }
6948 },
6949
6950 /* Get the date(s) for the first entry in a jQuery selection.
6951 @param target element - the target input field or division or span
6952 @param noDefault boolean - true if no default date is to be used
6953 @return Date - the current date */
6954 _getDateDatepicker: function(target, noDefault) {
6955 var inst = this._getInst(target);
6956 if (inst && !inst.inline)
6957 this._setDateFromField(inst, noDefault);
6958 return (inst ? this._getDate(inst) : null);
6959 },
6960
6961 /* Handle keystrokes. */
6962 _doKeyDown: function(event) {
6963 var inst = $.datepicker._getInst(event.target);
6964 var handled = true;
6965 var isRTL = inst.dpDiv.is('.ui-datepicker-rtl');
6966 inst._keyEvent = true;
6967 if ($.datepicker._datepickerShowing)
6968 switch (event.keyCode) {
6969 case 9: $.datepicker._hideDatepicker();
6970 handled = false;
6971 break; // hide on tab out
6972 case 13: var sel = $('td.' + $.datepicker._dayOverClass + ':not(.' +
6973 $.datepicker._currentClass + ')', inst.dpDiv);
6974 if (sel[0])
6975 $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
6976 var onSelect = $.datepicker._get(inst, 'onSelect');
6977 if (onSelect) {
6978 var dateStr = $.datepicker._formatDate(inst);
6979
6980 // trigger custom callback
6981 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
6982 }
6983 else
6984 $.datepicker._hideDatepicker();
6985 return false; // don't submit the form
6986 break; // select the value on enter
6987 case 27: $.datepicker._hideDatepicker();
6988 break; // hide on escape
6989 case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
6990 -$.datepicker._get(inst, 'stepBigMonths') :
6991 -$.datepicker._get(inst, 'stepMonths')), 'M');
6992 break; // previous month/year on page up/+ ctrl
6993 case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
6994 +$.datepicker._get(inst, 'stepBigMonths') :
6995 +$.datepicker._get(inst, 'stepMonths')), 'M');
6996 break; // next month/year on page down/+ ctrl
6997 case 35: if (event.ctrlKey || event.metaKey) $.datepicker._clearDate(event.target);
6998 handled = event.ctrlKey || event.metaKey;
6999 break; // clear on ctrl or command +end
7000 case 36: if (event.ctrlKey || event.metaKey) $.datepicker._gotoToday(event.target);
7001 handled = event.ctrlKey || event.metaKey;
7002 break; // current on ctrl or command +home
7003 case 37: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), 'D');
7004 handled = event.ctrlKey || event.metaKey;
7005 // -1 day on ctrl or command +left
7006 if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ?
7007 -$.datepicker._get(inst, 'stepBigMonths') :
7008 -$.datepicker._get(inst, 'stepMonths')), 'M');
7009 // next month/year on alt +left on Mac
7010 break;
7011 case 38: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, -7, 'D');
7012 handled = event.ctrlKey || event.metaKey;
7013 break; // -1 week on ctrl or command +up
7014 case 39: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), 'D');
7015 handled = event.ctrlKey || event.metaKey;
7016 // +1 day on ctrl or command +right
7017 if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ?
7018 +$.datepicker._get(inst, 'stepBigMonths') :
7019 +$.datepicker._get(inst, 'stepMonths')), 'M');
7020 // next month/year on alt +right
7021 break;
7022 case 40: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, +7, 'D');
7023 handled = event.ctrlKey || event.metaKey;
7024 break; // +1 week on ctrl or command +down
7025 default: handled = false;
7026 }
7027 else if (event.keyCode == 36 && event.ctrlKey) // display the date picker on ctrl+home
7028 $.datepicker._showDatepicker(this);
7029 else {
7030 handled = false;
7031 }
7032 if (handled) {
7033 event.preventDefault();
7034 event.stopPropagation();
7035 }
7036 },
7037
7038 /* Filter entered characters - based on date format. */
7039 _doKeyPress: function(event) {
7040 var inst = $.datepicker._getInst(event.target);
7041 if ($.datepicker._get(inst, 'constrainInput')) {
7042 var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat'));
7043 var chr = String.fromCharCode(event.charCode == undefined ? event.keyCode : event.charCode);
7044 return event.ctrlKey || event.metaKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1);
7045 }
7046 },
7047
7048 /* Synchronise manual entry and field/alternate field. */
7049 _doKeyUp: function(event) {
7050 var inst = $.datepicker._getInst(event.target);
7051 if (inst.input.val() != inst.lastVal) {
7052 try {
7053 var date = $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'),
7054 (inst.input ? inst.input.val() : null),
7055 $.datepicker._getFormatConfig(inst));
7056 if (date) { // only if valid
7057 $.datepicker._setDateFromField(inst);
7058 $.datepicker._updateAlternate(inst);
7059 $.datepicker._updateDatepicker(inst);
7060 }
7061 }
7062 catch (err) {
7063 $.datepicker.log(err);
7064 }
7065 }
7066 return true;
7067 },
7068
7069 /* Pop-up the date picker for a given input field.
7070 If false returned from beforeShow event handler do not show.
7071 @param input element - the input field attached to the date picker or
7072 event - if triggered by focus */
7073 _showDatepicker: function(input) {
7074 input = input.target || input;
7075 if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger
7076 input = $('input', input.parentNode)[0];
7077 if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here
7078 return;
7079 var inst = $.datepicker._getInst(input);
7080 if ($.datepicker._curInst && $.datepicker._curInst != inst) {
7081 $.datepicker._curInst.dpDiv.stop(true, true);
7082 if ( inst && $.datepicker._datepickerShowing ) {
7083 $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
7084 }
7085 }
7086 var beforeShow = $.datepicker._get(inst, 'beforeShow');
7087 var beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
7088 if(beforeShowSettings === false){
7089 //false
7090 return;
7091 }
7092 extendRemove(inst.settings, beforeShowSettings);
7093 inst.lastVal = null;
7094 $.datepicker._lastInput = input;
7095 $.datepicker._setDateFromField(inst);
7096 if ($.datepicker._inDialog) // hide cursor
7097 input.value = '';
7098 if (!$.datepicker._pos) { // position below input
7099 $.datepicker._pos = $.datepicker._findPos(input);
7100 $.datepicker._pos[1] += input.offsetHeight; // add the height
7101 }
7102 var isFixed = false;
7103 $(input).parents().each(function() {
7104 isFixed |= $(this).css('position') == 'fixed';
7105 return !isFixed;
7106 });
7107 var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
7108 $.datepicker._pos = null;
7109 //to avoid flashes on Firefox
7110 inst.dpDiv.empty();
7111 // determine sizing offscreen
7112 inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'});
7113 $.datepicker._updateDatepicker(inst);
7114 // fix width for dynamic number of date pickers
7115 // and adjust position before showing
7116 offset = $.datepicker._checkOffset(inst, offset, isFixed);
7117 inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
7118 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none',
7119 left: offset.left + 'px', top: offset.top + 'px'});
7120 if (!inst.inline) {
7121 var showAnim = $.datepicker._get(inst, 'showAnim');
7122 var duration = $.datepicker._get(inst, 'duration');
7123 var postProcess = function() {
7124 var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only
7125 if( !! cover.length ){
7126 var borders = $.datepicker._getBorders(inst.dpDiv);
7127 cover.css({left: -borders[0], top: -borders[1],
7128 width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()});
7129 }
7130 };
7131 inst.dpDiv.zIndex($(input).zIndex()+1);
7132 $.datepicker._datepickerShowing = true;
7133
7134 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
7135 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) )
7136 inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);
7137 else
7138 inst.dpDiv[showAnim || 'show']((showAnim ? duration : null), postProcess);
7139 if (!showAnim || !duration)
7140 postProcess();
7141 if (inst.input.is(':visible') && !inst.input.is(':disabled'))
7142 inst.input.focus();
7143 $.datepicker._curInst = inst;
7144 }
7145 },
7146
7147 /* Generate the date picker content. */
7148 _updateDatepicker: function(inst) {
7149 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
7150 var borders = $.datepicker._getBorders(inst.dpDiv);
7151 instActive = inst; // for delegate hover events
7152 inst.dpDiv.empty().append(this._generateHTML(inst));
7153 this._attachHandlers(inst);
7154 var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only
7155 if( !!cover.length ){ //avoid call to outerXXXX() when not in IE6
7156 cover.css({left: -borders[0], top: -borders[1], width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()})
7157 }
7158 inst.dpDiv.find('.' + this._dayOverClass + ' a').mouseover();
7159 var numMonths = this._getNumberOfMonths(inst);
7160 var cols = numMonths[1];
7161 var width = 17;
7162 inst.dpDiv.removeClass('ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4').width('');
7163 if (cols > 1)
7164 inst.dpDiv.addClass('ui-datepicker-multi-' + cols).css('width', (width * cols) + 'em');
7165 inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') +
7166 'Class']('ui-datepicker-multi');
7167 inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') +
7168 'Class']('ui-datepicker-rtl');
7169 if (inst == $.datepicker._curInst && $.datepicker._datepickerShowing && inst.input &&
7170 // #6694 - don't focus the input if it's already focused
7171 // this breaks the change event in IE
7172 inst.input.is(':visible') && !inst.input.is(':disabled') && inst.input[0] != document.activeElement)
7173 inst.input.focus();
7174 // deffered render of the years select (to avoid flashes on Firefox)
7175 if( inst.yearshtml ){
7176 var origyearshtml = inst.yearshtml;
7177 setTimeout(function(){
7178 //assure that inst.yearshtml didn't change.
7179 if( origyearshtml === inst.yearshtml && inst.yearshtml ){
7180 inst.dpDiv.find('select.ui-datepicker-year:first').replaceWith(inst.yearshtml);
7181 }
7182 origyearshtml = inst.yearshtml = null;
7183 }, 0);
7184 }
7185 },
7186
7187 /* Retrieve the size of left and top borders for an element.
7188 @param elem (jQuery object) the element of interest
7189 @return (number[2]) the left and top borders */
7190 _getBorders: function(elem) {
7191 var convert = function(value) {
7192 return {thin: 1, medium: 2, thick: 3}[value] || value;
7193 };
7194 return [parseFloat(convert(elem.css('border-left-width'))),
7195 parseFloat(convert(elem.css('border-top-width')))];
7196 },
7197
7198 /* Check positioning to remain on screen. */
7199 _checkOffset: function(inst, offset, isFixed) {
7200 var dpWidth = inst.dpDiv.outerWidth();
7201 var dpHeight = inst.dpDiv.outerHeight();
7202 var inputWidth = inst.input ? inst.input.outerWidth() : 0;
7203 var inputHeight = inst.input ? inst.input.outerHeight() : 0;
7204 var viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft());
7205 var viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
7206
7207 offset.left -= (this._get(inst, 'isRTL') ? (dpWidth - inputWidth) : 0);
7208 offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0;
7209 offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
7210
7211 // now check if datepicker is showing outside window viewport - move to a better place if so.
7212 offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
7213 Math.abs(offset.left + dpWidth - viewWidth) : 0);
7214 offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
7215 Math.abs(dpHeight + inputHeight) : 0);
7216
7217 return offset;
7218 },
7219
7220 /* Find an object's position on the screen. */
7221 _findPos: function(obj) {
7222 var inst = this._getInst(obj);
7223 var isRTL = this._get(inst, 'isRTL');
7224 while (obj && (obj.type == 'hidden' || obj.nodeType != 1 || $.expr.filters.hidden(obj))) {
7225 obj = obj[isRTL ? 'previousSibling' : 'nextSibling'];
7226 }
7227 var position = $(obj).offset();
7228 return [position.left, position.top];
7229 },
7230
7231 /* Hide the date picker from view.
7232 @param input element - the input field attached to the date picker */
7233 _hideDatepicker: function(input) {
7234 var inst = this._curInst;
7235 if (!inst || (input && inst != $.data(input, PROP_NAME)))
7236 return;
7237 if (this._datepickerShowing) {
7238 var showAnim = this._get(inst, 'showAnim');
7239 var duration = this._get(inst, 'duration');
7240 var postProcess = function() {
7241 $.datepicker._tidyDialog(inst);
7242 };
7243
7244 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
7245 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) )
7246 inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);
7247 else
7248 inst.dpDiv[(showAnim == 'slideDown' ? 'slideUp' :
7249 (showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))]((showAnim ? duration : null), postProcess);
7250 if (!showAnim)
7251 postProcess();
7252 this._datepickerShowing = false;
7253 var onClose = this._get(inst, 'onClose');
7254 if (onClose)
7255 onClose.apply((inst.input ? inst.input[0] : null),
7256 [(inst.input ? inst.input.val() : ''), inst]);
7257 this._lastInput = null;
7258 if (this._inDialog) {
7259 this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' });
7260 if ($.blockUI) {
7261 $.unblockUI();
7262 $('body').append(this.dpDiv);
7263 }
7264 }
7265 this._inDialog = false;
7266 }
7267 },
7268
7269 /* Tidy up after a dialog display. */
7270 _tidyDialog: function(inst) {
7271 inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker-calendar');
7272 },
7273
7274 /* Close date picker if clicked elsewhere. */
7275 _checkExternalClick: function(event) {
7276 if (!$.datepicker._curInst)
7277 return;
7278
7279 var $target = $(event.target),
7280 inst = $.datepicker._getInst($target[0]);
7281
7282 if ( ( ( $target[0].id != $.datepicker._mainDivId &&
7283 $target.parents('#' + $.datepicker._mainDivId).length == 0 &&
7284 !$target.hasClass($.datepicker.markerClassName) &&
7285 !$target.closest("." + $.datepicker._triggerClass).length &&
7286 $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
7287 ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst != inst ) )
7288 $.datepicker._hideDatepicker();
7289 },
7290
7291 /* Adjust one of the date sub-fields. */
7292 _adjustDate: function(id, offset, period) {
7293 var target = $(id);
7294 var inst = this._getInst(target[0]);
7295 if (this._isDisabledDatepicker(target[0])) {
7296 return;
7297 }
7298 this._adjustInstDate(inst, offset +
7299 (period == 'M' ? this._get(inst, 'showCurrentAtPos') : 0), // undo positioning
7300 period);
7301 this._updateDatepicker(inst);
7302 },
7303
7304 /* Action for current link. */
7305 _gotoToday: function(id) {
7306 var target = $(id);
7307 var inst = this._getInst(target[0]);
7308 if (this._get(inst, 'gotoCurrent') && inst.currentDay) {
7309 inst.selectedDay = inst.currentDay;
7310 inst.drawMonth = inst.selectedMonth = inst.currentMonth;
7311 inst.drawYear = inst.selectedYear = inst.currentYear;
7312 }
7313 else {
7314 var date = new Date();
7315 inst.selectedDay = date.getDate();
7316 inst.drawMonth = inst.selectedMonth = date.getMonth();
7317 inst.drawYear = inst.selectedYear = date.getFullYear();
7318 }
7319 this._notifyChange(inst);
7320 this._adjustDate(target);
7321 },
7322
7323 /* Action for selecting a new month/year. */
7324 _selectMonthYear: function(id, select, period) {
7325 var target = $(id);
7326 var inst = this._getInst(target[0]);
7327 inst['selected' + (period == 'M' ? 'Month' : 'Year')] =
7328 inst['draw' + (period == 'M' ? 'Month' : 'Year')] =
7329 parseInt(select.options[select.selectedIndex].value,10);
7330 this._notifyChange(inst);
7331 this._adjustDate(target);
7332 },
7333
7334 /* Action for selecting a day. */
7335 _selectDay: function(id, month, year, td) {
7336 var target = $(id);
7337 if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
7338 return;
7339 }
7340 var inst = this._getInst(target[0]);
7341 inst.selectedDay = inst.currentDay = $('a', td).html();
7342 inst.selectedMonth = inst.currentMonth = month;
7343 inst.selectedYear = inst.currentYear = year;
7344 this._selectDate(id, this._formatDate(inst,
7345 inst.currentDay, inst.currentMonth, inst.currentYear));
7346 },
7347
7348 /* Erase the input field and hide the date picker. */
7349 _clearDate: function(id) {
7350 var target = $(id);
7351 var inst = this._getInst(target[0]);
7352 this._selectDate(target, '');
7353 },
7354
7355 /* Update the input field with the selected date. */
7356 _selectDate: function(id, dateStr) {
7357 var target = $(id);
7358 var inst = this._getInst(target[0]);
7359 dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
7360 if (inst.input)
7361 inst.input.val(dateStr);
7362 this._updateAlternate(inst);
7363 var onSelect = this._get(inst, 'onSelect');
7364 if (onSelect)
7365 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
7366 else if (inst.input)
7367 inst.input.trigger('change'); // fire the change event
7368 if (inst.inline)
7369 this._updateDatepicker(inst);
7370 else {
7371 this._hideDatepicker();
7372 this._lastInput = inst.input[0];
7373 if (typeof(inst.input[0]) != 'object')
7374 inst.input.focus(); // restore focus
7375 this._lastInput = null;
7376 }
7377 },
7378
7379 /* Update any alternate field to synchronise with the main field. */
7380 _updateAlternate: function(inst) {
7381 var altField = this._get(inst, 'altField');
7382 if (altField) { // update alternate field too
7383 var altFormat = this._get(inst, 'altFormat') || this._get(inst, 'dateFormat');
7384 var date = this._getDate(inst);
7385 var dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
7386 $(altField).each(function() { $(this).val(dateStr); });
7387 }
7388 },
7389
7390 /* Set as beforeShowDay function to prevent selection of weekends.
7391 @param date Date - the date to customise
7392 @return [boolean, string] - is this date selectable?, what is its CSS class? */
7393 noWeekends: function(date) {
7394 var day = date.getDay();
7395 return [(day > 0 && day < 6), ''];
7396 },
7397
7398 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
7399 @param date Date - the date to get the week for
7400 @return number - the number of the week within the year that contains this date */
7401 iso8601Week: function(date) {
7402 var checkDate = new Date(date.getTime());
7403 // Find Thursday of this week starting on Monday
7404 checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
7405 var time = checkDate.getTime();
7406 checkDate.setMonth(0); // Compare with Jan 1
7407 checkDate.setDate(1);
7408 return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
7409 },
7410
7411 /* Parse a string value into a date object.
7412 See formatDate below for the possible formats.
7413
7414 @param format string - the expected format of the date
7415 @param value string - the date in the above format
7416 @param settings Object - attributes include:
7417 shortYearCutoff number - the cutoff year for determining the century (optional)
7418 dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
7419 dayNames string[7] - names of the days from Sunday (optional)
7420 monthNamesShort string[12] - abbreviated names of the months (optional)
7421 monthNames string[12] - names of the months (optional)
7422 @return Date - the extracted date value or null if value is blank */
7423 parseDate: function (format, value, settings) {
7424 if (format == null || value == null)
7425 throw 'Invalid arguments';
7426 value = (typeof value == 'object' ? value.toString() : value + '');
7427 if (value == '')
7428 return null;
7429 var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff;
7430 shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff :
7431 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
7432 var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
7433 var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
7434 var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
7435 var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
7436 var year = -1;
7437 var month = -1;
7438 var day = -1;
7439 var doy = -1;
7440 var literal = false;
7441 // Check whether a format character is doubled
7442 var lookAhead = function(match) {
7443 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
7444 if (matches)
7445 iFormat++;
7446 return matches;
7447 };
7448 // Extract a number from the string value
7449 var getNumber = function(match) {
7450 var isDoubled = lookAhead(match);
7451 var size = (match == '@' ? 14 : (match == '!' ? 20 :
7452 (match == 'y' && isDoubled ? 4 : (match == 'o' ? 3 : 2))));
7453 var digits = new RegExp('^\\d{1,' + size + '}');
7454 var num = value.substring(iValue).match(digits);
7455 if (!num)
7456 throw 'Missing number at position ' + iValue;
7457 iValue += num[0].length;
7458 return parseInt(num[0], 10);
7459 };
7460 // Extract a name from the string value and convert to an index
7461 var getName = function(match, shortNames, longNames) {
7462 var names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
7463 return [ [k, v] ];
7464 }).sort(function (a, b) {
7465 return -(a[1].length - b[1].length);
7466 });
7467 var index = -1;
7468 $.each(names, function (i, pair) {
7469 var name = pair[1];
7470 if (value.substr(iValue, name.length).toLowerCase() == name.toLowerCase()) {
7471 index = pair[0];
7472 iValue += name.length;
7473 return false;
7474 }
7475 });
7476 if (index != -1)
7477 return index + 1;
7478 else
7479 throw 'Unknown name at position ' + iValue;
7480 };
7481 // Confirm that a literal character matches the string value
7482 var checkLiteral = function() {
7483 if (value.charAt(iValue) != format.charAt(iFormat))
7484 throw 'Unexpected literal at position ' + iValue;
7485 iValue++;
7486 };
7487 var iValue = 0;
7488 for (var iFormat = 0; iFormat < format.length; iFormat++) {
7489 if (literal)
7490 if (format.charAt(iFormat) == "'" && !lookAhead("'"))
7491 literal = false;
7492 else
7493 checkLiteral();
7494 else
7495 switch (format.charAt(iFormat)) {
7496 case 'd':
7497 day = getNumber('d');
7498 break;
7499 case 'D':
7500 getName('D', dayNamesShort, dayNames);
7501 break;
7502 case 'o':
7503 doy = getNumber('o');
7504 break;
7505 case 'm':
7506 month = getNumber('m');
7507 break;
7508 case 'M':
7509 month = getName('M', monthNamesShort, monthNames);
7510 break;
7511 case 'y':
7512 year = getNumber('y');
7513 break;
7514 case '@':
7515 var date = new Date(getNumber('@'));
7516 year = date.getFullYear();
7517 month = date.getMonth() + 1;
7518 day = date.getDate();
7519 break;
7520 case '!':
7521 var date = new Date((getNumber('!') - this._ticksTo1970) / 10000);
7522 year = date.getFullYear();
7523 month = date.getMonth() + 1;
7524 day = date.getDate();
7525 break;
7526 case "'":
7527 if (lookAhead("'"))
7528 checkLiteral();
7529 else
7530 literal = true;
7531 break;
7532 default:
7533 checkLiteral();
7534 }
7535 }
7536 if (iValue < value.length){
7537 var extra = value.substr(iValue);
7538 if (!/^\s+/.test(extra)) {
7539 throw "Extra/unparsed characters found in date: " + extra;
7540 }
7541 }
7542 if (year == -1)
7543 year = new Date().getFullYear();
7544 else if (year < 100)
7545 year += new Date().getFullYear() - new Date().getFullYear() % 100 +
7546 (year <= shortYearCutoff ? 0 : -100);
7547 if (doy > -1) {
7548 month = 1;
7549 day = doy;
7550 do {
7551 var dim = this._getDaysInMonth(year, month - 1);
7552 if (day <= dim)
7553 break;
7554 month++;
7555 day -= dim;
7556 } while (true);
7557 }
7558 var date = this._daylightSavingAdjust(new Date(year, month - 1, day));
7559 if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day)
7560 throw 'Invalid date'; // E.g. 31/02/00
7561 return date;
7562 },
7563
7564 /* Standard date formats. */
7565 ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601)
7566 COOKIE: 'D, dd M yy',
7567 ISO_8601: 'yy-mm-dd',
7568 RFC_822: 'D, d M y',
7569 RFC_850: 'DD, dd-M-y',
7570 RFC_1036: 'D, d M y',
7571 RFC_1123: 'D, d M yy',
7572 RFC_2822: 'D, d M yy',
7573 RSS: 'D, d M y', // RFC 822
7574 TICKS: '!',
7575 TIMESTAMP: '@',
7576 W3C: 'yy-mm-dd', // ISO 8601
7577
7578 _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
7579 Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
7580
7581 /* Format a date object into a string value.
7582 The format can be combinations of the following:
7583 d - day of month (no leading zero)
7584 dd - day of month (two digit)
7585 o - day of year (no leading zeros)
7586 oo - day of year (three digit)
7587 D - day name short
7588 DD - day name long
7589 m - month of year (no leading zero)
7590 mm - month of year (two digit)
7591 M - month name short
7592 MM - month name long
7593 y - year (two digit)
7594 yy - year (four digit)
7595 @ - Unix timestamp (ms since 01/01/1970)
7596 ! - Windows ticks (100ns since 01/01/0001)
7597 '...' - literal text
7598 '' - single quote
7599
7600 @param format string - the desired format of the date
7601 @param date Date - the date value to format
7602 @param settings Object - attributes include:
7603 dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
7604 dayNames string[7] - names of the days from Sunday (optional)
7605 monthNamesShort string[12] - abbreviated names of the months (optional)
7606 monthNames string[12] - names of the months (optional)
7607 @return string - the date in the above format */
7608 formatDate: function (format, date, settings) {
7609 if (!date)
7610 return '';
7611 var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
7612 var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
7613 var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
7614 var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
7615 // Check whether a format character is doubled
7616 var lookAhead = function(match) {
7617 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
7618 if (matches)
7619 iFormat++;
7620 return matches;
7621 };
7622 // Format a number, with leading zero if necessary
7623 var formatNumber = function(match, value, len) {
7624 var num = '' + value;
7625 if (lookAhead(match))
7626 while (num.length < len)
7627 num = '0' + num;
7628 return num;
7629 };
7630 // Format a name, short or long as requested
7631 var formatName = function(match, value, shortNames, longNames) {
7632 return (lookAhead(match) ? longNames[value] : shortNames[value]);
7633 };
7634 var output = '';
7635 var literal = false;
7636 if (date)
7637 for (var iFormat = 0; iFormat < format.length; iFormat++) {
7638 if (literal)
7639 if (format.charAt(iFormat) == "'" && !lookAhead("'"))
7640 literal = false;
7641 else
7642 output += format.charAt(iFormat);
7643 else
7644 switch (format.charAt(iFormat)) {
7645 case 'd':
7646 output += formatNumber('d', date.getDate(), 2);
7647 break;
7648 case 'D':
7649 output += formatName('D', date.getDay(), dayNamesShort, dayNames);
7650 break;
7651 case 'o':
7652 output += formatNumber('o',
7653 Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
7654 break;
7655 case 'm':
7656 output += formatNumber('m', date.getMonth() + 1, 2);
7657 break;
7658 case 'M':
7659 output += formatName('M', date.getMonth(), monthNamesShort, monthNames);
7660 break;
7661 case 'y':
7662 output += (lookAhead('y') ? date.getFullYear() :
7663 (date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100);
7664 break;
7665 case '@':
7666 output += date.getTime();
7667 break;
7668 case '!':
7669 output += date.getTime() * 10000 + this._ticksTo1970;
7670 break;
7671 case "'":
7672 if (lookAhead("'"))
7673 output += "'";
7674 else
7675 literal = true;
7676 break;
7677 default:
7678 output += format.charAt(iFormat);
7679 }
7680 }
7681 return output;
7682 },
7683
7684 /* Extract all possible characters from the date format. */
7685 _possibleChars: function (format) {
7686 var chars = '';
7687 var literal = false;
7688 // Check whether a format character is doubled
7689 var lookAhead = function(match) {
7690 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
7691 if (matches)
7692 iFormat++;
7693 return matches;
7694 };
7695 for (var iFormat = 0; iFormat < format.length; iFormat++)
7696 if (literal)
7697 if (format.charAt(iFormat) == "'" && !lookAhead("'"))
7698 literal = false;
7699 else
7700 chars += format.charAt(iFormat);
7701 else
7702 switch (format.charAt(iFormat)) {
7703 case 'd': case 'm': case 'y': case '@':
7704 chars += '0123456789';
7705 break;
7706 case 'D': case 'M':
7707 return null; // Accept anything
7708 case "'":
7709 if (lookAhead("'"))
7710 chars += "'";
7711 else
7712 literal = true;
7713 break;
7714 default:
7715 chars += format.charAt(iFormat);
7716 }
7717 return chars;
7718 },
7719
7720 /* Get a setting value, defaulting if necessary. */
7721 _get: function(inst, name) {
7722 return inst.settings[name] !== undefined ?
7723 inst.settings[name] : this._defaults[name];
7724 },
7725
7726 /* Parse existing date and initialise date picker. */
7727 _setDateFromField: function(inst, noDefault) {
7728 if (inst.input.val() == inst.lastVal) {
7729 return;
7730 }
7731 var dateFormat = this._get(inst, 'dateFormat');
7732 var dates = inst.lastVal = inst.input ? inst.input.val() : null;
7733 var date, defaultDate;
7734 date = defaultDate = this._getDefaultDate(inst);
7735 var settings = this._getFormatConfig(inst);
7736 try {
7737 date = this.parseDate(dateFormat, dates, settings) || defaultDate;
7738 } catch (event) {
7739 this.log(event);
7740 dates = (noDefault ? '' : dates);
7741 }
7742 inst.selectedDay = date.getDate();
7743 inst.drawMonth = inst.selectedMonth = date.getMonth();
7744 inst.drawYear = inst.selectedYear = date.getFullYear();
7745 inst.currentDay = (dates ? date.getDate() : 0);
7746 inst.currentMonth = (dates ? date.getMonth() : 0);
7747 inst.currentYear = (dates ? date.getFullYear() : 0);
7748 this._adjustInstDate(inst);
7749 },
7750
7751 /* Retrieve the default date shown on opening. */
7752 _getDefaultDate: function(inst) {
7753 return this._restrictMinMax(inst,
7754 this._determineDate(inst, this._get(inst, 'defaultDate'), new Date()));
7755 },
7756
7757 /* A date may be specified as an exact value or a relative one. */
7758 _determineDate: function(inst, date, defaultDate) {
7759 var offsetNumeric = function(offset) {
7760 var date = new Date();
7761 date.setDate(date.getDate() + offset);
7762 return date;
7763 };
7764 var offsetString = function(offset) {
7765 try {
7766 return $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'),
7767 offset, $.datepicker._getFormatConfig(inst));
7768 }
7769 catch (e) {
7770 // Ignore
7771 }
7772 var date = (offset.toLowerCase().match(/^c/) ?
7773 $.datepicker._getDate(inst) : null) || new Date();
7774 var year = date.getFullYear();
7775 var month = date.getMonth();
7776 var day = date.getDate();
7777 var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g;
7778 var matches = pattern.exec(offset);
7779 while (matches) {
7780 switch (matches[2] || 'd') {
7781 case 'd' : case 'D' :
7782 day += parseInt(matches[1],10); break;
7783 case 'w' : case 'W' :
7784 day += parseInt(matches[1],10) * 7; break;
7785 case 'm' : case 'M' :
7786 month += parseInt(matches[1],10);
7787 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
7788 break;
7789 case 'y': case 'Y' :
7790 year += parseInt(matches[1],10);
7791 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
7792 break;
7793 }
7794 matches = pattern.exec(offset);
7795 }
7796 return new Date(year, month, day);
7797 };
7798 var newDate = (date == null || date === '' ? defaultDate : (typeof date == 'string' ? offsetString(date) :
7799 (typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
7800 newDate = (newDate && newDate.toString() == 'Invalid Date' ? defaultDate : newDate);
7801 if (newDate) {
7802 newDate.setHours(0);
7803 newDate.setMinutes(0);
7804 newDate.setSeconds(0);
7805 newDate.setMilliseconds(0);
7806 }
7807 return this._daylightSavingAdjust(newDate);
7808 },
7809
7810 /* Handle switch to/from daylight saving.
7811 Hours may be non-zero on daylight saving cut-over:
7812 > 12 when midnight changeover, but then cannot generate
7813 midnight datetime, so jump to 1AM, otherwise reset.
7814 @param date (Date) the date to check
7815 @return (Date) the corrected date */
7816 _daylightSavingAdjust: function(date) {
7817 if (!date) return null;
7818 date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
7819 return date;
7820 },
7821
7822 /* Set the date(s) directly. */
7823 _setDate: function(inst, date, noChange) {
7824 var clear = !date;
7825 var origMonth = inst.selectedMonth;
7826 var origYear = inst.selectedYear;
7827 var newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
7828 inst.selectedDay = inst.currentDay = newDate.getDate();
7829 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
7830 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
7831 if ((origMonth != inst.selectedMonth || origYear != inst.selectedYear) && !noChange)
7832 this._notifyChange(inst);
7833 this._adjustInstDate(inst);
7834 if (inst.input) {
7835 inst.input.val(clear ? '' : this._formatDate(inst));
7836 }
7837 },
7838
7839 /* Retrieve the date(s) directly. */
7840 _getDate: function(inst) {
7841 var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null :
7842 this._daylightSavingAdjust(new Date(
7843 inst.currentYear, inst.currentMonth, inst.currentDay)));
7844 return startDate;
7845 },
7846
7847 /* Attach the onxxx handlers. These are declared statically so
7848 * they work with static code transformers like Caja.
7849 */
7850 _attachHandlers: function(inst) {
7851 var stepMonths = this._get(inst, 'stepMonths');
7852 var id = '#' + inst.id.replace( /\\\\/g, "\\" );
7853 inst.dpDiv.find('[data-handler]').map(function () {
7854 var handler = {
7855 prev: function () {
7856 window['DP_jQuery_' + dpuuid].datepicker._adjustDate(id, -stepMonths, 'M');
7857 },
7858 next: function () {
7859 window['DP_jQuery_' + dpuuid].datepicker._adjustDate(id, +stepMonths, 'M');
7860 },
7861 hide: function () {
7862 window['DP_jQuery_' + dpuuid].datepicker._hideDatepicker();
7863 },
7864 today: function () {
7865 window['DP_jQuery_' + dpuuid].datepicker._gotoToday(id);
7866 },
7867 selectDay: function () {
7868 window['DP_jQuery_' + dpuuid].datepicker._selectDay(id, +this.getAttribute('data-month'), +this.getAttribute('data-year'), this);
7869 return false;
7870 },
7871 selectMonth: function () {
7872 window['DP_jQuery_' + dpuuid].datepicker._selectMonthYear(id, this, 'M');
7873 return false;
7874 },
7875 selectYear: function () {
7876 window['DP_jQuery_' + dpuuid].datepicker._selectMonthYear(id, this, 'Y');
7877 return false;
7878 }
7879 };
7880 $(this).bind(this.getAttribute('data-event'), handler[this.getAttribute('data-handler')]);
7881 });
7882 },
7883
7884 /* Generate the HTML for the current state of the date picker. */
7885 _generateHTML: function(inst) {
7886 var today = new Date();
7887 today = this._daylightSavingAdjust(
7888 new Date(today.getFullYear(), today.getMonth(), today.getDate())); // clear time
7889 var isRTL = this._get(inst, 'isRTL');
7890 var showButtonPanel = this._get(inst, 'showButtonPanel');
7891 var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext');
7892 var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat');
7893 var numMonths = this._getNumberOfMonths(inst);
7894 var showCurrentAtPos = this._get(inst, 'showCurrentAtPos');
7895 var stepMonths = this._get(inst, 'stepMonths');
7896 var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1);
7897 var currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
7898 new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
7899 var minDate = this._getMinMaxDate(inst, 'min');
7900 var maxDate = this._getMinMaxDate(inst, 'max');
7901 var drawMonth = inst.drawMonth - showCurrentAtPos;
7902 var drawYear = inst.drawYear;
7903 if (drawMonth < 0) {
7904 drawMonth += 12;
7905 drawYear--;
7906 }
7907 if (maxDate) {
7908 var maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
7909 maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
7910 maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
7911 while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
7912 drawMonth--;
7913 if (drawMonth < 0) {
7914 drawMonth = 11;
7915 drawYear--;
7916 }
7917 }
7918 }
7919 inst.drawMonth = drawMonth;
7920 inst.drawYear = drawYear;
7921 var prevText = this._get(inst, 'prevText');
7922 prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
7923 this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
7924 this._getFormatConfig(inst)));
7925 var prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
7926 '<a class="ui-datepicker-prev ui-corner-all" data-handler="prev" data-event="click"' +
7927 ' title="' + prevText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'e' : 'w') + '">' + prevText + '</span></a>' :
7928 (hideIfNoPrevNext ? '' : '<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+ prevText +'"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'e' : 'w') + '">' + prevText + '</span></a>'));
7929 var nextText = this._get(inst, 'nextText');
7930 nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
7931 this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
7932 this._getFormatConfig(inst)));
7933 var next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
7934 '<a class="ui-datepicker-next ui-corner-all" data-handler="next" data-event="click"' +
7935 ' title="' + nextText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'w' : 'e') + '">' + nextText + '</span></a>' :
7936 (hideIfNoPrevNext ? '' : '<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+ nextText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'w' : 'e') + '">' + nextText + '</span></a>'));
7937 var currentText = this._get(inst, 'currentText');
7938 var gotoDate = (this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today);
7939 currentText = (!navigationAsDateFormat ? currentText :
7940 this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
7941 var controls = (!inst.inline ? '<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" data-handler="hide" data-event="click">' +
7942 this._get(inst, 'closeText') + '</button>' : '');
7943 var buttonPanel = (showButtonPanel) ? '<div class="ui-datepicker-buttonpane ui-widget-content">' + (isRTL ? controls : '') +
7944 (this._isInRange(inst, gotoDate) ? '<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" data-handler="today" data-event="click"' +
7945 '>' + currentText + '</button>' : '') + (isRTL ? '' : controls) + '</div>' : '';
7946 var firstDay = parseInt(this._get(inst, 'firstDay'),10);
7947 firstDay = (isNaN(firstDay) ? 0 : firstDay);
7948 var showWeek = this._get(inst, 'showWeek');
7949 var dayNames = this._get(inst, 'dayNames');
7950 var dayNamesShort = this._get(inst, 'dayNamesShort');
7951 var dayNamesMin = this._get(inst, 'dayNamesMin');
7952 var monthNames = this._get(inst, 'monthNames');
7953 var monthNamesShort = this._get(inst, 'monthNamesShort');
7954 var beforeShowDay = this._get(inst, 'beforeShowDay');
7955 var showOtherMonths = this._get(inst, 'showOtherMonths');
7956 var selectOtherMonths = this._get(inst, 'selectOtherMonths');
7957 var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week;
7958 var defaultDate = this._getDefaultDate(inst);
7959 var html = '';
7960 for (var row = 0; row < numMonths[0]; row++) {
7961 var group = '';
7962 this.maxRows = 4;
7963 for (var col = 0; col < numMonths[1]; col++) {
7964 var selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
7965 var cornerClass = ' ui-corner-all';
7966 var calender = '';
7967 if (isMultiMonth) {
7968 calender += '<div class="ui-datepicker-group';
7969 if (numMonths[1] > 1)
7970 switch (col) {
7971 case 0: calender += ' ui-datepicker-group-first';
7972 cornerClass = ' ui-corner-' + (isRTL ? 'right' : 'left'); break;
7973 case numMonths[1]-1: calender += ' ui-datepicker-group-last';
7974 cornerClass = ' ui-corner-' + (isRTL ? 'left' : 'right'); break;
7975 default: calender += ' ui-datepicker-group-middle'; cornerClass = ''; break;
7976 }
7977 calender += '">';
7978 }
7979 calender += '<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix' + cornerClass + '">' +
7980 (/all|left/.test(cornerClass) && row == 0 ? (isRTL ? next : prev) : '') +
7981 (/all|right/.test(cornerClass) && row == 0 ? (isRTL ? prev : next) : '') +
7982 this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
7983 row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
7984 '</div><table class="ui-datepicker-calendar"><thead>' +
7985 '<tr>';
7986 var thead = (showWeek ? '<th class="ui-datepicker-week-col">' + this._get(inst, 'weekHeader') + '</th>' : '');
7987 for (var dow = 0; dow < 7; dow++) { // days of the week
7988 var day = (dow + firstDay) % 7;
7989 thead += '<th' + ((dow + firstDay + 6) % 7 >= 5 ? ' class="ui-datepicker-week-end"' : '') + '>' +
7990 '<span title="' + dayNames[day] + '">' + dayNamesMin[day] + '</span></th>';
7991 }
7992 calender += thead + '</tr></thead><tbody>';
7993 var daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
7994 if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth)
7995 inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
7996 var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
7997 var curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
7998 var numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
7999 this.maxRows = numRows;
8000 var printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
8001 for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows
8002 calender += '<tr>';
8003 var tbody = (!showWeek ? '' : '<td class="ui-datepicker-week-col">' +
8004 this._get(inst, 'calculateWeek')(printDate) + '</td>');
8005 for (var dow = 0; dow < 7; dow++) { // create date picker days
8006 var daySettings = (beforeShowDay ?
8007 beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']);
8008 var otherMonth = (printDate.getMonth() != drawMonth);
8009 var unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
8010 (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
8011 tbody += '<td class="' +
8012 ((dow + firstDay + 6) % 7 >= 5 ? ' ui-datepicker-week-end' : '') + // highlight weekends
8013 (otherMonth ? ' ui-datepicker-other-month' : '') + // highlight days from other months
8014 ((printDate.getTime() == selectedDate.getTime() && drawMonth == inst.selectedMonth && inst._keyEvent) || // user pressed key
8015 (defaultDate.getTime() == printDate.getTime() && defaultDate.getTime() == selectedDate.getTime()) ?
8016 // or defaultDate is current printedDate and defaultDate is selectedDate
8017 ' ' + this._dayOverClass : '') + // highlight selected day
8018 (unselectable ? ' ' + this._unselectableClass + ' ui-state-disabled': '') + // highlight unselectable days
8019 (otherMonth && !showOtherMonths ? '' : ' ' + daySettings[1] + // highlight custom dates
8020 (printDate.getTime() == currentDate.getTime() ? ' ' + this._currentClass : '') + // highlight selected day
8021 (printDate.getTime() == today.getTime() ? ' ui-datepicker-today' : '')) + '"' + // highlight today (if different)
8022 ((!otherMonth || showOtherMonths) && daySettings[2] ? ' title="' + daySettings[2] + '"' : '') + // cell title
8023 (unselectable ? '' : ' data-handler="selectDay" data-event="click" data-month="' + printDate.getMonth() + '" data-year="' + printDate.getFullYear() + '"') + '>' + // actions
8024 (otherMonth && !showOtherMonths ? '&#xa0;' : // display for other months
8025 (unselectable ? '<span class="ui-state-default">' + printDate.getDate() + '</span>' : '<a class="ui-state-default' +
8026 (printDate.getTime() == today.getTime() ? ' ui-state-highlight' : '') +
8027 (printDate.getTime() == currentDate.getTime() ? ' ui-state-active' : '') + // highlight selected day
8028 (otherMonth ? ' ui-priority-secondary' : '') + // distinguish dates from other months
8029 '" href="#">' + printDate.getDate() + '</a>')) + '</td>'; // display selectable date
8030 printDate.setDate(printDate.getDate() + 1);
8031 printDate = this._daylightSavingAdjust(printDate);
8032 }
8033 calender += tbody + '</tr>';
8034 }
8035 drawMonth++;
8036 if (drawMonth > 11) {
8037 drawMonth = 0;
8038 drawYear++;
8039 }
8040 calender += '</tbody></table>' + (isMultiMonth ? '</div>' +
8041 ((numMonths[0] > 0 && col == numMonths[1]-1) ? '<div class="ui-datepicker-row-break"></div>' : '') : '');
8042 group += calender;
8043 }
8044 html += group;
8045 }
8046 html += buttonPanel + ($.ui.ie6 && !inst.inline ?
8047 '<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>' : '');
8048 inst._keyEvent = false;
8049 return html;
8050 },
8051
8052 /* Generate the month and year header. */
8053 _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
8054 secondary, monthNames, monthNamesShort) {
8055 var changeMonth = this._get(inst, 'changeMonth');
8056 var changeYear = this._get(inst, 'changeYear');
8057 var showMonthAfterYear = this._get(inst, 'showMonthAfterYear');
8058 var html = '<div class="ui-datepicker-title">';
8059 var monthHtml = '';
8060 // month selection
8061 if (secondary || !changeMonth)
8062 monthHtml += '<span class="ui-datepicker-month">' + monthNames[drawMonth] + '</span>';
8063 else {
8064 var inMinYear = (minDate && minDate.getFullYear() == drawYear);
8065 var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear);
8066 monthHtml += '<select class="ui-datepicker-month" data-handler="selectMonth" data-event="change">';
8067 for (var month = 0; month < 12; month++) {
8068 if ((!inMinYear || month >= minDate.getMonth()) &&
8069 (!inMaxYear || month <= maxDate.getMonth()))
8070 monthHtml += '<option value="' + month + '"' +
8071 (month == drawMonth ? ' selected="selected"' : '') +
8072 '>' + monthNamesShort[month] + '</option>';
8073 }
8074 monthHtml += '</select>';
8075 }
8076 if (!showMonthAfterYear)
8077 html += monthHtml + (secondary || !(changeMonth && changeYear) ? '&#xa0;' : '');
8078 // year selection
8079 if ( !inst.yearshtml ) {
8080 inst.yearshtml = '';
8081 if (secondary || !changeYear)
8082 html += '<span class="ui-datepicker-year">' + drawYear + '</span>';
8083 else {
8084 // determine range of years to display
8085 var years = this._get(inst, 'yearRange').split(':');
8086 var thisYear = new Date().getFullYear();
8087 var determineYear = function(value) {
8088 var year = (value.match(/c[+-].*/) ? drawYear + parseInt(value.substring(1), 10) :
8089 (value.match(/[+-].*/) ? thisYear + parseInt(value, 10) :
8090 parseInt(value, 10)));
8091 return (isNaN(year) ? thisYear : year);
8092 };
8093 var year = determineYear(years[0]);
8094 var endYear = Math.max(year, determineYear(years[1] || ''));
8095 year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
8096 endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
8097 inst.yearshtml += '<select class="ui-datepicker-year" data-handler="selectYear" data-event="change">';
8098 for (; year <= endYear; year++) {
8099 inst.yearshtml += '<option value="' + year + '"' +
8100 (year == drawYear ? ' selected="selected"' : '') +
8101 '>' + year + '</option>';
8102 }
8103 inst.yearshtml += '</select>';
8104
8105 html += inst.yearshtml;
8106 inst.yearshtml = null;
8107 }
8108 }
8109 html += this._get(inst, 'yearSuffix');
8110 if (showMonthAfterYear)
8111 html += (secondary || !(changeMonth && changeYear) ? '&#xa0;' : '') + monthHtml;
8112 html += '</div>'; // Close datepicker_header
8113 return html;
8114 },
8115
8116 /* Adjust one of the date sub-fields. */
8117 _adjustInstDate: function(inst, offset, period) {
8118 var year = inst.drawYear + (period == 'Y' ? offset : 0);
8119 var month = inst.drawMonth + (period == 'M' ? offset : 0);
8120 var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) +
8121 (period == 'D' ? offset : 0);
8122 var date = this._restrictMinMax(inst,
8123 this._daylightSavingAdjust(new Date(year, month, day)));
8124 inst.selectedDay = date.getDate();
8125 inst.drawMonth = inst.selectedMonth = date.getMonth();
8126 inst.drawYear = inst.selectedYear = date.getFullYear();
8127 if (period == 'M' || period == 'Y')
8128 this._notifyChange(inst);
8129 },
8130
8131 /* Ensure a date is within any min/max bounds. */
8132 _restrictMinMax: function(inst, date) {
8133 var minDate = this._getMinMaxDate(inst, 'min');
8134 var maxDate = this._getMinMaxDate(inst, 'max');
8135 var newDate = (minDate && date < minDate ? minDate : date);
8136 newDate = (maxDate && newDate > maxDate ? maxDate : newDate);
8137 return newDate;
8138 },
8139
8140 /* Notify change of month/year. */
8141 _notifyChange: function(inst) {
8142 var onChange = this._get(inst, 'onChangeMonthYear');
8143 if (onChange)
8144 onChange.apply((inst.input ? inst.input[0] : null),
8145 [inst.selectedYear, inst.selectedMonth + 1, inst]);
8146 },
8147
8148 /* Determine the number of months to show. */
8149 _getNumberOfMonths: function(inst) {
8150 var numMonths = this._get(inst, 'numberOfMonths');
8151 return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths));
8152 },
8153
8154 /* Determine the current maximum date - ensure no time components are set. */
8155 _getMinMaxDate: function(inst, minMax) {
8156 return this._determineDate(inst, this._get(inst, minMax + 'Date'), null);
8157 },
8158
8159 /* Find the number of days in a given month. */
8160 _getDaysInMonth: function(year, month) {
8161 return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
8162 },
8163
8164 /* Find the day of the week of the first of a month. */
8165 _getFirstDayOfMonth: function(year, month) {
8166 return new Date(year, month, 1).getDay();
8167 },
8168
8169 /* Determines if we should allow a "next/prev" month display change. */
8170 _canAdjustMonth: function(inst, offset, curYear, curMonth) {
8171 var numMonths = this._getNumberOfMonths(inst);
8172 var date = this._daylightSavingAdjust(new Date(curYear,
8173 curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
8174 if (offset < 0)
8175 date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
8176 return this._isInRange(inst, date);
8177 },
8178
8179 /* Is the given date in the accepted range? */
8180 _isInRange: function(inst, date) {
8181 var minDate = this._getMinMaxDate(inst, 'min');
8182 var maxDate = this._getMinMaxDate(inst, 'max');
8183 return ((!minDate || date.getTime() >= minDate.getTime()) &&
8184 (!maxDate || date.getTime() <= maxDate.getTime()));
8185 },
8186
8187 /* Provide the configuration settings for formatting/parsing. */
8188 _getFormatConfig: function(inst) {
8189 var shortYearCutoff = this._get(inst, 'shortYearCutoff');
8190 shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff :
8191 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
8192 return {shortYearCutoff: shortYearCutoff,
8193 dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'),
8194 monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')};
8195 },
8196
8197 /* Format the given date for display. */
8198 _formatDate: function(inst, day, month, year) {
8199 if (!day) {
8200 inst.currentDay = inst.selectedDay;
8201 inst.currentMonth = inst.selectedMonth;
8202 inst.currentYear = inst.selectedYear;
8203 }
8204 var date = (day ? (typeof day == 'object' ? day :
8205 this._daylightSavingAdjust(new Date(year, month, day))) :
8206 this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
8207 return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst));
8208 }
8209 });
8210
8211 /*
8212 * Bind hover events for datepicker elements.
8213 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
8214 * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
8215 */
8216 function bindHover(dpDiv) {
8217 var selector = 'button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a';
8218 return dpDiv.delegate(selector, 'mouseout', function() {
8219 $(this).removeClass('ui-state-hover');
8220 if (this.className.indexOf('ui-datepicker-prev') != -1) $(this).removeClass('ui-datepicker-prev-hover');
8221 if (this.className.indexOf('ui-datepicker-next') != -1) $(this).removeClass('ui-datepicker-next-hover');
8222 })
8223 .delegate(selector, 'mouseover', function(){
8224 if (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) {
8225 $(this).parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover');
8226 $(this).addClass('ui-state-hover');
8227 if (this.className.indexOf('ui-datepicker-prev') != -1) $(this).addClass('ui-datepicker-prev-hover');
8228 if (this.className.indexOf('ui-datepicker-next') != -1) $(this).addClass('ui-datepicker-next-hover');
8229 }
8230 });
8231 }
8232
8233 /* jQuery extend now ignores nulls! */
8234 function extendRemove(target, props) {
8235 $.extend(target, props);
8236 for (var name in props)
8237 if (props[name] == null || props[name] == undefined)
8238 target[name] = props[name];
8239 return target;
8240 };
8241
8242 /* Invoke the datepicker functionality.
8243 @param options string - a command, optionally followed by additional parameters or
8244 Object - settings for attaching new datepicker functionality
8245 @return jQuery object */
8246 $.fn.datepicker = function(options){
8247
8248 /* Verify an empty collection wasn't passed - Fixes #6976 */
8249 if ( !this.length ) {
8250 return this;
8251 }
8252
8253 /* Initialise the date picker. */
8254 if (!$.datepicker.initialized) {
8255 $(document).mousedown($.datepicker._checkExternalClick).
8256 find(document.body).append($.datepicker.dpDiv);
8257 $.datepicker.initialized = true;
8258 }
8259
8260 var otherArgs = Array.prototype.slice.call(arguments, 1);
8261 if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate' || options == 'widget'))
8262 return $.datepicker['_' + options + 'Datepicker'].
8263 apply($.datepicker, [this[0]].concat(otherArgs));
8264 if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string')
8265 return $.datepicker['_' + options + 'Datepicker'].
8266 apply($.datepicker, [this[0]].concat(otherArgs));
8267 return this.each(function() {
8268 typeof options == 'string' ?
8269 $.datepicker['_' + options + 'Datepicker'].
8270 apply($.datepicker, [this].concat(otherArgs)) :
8271 $.datepicker._attachDatepicker(this, options);
8272 });
8273 };
8274
8275 $.datepicker = new Datepicker(); // singleton instance
8276 $.datepicker.initialized = false;
8277 $.datepicker.uuid = new Date().getTime();
8278 $.datepicker.version = "1.9.2";
8279
8280 // Workaround for #4055
8281 // Add another global to avoid noConflict issues with inline event handlers
8282 window['DP_jQuery_' + dpuuid] = $;
8283
8284 })(jQuery);
8285 (function( $, undefined ) {
8286
8287 var uiDialogClasses = "ui-dialog ui-widget ui-widget-content ui-corner-all ",
8288 sizeRelatedOptions = {
8289 buttons: true,
8290 height: true,
8291 maxHeight: true,
8292 maxWidth: true,
8293 minHeight: true,
8294 minWidth: true,
8295 width: true
8296 },
8297 resizableRelatedOptions = {
8298 maxHeight: true,
8299 maxWidth: true,
8300 minHeight: true,
8301 minWidth: true
8302 };
8303
8304 $.widget("ui.dialog", {
8305 version: "1.9.2",
8306 options: {
8307 autoOpen: true,
8308 buttons: {},
8309 closeOnEscape: true,
8310 closeText: "close",
8311 dialogClass: "",
8312 draggable: true,
8313 hide: null,
8314 height: "auto",
8315 maxHeight: false,
8316 maxWidth: false,
8317 minHeight: 150,
8318 minWidth: 150,
8319 modal: false,
8320 position: {
8321 my: "center",
8322 at: "center",
8323 of: window,
8324 collision: "fit",
8325 // ensure that the titlebar is never outside the document
8326 using: function( pos ) {
8327 var topOffset = $( this ).css( pos ).offset().top;
8328 if ( topOffset < 0 ) {
8329 $( this ).css( "top", pos.top - topOffset );
8330 }
8331 }
8332 },
8333 resizable: true,
8334 show: null,
8335 stack: true,
8336 title: "",
8337 width: 300,
8338 zIndex: 1000
8339 },
8340
8341 _create: function() {
8342 this.originalTitle = this.element.attr( "title" );
8343 // #5742 - .attr() might return a DOMElement
8344 if ( typeof this.originalTitle !== "string" ) {
8345 this.originalTitle = "";
8346 }
8347 this.oldPosition = {
8348 parent: this.element.parent(),
8349 index: this.element.parent().children().index( this.element )
8350 };
8351 this.options.title = this.options.title || this.originalTitle;
8352 var that = this,
8353 options = this.options,
8354
8355 title = options.title || "&#160;",
8356 uiDialog,
8357 uiDialogTitlebar,
8358 uiDialogTitlebarClose,
8359 uiDialogTitle,
8360 uiDialogButtonPane;
8361
8362 uiDialog = ( this.uiDialog = $( "<div>" ) )
8363 .addClass( uiDialogClasses + options.dialogClass )
8364 .css({
8365 display: "none",
8366 outline: 0, // TODO: move to stylesheet
8367 zIndex: options.zIndex
8368 })
8369 // setting tabIndex makes the div focusable
8370 .attr( "tabIndex", -1)
8371 .keydown(function( event ) {
8372 if ( options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
8373 event.keyCode === $.ui.keyCode.ESCAPE ) {
8374 that.close( event );
8375 event.preventDefault();
8376 }
8377 })
8378 .mousedown(function( event ) {
8379 that.moveToTop( false, event );
8380 })
8381 .appendTo( "body" );
8382
8383 this.element
8384 .show()
8385 .removeAttr( "title" )
8386 .addClass( "ui-dialog-content ui-widget-content" )
8387 .appendTo( uiDialog );
8388
8389 uiDialogTitlebar = ( this.uiDialogTitlebar = $( "<div>" ) )
8390 .addClass( "ui-dialog-titlebar ui-widget-header " +
8391 "ui-corner-all ui-helper-clearfix" )
8392 .bind( "mousedown", function() {
8393 // Dialog isn't getting focus when dragging (#8063)
8394 uiDialog.focus();
8395 })
8396 .prependTo( uiDialog );
8397
8398 uiDialogTitlebarClose = $( "<a href='#'></a>" )
8399 .addClass( "ui-dialog-titlebar-close ui-corner-all" )
8400 .attr( "role", "button" )
8401 .click(function( event ) {
8402 event.preventDefault();
8403 that.close( event );
8404 })
8405 .appendTo( uiDialogTitlebar );
8406
8407 ( this.uiDialogTitlebarCloseText = $( "<span>" ) )
8408 .addClass( "ui-icon ui-icon-closethick" )
8409 .text( options.closeText )
8410 .appendTo( uiDialogTitlebarClose );
8411
8412 uiDialogTitle = $( "<span>" )
8413 .uniqueId()
8414 .addClass( "ui-dialog-title" )
8415 .html( title )
8416 .prependTo( uiDialogTitlebar );
8417
8418 uiDialogButtonPane = ( this.uiDialogButtonPane = $( "<div>" ) )
8419 .addClass( "ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" );
8420
8421 ( this.uiButtonSet = $( "<div>" ) )
8422 .addClass( "ui-dialog-buttonset" )
8423 .appendTo( uiDialogButtonPane );
8424
8425 uiDialog.attr({
8426 role: "dialog",
8427 "aria-labelledby": uiDialogTitle.attr( "id" )
8428 });
8429
8430 uiDialogTitlebar.find( "*" ).add( uiDialogTitlebar ).disableSelection();
8431 this._hoverable( uiDialogTitlebarClose );
8432 this._focusable( uiDialogTitlebarClose );
8433
8434 if ( options.draggable && $.fn.draggable ) {
8435 this._makeDraggable();
8436 }
8437 if ( options.resizable && $.fn.resizable ) {
8438 this._makeResizable();
8439 }
8440
8441 this._createButtons( options.buttons );
8442 this._isOpen = false;
8443
8444 if ( $.fn.bgiframe ) {
8445 uiDialog.bgiframe();
8446 }
8447
8448 // prevent tabbing out of modal dialogs
8449 this._on( uiDialog, { keydown: function( event ) {
8450 if ( !options.modal || event.keyCode !== $.ui.keyCode.TAB ) {
8451 return;
8452 }
8453
8454 var tabbables = $( ":tabbable", uiDialog ),
8455 first = tabbables.filter( ":first" ),
8456 last = tabbables.filter( ":last" );
8457
8458 if ( event.target === last[0] && !event.shiftKey ) {
8459 first.focus( 1 );
8460 return false;
8461 } else if ( event.target === first[0] && event.shiftKey ) {
8462 last.focus( 1 );
8463 return false;
8464 }
8465 }});
8466 },
8467
8468 _init: function() {
8469 if ( this.options.autoOpen ) {
8470 this.open();
8471 }
8472 },
8473
8474 _destroy: function() {
8475 var next,
8476 oldPosition = this.oldPosition;
8477
8478 if ( this.overlay ) {
8479 this.overlay.destroy();
8480 }
8481 this.uiDialog.hide();
8482 this.element
8483 .removeClass( "ui-dialog-content ui-widget-content" )
8484 .hide()
8485 .appendTo( "body" );
8486 this.uiDialog.remove();
8487
8488 if ( this.originalTitle ) {
8489 this.element.attr( "title", this.originalTitle );
8490 }
8491
8492 next = oldPosition.parent.children().eq( oldPosition.index );
8493 // Don't try to place the dialog next to itself (#8613)
8494 if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
8495 next.before( this.element );
8496 } else {
8497 oldPosition.parent.append( this.element );
8498 }
8499 },
8500
8501 widget: function() {
8502 return this.uiDialog;
8503 },
8504
8505 close: function( event ) {
8506 var that = this,
8507 maxZ, thisZ;
8508
8509 if ( !this._isOpen ) {
8510 return;
8511 }
8512
8513 if ( false === this._trigger( "beforeClose", event ) ) {
8514 return;
8515 }
8516
8517 this._isOpen = false;
8518
8519 if ( this.overlay ) {
8520 this.overlay.destroy();
8521 }
8522
8523 if ( this.options.hide ) {
8524 this._hide( this.uiDialog, this.options.hide, function() {
8525 that._trigger( "close", event );
8526 });
8527 } else {
8528 this.uiDialog.hide();
8529 this._trigger( "close", event );
8530 }
8531
8532 $.ui.dialog.overlay.resize();
8533
8534 // adjust the maxZ to allow other modal dialogs to continue to work (see #4309)
8535 if ( this.options.modal ) {
8536 maxZ = 0;
8537 $( ".ui-dialog" ).each(function() {
8538 if ( this !== that.uiDialog[0] ) {
8539 thisZ = $( this ).css( "z-index" );
8540 if ( !isNaN( thisZ ) ) {
8541 maxZ = Math.max( maxZ, thisZ );
8542 }
8543 }
8544 });
8545 $.ui.dialog.maxZ = maxZ;
8546 }
8547
8548 return this;
8549 },
8550
8551 isOpen: function() {
8552 return this._isOpen;
8553 },
8554
8555 // the force parameter allows us to move modal dialogs to their correct
8556 // position on open
8557 moveToTop: function( force, event ) {
8558 var options = this.options,
8559 saveScroll;
8560
8561 if ( ( options.modal && !force ) ||
8562 ( !options.stack && !options.modal ) ) {
8563 return this._trigger( "focus", event );
8564 }
8565
8566 if ( options.zIndex > $.ui.dialog.maxZ ) {
8567 $.ui.dialog.maxZ = options.zIndex;
8568 }
8569 if ( this.overlay ) {
8570 $.ui.dialog.maxZ += 1;
8571 $.ui.dialog.overlay.maxZ = $.ui.dialog.maxZ;
8572 this.overlay.$el.css( "z-index", $.ui.dialog.overlay.maxZ );
8573 }
8574
8575 // Save and then restore scroll
8576 // Opera 9.5+ resets when parent z-index is changed.
8577 // http://bugs.jqueryui.com/ticket/3193
8578 saveScroll = {
8579 scrollTop: this.element.scrollTop(),
8580 scrollLeft: this.element.scrollLeft()
8581 };
8582 $.ui.dialog.maxZ += 1;
8583 this.uiDialog.css( "z-index", $.ui.dialog.maxZ );
8584 this.element.attr( saveScroll );
8585 this._trigger( "focus", event );
8586
8587 return this;
8588 },
8589
8590 open: function() {
8591 if ( this._isOpen ) {
8592 return;
8593 }
8594
8595 var hasFocus,
8596 options = this.options,
8597 uiDialog = this.uiDialog;
8598
8599 this._size();
8600 this._position( options.position );
8601 uiDialog.show( options.show );
8602 this.overlay = options.modal ? new $.ui.dialog.overlay( this ) : null;
8603 this.moveToTop( true );
8604
8605 // set focus to the first tabbable element in the content area or the first button
8606 // if there are no tabbable elements, set focus on the dialog itself
8607 hasFocus = this.element.find( ":tabbable" );
8608 if ( !hasFocus.length ) {
8609 hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
8610 if ( !hasFocus.length ) {
8611 hasFocus = uiDialog;
8612 }
8613 }
8614 hasFocus.eq( 0 ).focus();
8615
8616 this._isOpen = true;
8617 this._trigger( "open" );
8618
8619 return this;
8620 },
8621
8622 _createButtons: function( buttons ) {
8623 var that = this,
8624 hasButtons = false;
8625
8626 // if we already have a button pane, remove it
8627 this.uiDialogButtonPane.remove();
8628 this.uiButtonSet.empty();
8629
8630 if ( typeof buttons === "object" && buttons !== null ) {
8631 $.each( buttons, function() {
8632 return !(hasButtons = true);
8633 });
8634 }
8635 if ( hasButtons ) {
8636 $.each( buttons, function( name, props ) {
8637 var button, click;
8638 props = $.isFunction( props ) ?
8639 { click: props, text: name } :
8640 props;
8641 // Default to a non-submitting button
8642 props = $.extend( { type: "button" }, props );
8643 // Change the context for the click callback to be the main element
8644 click = props.click;
8645 props.click = function() {
8646 click.apply( that.element[0], arguments );
8647 };
8648 button = $( "<button></button>", props )
8649 .appendTo( that.uiButtonSet );
8650 if ( $.fn.button ) {
8651 button.button();
8652 }
8653 });
8654 this.uiDialog.addClass( "ui-dialog-buttons" );
8655 this.uiDialogButtonPane.appendTo( this.uiDialog );
8656 } else {
8657 this.uiDialog.removeClass( "ui-dialog-buttons" );
8658 }
8659 },
8660
8661 _makeDraggable: function() {
8662 var that = this,
8663 options = this.options;
8664
8665 function filteredUi( ui ) {
8666 return {
8667 position: ui.position,
8668 offset: ui.offset
8669 };
8670 }
8671
8672 this.uiDialog.draggable({
8673 cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
8674 handle: ".ui-dialog-titlebar",
8675 containment: "document",
8676 start: function( event, ui ) {
8677 $( this )
8678 .addClass( "ui-dialog-dragging" );
8679 that._trigger( "dragStart", event, filteredUi( ui ) );
8680 },
8681 drag: function( event, ui ) {
8682 that._trigger( "drag", event, filteredUi( ui ) );
8683 },
8684 stop: function( event, ui ) {
8685 options.position = [
8686 ui.position.left - that.document.scrollLeft(),
8687 ui.position.top - that.document.scrollTop()
8688 ];
8689 $( this )
8690 .removeClass( "ui-dialog-dragging" );
8691 that._trigger( "dragStop", event, filteredUi( ui ) );
8692 $.ui.dialog.overlay.resize();
8693 }
8694 });
8695 },
8696
8697 _makeResizable: function( handles ) {
8698 handles = (handles === undefined ? this.options.resizable : handles);
8699 var that = this,
8700 options = this.options,
8701 // .ui-resizable has position: relative defined in the stylesheet
8702 // but dialogs have to use absolute or fixed positioning
8703 position = this.uiDialog.css( "position" ),
8704 resizeHandles = typeof handles === 'string' ?
8705 handles :
8706 "n,e,s,w,se,sw,ne,nw";
8707
8708 function filteredUi( ui ) {
8709 return {
8710 originalPosition: ui.originalPosition,
8711 originalSize: ui.originalSize,
8712 position: ui.position,
8713 size: ui.size
8714 };
8715 }
8716
8717 this.uiDialog.resizable({
8718 cancel: ".ui-dialog-content",
8719 containment: "document",
8720 alsoResize: this.element,
8721 maxWidth: options.maxWidth,
8722 maxHeight: options.maxHeight,
8723 minWidth: options.minWidth,
8724 minHeight: this._minHeight(),
8725 handles: resizeHandles,
8726 start: function( event, ui ) {
8727 $( this ).addClass( "ui-dialog-resizing" );
8728 that._trigger( "resizeStart", event, filteredUi( ui ) );
8729 },
8730 resize: function( event, ui ) {
8731 that._trigger( "resize", event, filteredUi( ui ) );
8732 },
8733 stop: function( event, ui ) {
8734 $( this ).removeClass( "ui-dialog-resizing" );
8735 options.height = $( this ).height();
8736 options.width = $( this ).width();
8737 that._trigger( "resizeStop", event, filteredUi( ui ) );
8738 $.ui.dialog.overlay.resize();
8739 }
8740 })
8741 .css( "position", position )
8742 .find( ".ui-resizable-se" )
8743 .addClass( "ui-icon ui-icon-grip-diagonal-se" );
8744 },
8745
8746 _minHeight: function() {
8747 var options = this.options;
8748
8749 if ( options.height === "auto" ) {
8750 return options.minHeight;
8751 } else {
8752 return Math.min( options.minHeight, options.height );
8753 }
8754 },
8755
8756 _position: function( position ) {
8757 var myAt = [],
8758 offset = [ 0, 0 ],
8759 isVisible;
8760
8761 if ( position ) {
8762 // deep extending converts arrays to objects in jQuery <= 1.3.2 :-(
8763 // if (typeof position == 'string' || $.isArray(position)) {
8764 // myAt = $.isArray(position) ? position : position.split(' ');
8765
8766 if ( typeof position === "string" || (typeof position === "object" && "0" in position ) ) {
8767 myAt = position.split ? position.split( " " ) : [ position[ 0 ], position[ 1 ] ];
8768 if ( myAt.length === 1 ) {
8769 myAt[ 1 ] = myAt[ 0 ];
8770 }
8771
8772 $.each( [ "left", "top" ], function( i, offsetPosition ) {
8773 if ( +myAt[ i ] === myAt[ i ] ) {
8774 offset[ i ] = myAt[ i ];
8775 myAt[ i ] = offsetPosition;
8776 }
8777 });
8778
8779 position = {
8780 my: myAt[0] + (offset[0] < 0 ? offset[0] : "+" + offset[0]) + " " +
8781 myAt[1] + (offset[1] < 0 ? offset[1] : "+" + offset[1]),
8782 at: myAt.join( " " )
8783 };
8784 }
8785
8786 position = $.extend( {}, $.ui.dialog.prototype.options.position, position );
8787 } else {
8788 position = $.ui.dialog.prototype.options.position;
8789 }
8790
8791 // need to show the dialog to get the actual offset in the position plugin
8792 isVisible = this.uiDialog.is( ":visible" );
8793 if ( !isVisible ) {
8794 this.uiDialog.show();
8795 }
8796 this.uiDialog.position( position );
8797 if ( !isVisible ) {
8798 this.uiDialog.hide();
8799 }
8800 },
8801
8802 _setOptions: function( options ) {
8803 var that = this,
8804 resizableOptions = {},
8805 resize = false;
8806
8807 $.each( options, function( key, value ) {
8808 that._setOption( key, value );
8809
8810 if ( key in sizeRelatedOptions ) {
8811 resize = true;
8812 }
8813 if ( key in resizableRelatedOptions ) {
8814 resizableOptions[ key ] = value;
8815 }
8816 });
8817
8818 if ( resize ) {
8819 this._size();
8820 }
8821 if ( this.uiDialog.is( ":data(resizable)" ) ) {
8822 this.uiDialog.resizable( "option", resizableOptions );
8823 }
8824 },
8825
8826 _setOption: function( key, value ) {
8827 var isDraggable, isResizable,
8828 uiDialog = this.uiDialog;
8829
8830 switch ( key ) {
8831 case "buttons":
8832 this._createButtons( value );
8833 break;
8834 case "closeText":
8835 // ensure that we always pass a string
8836 this.uiDialogTitlebarCloseText.text( "" + value );
8837 break;
8838 case "dialogClass":
8839 uiDialog
8840 .removeClass( this.options.dialogClass )
8841 .addClass( uiDialogClasses + value );
8842 break;
8843 case "disabled":
8844 if ( value ) {
8845 uiDialog.addClass( "ui-dialog-disabled" );
8846 } else {
8847 uiDialog.removeClass( "ui-dialog-disabled" );
8848 }
8849 break;
8850 case "draggable":
8851 isDraggable = uiDialog.is( ":data(draggable)" );
8852 if ( isDraggable && !value ) {
8853 uiDialog.draggable( "destroy" );
8854 }
8855
8856 if ( !isDraggable && value ) {
8857 this._makeDraggable();
8858 }
8859 break;
8860 case "position":
8861 this._position( value );
8862 break;
8863 case "resizable":
8864 // currently resizable, becoming non-resizable
8865 isResizable = uiDialog.is( ":data(resizable)" );
8866 if ( isResizable && !value ) {
8867 uiDialog.resizable( "destroy" );
8868 }
8869
8870 // currently resizable, changing handles
8871 if ( isResizable && typeof value === "string" ) {
8872 uiDialog.resizable( "option", "handles", value );
8873 }
8874
8875 // currently non-resizable, becoming resizable
8876 if ( !isResizable && value !== false ) {
8877 this._makeResizable( value );
8878 }
8879 break;
8880 case "title":
8881 // convert whatever was passed in o a string, for html() to not throw up
8882 $( ".ui-dialog-title", this.uiDialogTitlebar )
8883 .html( "" + ( value || "&#160;" ) );
8884 break;
8885 }
8886
8887 this._super( key, value );
8888 },
8889
8890 _size: function() {
8891 /* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
8892 * divs will both have width and height set, so we need to reset them
8893 */
8894 var nonContentHeight, minContentHeight, autoHeight,
8895 options = this.options,
8896 isVisible = this.uiDialog.is( ":visible" );
8897
8898 // reset content sizing
8899 this.element.show().css({
8900 width: "auto",
8901 minHeight: 0,
8902 height: 0
8903 });
8904
8905 if ( options.minWidth > options.width ) {
8906 options.width = options.minWidth;
8907 }
8908
8909 // reset wrapper sizing
8910 // determine the height of all the non-content elements
8911 nonContentHeight = this.uiDialog.css({
8912 height: "auto",
8913 width: options.width
8914 })
8915 .outerHeight();
8916 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
8917
8918 if ( options.height === "auto" ) {
8919 // only needed for IE6 support
8920 if ( $.support.minHeight ) {
8921 this.element.css({
8922 minHeight: minContentHeight,
8923 height: "auto"
8924 });
8925 } else {
8926 this.uiDialog.show();
8927 autoHeight = this.element.css( "height", "auto" ).height();
8928 if ( !isVisible ) {
8929 this.uiDialog.hide();
8930 }
8931 this.element.height( Math.max( autoHeight, minContentHeight ) );
8932 }
8933 } else {
8934 this.element.height( Math.max( options.height - nonContentHeight, 0 ) );
8935 }
8936
8937 if (this.uiDialog.is( ":data(resizable)" ) ) {
8938 this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
8939 }
8940 }
8941 });
8942
8943 $.extend($.ui.dialog, {
8944 uuid: 0,
8945 maxZ: 0,
8946
8947 getTitleId: function($el) {
8948 var id = $el.attr( "id" );
8949 if ( !id ) {
8950 this.uuid += 1;
8951 id = this.uuid;
8952 }
8953 return "ui-dialog-title-" + id;
8954 },
8955
8956 overlay: function( dialog ) {
8957 this.$el = $.ui.dialog.overlay.create( dialog );
8958 }
8959 });
8960
8961 $.extend( $.ui.dialog.overlay, {
8962 instances: [],
8963 // reuse old instances due to IE memory leak with alpha transparency (see #5185)
8964 oldInstances: [],
8965 maxZ: 0,
8966 events: $.map(
8967 "focus,mousedown,mouseup,keydown,keypress,click".split( "," ),
8968 function( event ) {
8969 return event + ".dialog-overlay";
8970 }
8971 ).join( " " ),
8972 create: function( dialog ) {
8973 if ( this.instances.length === 0 ) {
8974 // prevent use of anchors and inputs
8975 // we use a setTimeout in case the overlay is created from an
8976 // event that we're going to be cancelling (see #2804)
8977 setTimeout(function() {
8978 // handle $(el).dialog().dialog('close') (see #4065)
8979 if ( $.ui.dialog.overlay.instances.length ) {
8980 $( document ).bind( $.ui.dialog.overlay.events, function( event ) {
8981 // stop events if the z-index of the target is < the z-index of the overlay
8982 // we cannot return true when we don't want to cancel the event (#3523)
8983 if ( $( event.target ).zIndex() < $.ui.dialog.overlay.maxZ ) {
8984 return false;
8985 }
8986 });
8987 }
8988 }, 1 );
8989
8990 // handle window resize
8991 $( window ).bind( "resize.dialog-overlay", $.ui.dialog.overlay.resize );
8992 }
8993
8994 var $el = ( this.oldInstances.pop() || $( "<div>" ).addClass( "ui-widget-overlay" ) );
8995
8996 // allow closing by pressing the escape key
8997 $( document ).bind( "keydown.dialog-overlay", function( event ) {
8998 var instances = $.ui.dialog.overlay.instances;
8999 // only react to the event if we're the top overlay
9000 if ( instances.length !== 0 && instances[ instances.length - 1 ] === $el &&
9001 dialog.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
9002 event.keyCode === $.ui.keyCode.ESCAPE ) {
9003
9004 dialog.close( event );
9005 event.preventDefault();
9006 }
9007 });
9008
9009 $el.appendTo( document.body ).css({
9010 width: this.width(),
9011 height: this.height()
9012 });
9013
9014 if ( $.fn.bgiframe ) {
9015 $el.bgiframe();
9016 }
9017
9018 this.instances.push( $el );
9019 return $el;
9020 },
9021
9022 destroy: function( $el ) {
9023 var indexOf = $.inArray( $el, this.instances ),
9024 maxZ = 0;
9025
9026 if ( indexOf !== -1 ) {
9027 this.oldInstances.push( this.instances.splice( indexOf, 1 )[ 0 ] );
9028 }
9029
9030 if ( this.instances.length === 0 ) {
9031 $( [ document, window ] ).unbind( ".dialog-overlay" );
9032 }
9033
9034 $el.height( 0 ).width( 0 ).remove();
9035
9036 // adjust the maxZ to allow other modal dialogs to continue to work (see #4309)
9037 $.each( this.instances, function() {
9038 maxZ = Math.max( maxZ, this.css( "z-index" ) );
9039 });
9040 this.maxZ = maxZ;
9041 },
9042
9043 height: function() {
9044 var scrollHeight,
9045 offsetHeight;
9046 // handle IE
9047 if ( $.ui.ie ) {
9048 scrollHeight = Math.max(
9049 document.documentElement.scrollHeight,
9050 document.body.scrollHeight
9051 );
9052 offsetHeight = Math.max(
9053 document.documentElement.offsetHeight,
9054 document.body.offsetHeight
9055 );
9056
9057 if ( scrollHeight < offsetHeight ) {
9058 return $( window ).height() + "px";
9059 } else {
9060 return scrollHeight + "px";
9061 }
9062 // handle "good" browsers
9063 } else {
9064 return $( document ).height() + "px";
9065 }
9066 },
9067
9068 width: function() {
9069 var scrollWidth,
9070 offsetWidth;
9071 // handle IE
9072 if ( $.ui.ie ) {
9073 scrollWidth = Math.max(
9074 document.documentElement.scrollWidth,
9075 document.body.scrollWidth
9076 );
9077 offsetWidth = Math.max(
9078 document.documentElement.offsetWidth,
9079 document.body.offsetWidth
9080 );
9081
9082 if ( scrollWidth < offsetWidth ) {
9083 return $( window ).width() + "px";
9084 } else {
9085 return scrollWidth + "px";
9086 }
9087 // handle "good" browsers
9088 } else {
9089 return $( document ).width() + "px";
9090 }
9091 },
9092
9093 resize: function() {
9094 /* If the dialog is draggable and the user drags it past the
9095 * right edge of the window, the document becomes wider so we
9096 * need to stretch the overlay. If the user then drags the
9097 * dialog back to the left, the document will become narrower,
9098 * so we need to shrink the overlay to the appropriate size.
9099 * This is handled by shrinking the overlay before setting it
9100 * to the full document size.
9101 */
9102 var $overlays = $( [] );
9103 $.each( $.ui.dialog.overlay.instances, function() {
9104 $overlays = $overlays.add( this );
9105 });
9106
9107 $overlays.css({
9108 width: 0,
9109 height: 0
9110 }).css({
9111 width: $.ui.dialog.overlay.width(),
9112 height: $.ui.dialog.overlay.height()
9113 });
9114 }
9115 });
9116
9117 $.extend( $.ui.dialog.overlay.prototype, {
9118 destroy: function() {
9119 $.ui.dialog.overlay.destroy( this.$el );
9120 }
9121 });
9122
9123 }( jQuery ) );
9124 (function( $, undefined ) {
9125
9126 var mouseHandled = false;
9127
9128 $.widget( "ui.menu", {
9129 version: "1.9.2",
9130 defaultElement: "<ul>",
9131 delay: 300,
9132 options: {
9133 icons: {
9134 submenu: "ui-icon-carat-1-e"
9135 },
9136 menus: "ul",
9137 position: {
9138 my: "left top",
9139 at: "right top"
9140 },
9141 role: "menu",
9142
9143 // callbacks
9144 blur: null,
9145 focus: null,
9146 select: null
9147 },
9148
9149 _create: function() {
9150 this.activeMenu = this.element;
9151 this.element
9152 .uniqueId()
9153 .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
9154 .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
9155 .attr({
9156 role: this.options.role,
9157 tabIndex: 0
9158 })
9159 // need to catch all clicks on disabled menu
9160 // not possible through _on
9161 .bind( "click" + this.eventNamespace, $.proxy(function( event ) {
9162 if ( this.options.disabled ) {
9163 event.preventDefault();
9164 }
9165 }, this ));
9166
9167 if ( this.options.disabled ) {
9168 this.element
9169 .addClass( "ui-state-disabled" )
9170 .attr( "aria-disabled", "true" );
9171 }
9172
9173 this._on({
9174 // Prevent focus from sticking to links inside menu after clicking
9175 // them (focus should always stay on UL during navigation).
9176 "mousedown .ui-menu-item > a": function( event ) {
9177 event.preventDefault();
9178 },
9179 "click .ui-state-disabled > a": function( event ) {
9180 event.preventDefault();
9181 },
9182 "click .ui-menu-item:has(a)": function( event ) {
9183 var target = $( event.target ).closest( ".ui-menu-item" );
9184 if ( !mouseHandled && target.not( ".ui-state-disabled" ).length ) {
9185 mouseHandled = true;
9186
9187 this.select( event );
9188 // Open submenu on click
9189 if ( target.has( ".ui-menu" ).length ) {
9190 this.expand( event );
9191 } else if ( !this.element.is( ":focus" ) ) {
9192 // Redirect focus to the menu
9193 this.element.trigger( "focus", [ true ] );
9194
9195 // If the active item is on the top level, let it stay active.
9196 // Otherwise, blur the active item since it is no longer visible.
9197 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
9198 clearTimeout( this.timer );
9199 }
9200 }
9201 }
9202 },
9203 "mouseenter .ui-menu-item": function( event ) {
9204 var target = $( event.currentTarget );
9205 // Remove ui-state-active class from siblings of the newly focused menu item
9206 // to avoid a jump caused by adjacent elements both having a class with a border
9207 target.siblings().children( ".ui-state-active" ).removeClass( "ui-state-active" );
9208 this.focus( event, target );
9209 },
9210 mouseleave: "collapseAll",
9211 "mouseleave .ui-menu": "collapseAll",
9212 focus: function( event, keepActiveItem ) {
9213 // If there's already an active item, keep it active
9214 // If not, activate the first item
9215 var item = this.active || this.element.children( ".ui-menu-item" ).eq( 0 );
9216
9217 if ( !keepActiveItem ) {
9218 this.focus( event, item );
9219 }
9220 },
9221 blur: function( event ) {
9222 this._delay(function() {
9223 if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
9224 this.collapseAll( event );
9225 }
9226 });
9227 },
9228 keydown: "_keydown"
9229 });
9230
9231 this.refresh();
9232
9233 // Clicks outside of a menu collapse any open menus
9234 this._on( this.document, {
9235 click: function( event ) {
9236 if ( !$( event.target ).closest( ".ui-menu" ).length ) {
9237 this.collapseAll( event );
9238 }
9239
9240 // Reset the mouseHandled flag
9241 mouseHandled = false;
9242 }
9243 });
9244 },
9245
9246 _destroy: function() {
9247 // Destroy (sub)menus
9248 this.element
9249 .removeAttr( "aria-activedescendant" )
9250 .find( ".ui-menu" ).andSelf()
9251 .removeClass( "ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons" )
9252 .removeAttr( "role" )
9253 .removeAttr( "tabIndex" )
9254 .removeAttr( "aria-labelledby" )
9255 .removeAttr( "aria-expanded" )
9256 .removeAttr( "aria-hidden" )
9257 .removeAttr( "aria-disabled" )
9258 .removeUniqueId()
9259 .show();
9260
9261 // Destroy menu items
9262 this.element.find( ".ui-menu-item" )
9263 .removeClass( "ui-menu-item" )
9264 .removeAttr( "role" )
9265 .removeAttr( "aria-disabled" )
9266 .children( "a" )
9267 .removeUniqueId()
9268 .removeClass( "ui-corner-all ui-state-hover" )
9269 .removeAttr( "tabIndex" )
9270 .removeAttr( "role" )
9271 .removeAttr( "aria-haspopup" )
9272 .children().each( function() {
9273 var elem = $( this );
9274 if ( elem.data( "ui-menu-submenu-carat" ) ) {
9275 elem.remove();
9276 }
9277 });
9278
9279 // Destroy menu dividers
9280 this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
9281 },
9282
9283 _keydown: function( event ) {
9284 var match, prev, character, skip, regex,
9285 preventDefault = true;
9286
9287 function escape( value ) {
9288 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
9289 }
9290
9291 switch ( event.keyCode ) {
9292 case $.ui.keyCode.PAGE_UP:
9293 this.previousPage( event );
9294 break;
9295 case $.ui.keyCode.PAGE_DOWN:
9296 this.nextPage( event );
9297 break;
9298 case $.ui.keyCode.HOME:
9299 this._move( "first", "first", event );
9300 break;
9301 case $.ui.keyCode.END:
9302 this._move( "last", "last", event );
9303 break;
9304 case $.ui.keyCode.UP:
9305 this.previous( event );
9306 break;
9307 case $.ui.keyCode.DOWN:
9308 this.next( event );
9309 break;
9310 case $.ui.keyCode.LEFT:
9311 this.collapse( event );
9312 break;
9313 case $.ui.keyCode.RIGHT:
9314 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
9315 this.expand( event );
9316 }
9317 break;
9318 case $.ui.keyCode.ENTER:
9319 case $.ui.keyCode.SPACE:
9320 this._activate( event );
9321 break;
9322 case $.ui.keyCode.ESCAPE:
9323 this.collapse( event );
9324 break;
9325 default:
9326 preventDefault = false;
9327 prev = this.previousFilter || "";
9328 character = String.fromCharCode( event.keyCode );
9329 skip = false;
9330
9331 clearTimeout( this.filterTimer );
9332
9333 if ( character === prev ) {
9334 skip = true;
9335 } else {
9336 character = prev + character;
9337 }
9338
9339 regex = new RegExp( "^" + escape( character ), "i" );
9340 match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
9341 return regex.test( $( this ).children( "a" ).text() );
9342 });
9343 match = skip && match.index( this.active.next() ) !== -1 ?
9344 this.active.nextAll( ".ui-menu-item" ) :
9345 match;
9346
9347 // If no matches on the current filter, reset to the last character pressed
9348 // to move down the menu to the first item that starts with that character
9349 if ( !match.length ) {
9350 character = String.fromCharCode( event.keyCode );
9351 regex = new RegExp( "^" + escape( character ), "i" );
9352 match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
9353 return regex.test( $( this ).children( "a" ).text() );
9354 });
9355 }
9356
9357 if ( match.length ) {
9358 this.focus( event, match );
9359 if ( match.length > 1 ) {
9360 this.previousFilter = character;
9361 this.filterTimer = this._delay(function() {
9362 delete this.previousFilter;
9363 }, 1000 );
9364 } else {
9365 delete this.previousFilter;
9366 }
9367 } else {
9368 delete this.previousFilter;
9369 }
9370 }
9371
9372 if ( preventDefault ) {
9373 event.preventDefault();
9374 }
9375 },
9376
9377 _activate: function( event ) {
9378 if ( !this.active.is( ".ui-state-disabled" ) ) {
9379 if ( this.active.children( "a[aria-haspopup='true']" ).length ) {
9380 this.expand( event );
9381 } else {
9382 this.select( event );
9383 }
9384 }
9385 },
9386
9387 refresh: function() {
9388 var menus,
9389 icon = this.options.icons.submenu,
9390 submenus = this.element.find( this.options.menus );
9391
9392 // Initialize nested menus
9393 submenus.filter( ":not(.ui-menu)" )
9394 .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
9395 .hide()
9396 .attr({
9397 role: this.options.role,
9398 "aria-hidden": "true",
9399 "aria-expanded": "false"
9400 })
9401 .each(function() {
9402 var menu = $( this ),
9403 item = menu.prev( "a" ),
9404 submenuCarat = $( "<span>" )
9405 .addClass( "ui-menu-icon ui-icon " + icon )
9406 .data( "ui-menu-submenu-carat", true );
9407
9408 item
9409 .attr( "aria-haspopup", "true" )
9410 .prepend( submenuCarat );
9411 menu.attr( "aria-labelledby", item.attr( "id" ) );
9412 });
9413
9414 menus = submenus.add( this.element );
9415
9416 // Don't refresh list items that are already adapted
9417 menus.children( ":not(.ui-menu-item):has(a)" )
9418 .addClass( "ui-menu-item" )
9419 .attr( "role", "presentation" )
9420 .children( "a" )
9421 .uniqueId()
9422 .addClass( "ui-corner-all" )
9423 .attr({
9424 tabIndex: -1,
9425 role: this._itemRole()
9426 });
9427
9428 // Initialize unlinked menu-items containing spaces and/or dashes only as dividers
9429 menus.children( ":not(.ui-menu-item)" ).each(function() {
9430 var item = $( this );
9431 // hyphen, em dash, en dash
9432 if ( !/[^\-—–\s]/.test( item.text() ) ) {
9433 item.addClass( "ui-widget-content ui-menu-divider" );
9434 }
9435 });
9436
9437 // Add aria-disabled attribute to any disabled menu item
9438 menus.children( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
9439
9440 // If the active item has been removed, blur the menu
9441 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
9442 this.blur();
9443 }
9444 },
9445
9446 _itemRole: function() {
9447 return {
9448 menu: "menuitem",
9449 listbox: "option"
9450 }[ this.options.role ];
9451 },
9452
9453 focus: function( event, item ) {
9454 var nested, focused;
9455 this.blur( event, event && event.type === "focus" );
9456
9457 this._scrollIntoView( item );
9458
9459 this.active = item.first();
9460 focused = this.active.children( "a" ).addClass( "ui-state-focus" );
9461 // Only update aria-activedescendant if there's a role
9462 // otherwise we assume focus is managed elsewhere
9463 if ( this.options.role ) {
9464 this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
9465 }
9466
9467 // Highlight active parent menu item, if any
9468 this.active
9469 .parent()
9470 .closest( ".ui-menu-item" )
9471 .children( "a:first" )
9472 .addClass( "ui-state-active" );
9473
9474 if ( event && event.type === "keydown" ) {
9475 this._close();
9476 } else {
9477 this.timer = this._delay(function() {
9478 this._close();
9479 }, this.delay );
9480 }
9481
9482 nested = item.children( ".ui-menu" );
9483 if ( nested.length && ( /^mouse/.test( event.type ) ) ) {
9484 this._startOpening(nested);
9485 }
9486 this.activeMenu = item.parent();
9487
9488 this._trigger( "focus", event, { item: item } );
9489 },
9490
9491 _scrollIntoView: function( item ) {
9492 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
9493 if ( this._hasScroll() ) {
9494 borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
9495 paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
9496 offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
9497 scroll = this.activeMenu.scrollTop();
9498 elementHeight = this.activeMenu.height();
9499 itemHeight = item.height();
9500
9501 if ( offset < 0 ) {
9502 this.activeMenu.scrollTop( scroll + offset );
9503 } else if ( offset + itemHeight > elementHeight ) {
9504 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
9505 }
9506 }
9507 },
9508
9509 blur: function( event, fromFocus ) {
9510 if ( !fromFocus ) {
9511 clearTimeout( this.timer );
9512 }
9513
9514 if ( !this.active ) {
9515 return;
9516 }
9517
9518 this.active.children( "a" ).removeClass( "ui-state-focus" );
9519 this.active = null;
9520
9521 this._trigger( "blur", event, { item: this.active } );
9522 },
9523
9524 _startOpening: function( submenu ) {
9525 clearTimeout( this.timer );
9526
9527 // Don't open if already open fixes a Firefox bug that caused a .5 pixel
9528 // shift in the submenu position when mousing over the carat icon
9529 if ( submenu.attr( "aria-hidden" ) !== "true" ) {
9530 return;
9531 }
9532
9533 this.timer = this._delay(function() {
9534 this._close();
9535 this._open( submenu );
9536 }, this.delay );
9537 },
9538
9539 _open: function( submenu ) {
9540 var position = $.extend({
9541 of: this.active
9542 }, this.options.position );
9543
9544 clearTimeout( this.timer );
9545 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
9546 .hide()
9547 .attr( "aria-hidden", "true" );
9548
9549 submenu
9550 .show()
9551 .removeAttr( "aria-hidden" )
9552 .attr( "aria-expanded", "true" )
9553 .position( position );
9554 },
9555
9556 collapseAll: function( event, all ) {
9557 clearTimeout( this.timer );
9558 this.timer = this._delay(function() {
9559 // If we were passed an event, look for the submenu that contains the event
9560 var currentMenu = all ? this.element :
9561 $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
9562
9563 // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
9564 if ( !currentMenu.length ) {
9565 currentMenu = this.element;
9566 }
9567
9568 this._close( currentMenu );
9569
9570 this.blur( event );
9571 this.activeMenu = currentMenu;
9572 }, this.delay );
9573 },
9574
9575 // With no arguments, closes the currently active menu - if nothing is active
9576 // it closes all menus. If passed an argument, it will search for menus BELOW
9577 _close: function( startMenu ) {
9578 if ( !startMenu ) {
9579 startMenu = this.active ? this.active.parent() : this.element;
9580 }
9581
9582 startMenu
9583 .find( ".ui-menu" )
9584 .hide()
9585 .attr( "aria-hidden", "true" )
9586 .attr( "aria-expanded", "false" )
9587 .end()
9588 .find( "a.ui-state-active" )
9589 .removeClass( "ui-state-active" );
9590 },
9591
9592 collapse: function( event ) {
9593 var newItem = this.active &&
9594 this.active.parent().closest( ".ui-menu-item", this.element );
9595 if ( newItem && newItem.length ) {
9596 this._close();
9597 this.focus( event, newItem );
9598 }
9599 },
9600
9601 expand: function( event ) {
9602 var newItem = this.active &&
9603 this.active
9604 .children( ".ui-menu " )
9605 .children( ".ui-menu-item" )
9606 .first();
9607
9608 if ( newItem && newItem.length ) {
9609 this._open( newItem.parent() );
9610
9611 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
9612 this._delay(function() {
9613 this.focus( event, newItem );
9614 });
9615 }
9616 },
9617
9618 next: function( event ) {
9619 this._move( "next", "first", event );
9620 },
9621
9622 previous: function( event ) {
9623 this._move( "prev", "last", event );
9624 },
9625
9626 isFirstItem: function() {
9627 return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
9628 },
9629
9630 isLastItem: function() {
9631 return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
9632 },
9633
9634 _move: function( direction, filter, event ) {
9635 var next;
9636 if ( this.active ) {
9637 if ( direction === "first" || direction === "last" ) {
9638 next = this.active
9639 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
9640 .eq( -1 );
9641 } else {
9642 next = this.active
9643 [ direction + "All" ]( ".ui-menu-item" )
9644 .eq( 0 );
9645 }
9646 }
9647 if ( !next || !next.length || !this.active ) {
9648 next = this.activeMenu.children( ".ui-menu-item" )[ filter ]();
9649 }
9650
9651 this.focus( event, next );
9652 },
9653
9654 nextPage: function( event ) {
9655 var item, base, height;
9656
9657 if ( !this.active ) {
9658 this.next( event );
9659 return;
9660 }
9661 if ( this.isLastItem() ) {
9662 return;
9663 }
9664 if ( this._hasScroll() ) {
9665 base = this.active.offset().top;
9666 height = this.element.height();
9667 this.active.nextAll( ".ui-menu-item" ).each(function() {
9668 item = $( this );
9669 return item.offset().top - base - height < 0;
9670 });
9671
9672 this.focus( event, item );
9673 } else {
9674 this.focus( event, this.activeMenu.children( ".ui-menu-item" )
9675 [ !this.active ? "first" : "last" ]() );
9676 }
9677 },
9678
9679 previousPage: function( event ) {
9680 var item, base, height;
9681 if ( !this.active ) {
9682 this.next( event );
9683 return;
9684 }
9685 if ( this.isFirstItem() ) {
9686 return;
9687 }
9688 if ( this._hasScroll() ) {
9689 base = this.active.offset().top;
9690 height = this.element.height();
9691 this.active.prevAll( ".ui-menu-item" ).each(function() {
9692 item = $( this );
9693 return item.offset().top - base + height > 0;
9694 });
9695
9696 this.focus( event, item );
9697 } else {
9698 this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
9699 }
9700 },
9701
9702 _hasScroll: function() {
9703 return this.element.outerHeight() < this.element.prop( "scrollHeight" );
9704 },
9705
9706 select: function( event ) {
9707 // TODO: It should never be possible to not have an active item at this
9708 // point, but the tests don't trigger mouseenter before click.
9709 this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
9710 var ui = { item: this.active };
9711 if ( !this.active.has( ".ui-menu" ).length ) {
9712 this.collapseAll( event, true );
9713 }
9714 this._trigger( "select", event, ui );
9715 }
9716 });
9717
9718 }( jQuery ));
9719 (function( $, undefined ) {
9720
9721 $.widget( "ui.progressbar", {
9722 version: "1.9.2",
9723 options: {
9724 value: 0,
9725 max: 100
9726 },
9727
9728 min: 0,
9729
9730 _create: function() {
9731 this.element
9732 .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
9733 .attr({
9734 role: "progressbar",
9735 "aria-valuemin": this.min,
9736 "aria-valuemax": this.options.max,
9737 "aria-valuenow": this._value()
9738 });
9739
9740 this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
9741 .appendTo( this.element );
9742
9743 this.oldValue = this._value();
9744 this._refreshValue();
9745 },
9746
9747 _destroy: function() {
9748 this.element
9749 .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
9750 .removeAttr( "role" )
9751 .removeAttr( "aria-valuemin" )
9752 .removeAttr( "aria-valuemax" )
9753 .removeAttr( "aria-valuenow" );
9754
9755 this.valueDiv.remove();
9756 },
9757
9758 value: function( newValue ) {
9759 if ( newValue === undefined ) {
9760 return this._value();
9761 }
9762
9763 this._setOption( "value", newValue );
9764 return this;
9765 },
9766
9767 _setOption: function( key, value ) {
9768 if ( key === "value" ) {
9769 this.options.value = value;
9770 this._refreshValue();
9771 if ( this._value() === this.options.max ) {
9772 this._trigger( "complete" );
9773 }
9774 }
9775
9776 this._super( key, value );
9777 },
9778
9779 _value: function() {
9780 var val = this.options.value;
9781 // normalize invalid value
9782 if ( typeof val !== "number" ) {
9783 val = 0;
9784 }
9785 return Math.min( this.options.max, Math.max( this.min, val ) );
9786 },
9787
9788 _percentage: function() {
9789 return 100 * this._value() / this.options.max;
9790 },
9791
9792 _refreshValue: function() {
9793 var value = this.value(),
9794 percentage = this._percentage();
9795
9796 if ( this.oldValue !== value ) {
9797 this.oldValue = value;
9798 this._trigger( "change" );
9799 }
9800
9801 this.valueDiv
9802 .toggle( value > this.min )
9803 .toggleClass( "ui-corner-right", value === this.options.max )
9804 .width( percentage.toFixed(0) + "%" );
9805 this.element.attr( "aria-valuenow", value );
9806 }
9807 });
9808
9809 })( jQuery );
9810 (function( $, undefined ) {
9811
9812 // number of pages in a slider
9813 // (how many times can you page up/down to go through the whole range)
9814 var numPages = 5;
9815
9816 $.widget( "ui.slider", $.ui.mouse, {
9817 version: "1.9.2",
9818 widgetEventPrefix: "slide",
9819
9820 options: {
9821 animate: false,
9822 distance: 0,
9823 max: 100,
9824 min: 0,
9825 orientation: "horizontal",
9826 range: false,
9827 step: 1,
9828 value: 0,
9829 values: null
9830 },
9831
9832 _create: function() {
9833 var i, handleCount,
9834 o = this.options,
9835 existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
9836 handle = "<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",
9837 handles = [];
9838
9839 this._keySliding = false;
9840 this._mouseSliding = false;
9841 this._animateOff = true;
9842 this._handleIndex = null;
9843 this._detectOrientation();
9844 this._mouseInit();
9845
9846 this.element
9847 .addClass( "ui-slider" +
9848 " ui-slider-" + this.orientation +
9849 " ui-widget" +
9850 " ui-widget-content" +
9851 " ui-corner-all" +
9852 ( o.disabled ? " ui-slider-disabled ui-disabled" : "" ) );
9853
9854 this.range = $([]);
9855
9856 if ( o.range ) {
9857 if ( o.range === true ) {
9858 if ( !o.values ) {
9859 o.values = [ this._valueMin(), this._valueMin() ];
9860 }
9861 if ( o.values.length && o.values.length !== 2 ) {
9862 o.values = [ o.values[0], o.values[0] ];
9863 }
9864 }
9865
9866 this.range = $( "<div></div>" )
9867 .appendTo( this.element )
9868 .addClass( "ui-slider-range" +
9869 // note: this isn't the most fittingly semantic framework class for this element,
9870 // but worked best visually with a variety of themes
9871 " ui-widget-header" +
9872 ( ( o.range === "min" || o.range === "max" ) ? " ui-slider-range-" + o.range : "" ) );
9873 }
9874
9875 handleCount = ( o.values && o.values.length ) || 1;
9876
9877 for ( i = existingHandles.length; i < handleCount; i++ ) {
9878 handles.push( handle );
9879 }
9880
9881 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
9882
9883 this.handle = this.handles.eq( 0 );
9884
9885 this.handles.add( this.range ).filter( "a" )
9886 .click(function( event ) {
9887 event.preventDefault();
9888 })
9889 .mouseenter(function() {
9890 if ( !o.disabled ) {
9891 $( this ).addClass( "ui-state-hover" );
9892 }
9893 })
9894 .mouseleave(function() {
9895 $( this ).removeClass( "ui-state-hover" );
9896 })
9897 .focus(function() {
9898 if ( !o.disabled ) {
9899 $( ".ui-slider .ui-state-focus" ).removeClass( "ui-state-focus" );
9900 $( this ).addClass( "ui-state-focus" );
9901 } else {
9902 $( this ).blur();
9903 }
9904 })
9905 .blur(function() {
9906 $( this ).removeClass( "ui-state-focus" );
9907 });
9908
9909 this.handles.each(function( i ) {
9910 $( this ).data( "ui-slider-handle-index", i );
9911 });
9912
9913 this._on( this.handles, {
9914 keydown: function( event ) {
9915 var allowed, curVal, newVal, step,
9916 index = $( event.target ).data( "ui-slider-handle-index" );
9917
9918 switch ( event.keyCode ) {
9919 case $.ui.keyCode.HOME:
9920 case $.ui.keyCode.END:
9921 case $.ui.keyCode.PAGE_UP:
9922 case $.ui.keyCode.PAGE_DOWN:
9923 case $.ui.keyCode.UP:
9924 case $.ui.keyCode.RIGHT:
9925 case $.ui.keyCode.DOWN:
9926 case $.ui.keyCode.LEFT:
9927 event.preventDefault();
9928 if ( !this._keySliding ) {
9929 this._keySliding = true;
9930 $( event.target ).addClass( "ui-state-active" );
9931 allowed = this._start( event, index );
9932 if ( allowed === false ) {
9933 return;
9934 }
9935 }
9936 break;
9937 }
9938
9939 step = this.options.step;
9940 if ( this.options.values && this.options.values.length ) {
9941 curVal = newVal = this.values( index );
9942 } else {
9943 curVal = newVal = this.value();
9944 }
9945
9946 switch ( event.keyCode ) {
9947 case $.ui.keyCode.HOME:
9948 newVal = this._valueMin();
9949 break;
9950 case $.ui.keyCode.END:
9951 newVal = this._valueMax();
9952 break;
9953 case $.ui.keyCode.PAGE_UP:
9954 newVal = this._trimAlignValue( curVal + ( (this._valueMax() - this._valueMin()) / numPages ) );
9955 break;
9956 case $.ui.keyCode.PAGE_DOWN:
9957 newVal = this._trimAlignValue( curVal - ( (this._valueMax() - this._valueMin()) / numPages ) );
9958 break;
9959 case $.ui.keyCode.UP:
9960 case $.ui.keyCode.RIGHT:
9961 if ( curVal === this._valueMax() ) {
9962 return;
9963 }
9964 newVal = this._trimAlignValue( curVal + step );
9965 break;
9966 case $.ui.keyCode.DOWN:
9967 case $.ui.keyCode.LEFT:
9968 if ( curVal === this._valueMin() ) {
9969 return;
9970 }
9971 newVal = this._trimAlignValue( curVal - step );
9972 break;
9973 }
9974
9975 this._slide( event, index, newVal );
9976 },
9977 keyup: function( event ) {
9978 var index = $( event.target ).data( "ui-slider-handle-index" );
9979
9980 if ( this._keySliding ) {
9981 this._keySliding = false;
9982 this._stop( event, index );
9983 this._change( event, index );
9984 $( event.target ).removeClass( "ui-state-active" );
9985 }
9986 }
9987 });
9988
9989 this._refreshValue();
9990
9991 this._animateOff = false;
9992 },
9993
9994 _destroy: function() {
9995 this.handles.remove();
9996 this.range.remove();
9997
9998 this.element
9999 .removeClass( "ui-slider" +
10000 " ui-slider-horizontal" +
10001 " ui-slider-vertical" +
10002 " ui-slider-disabled" +
10003 " ui-widget" +
10004 " ui-widget-content" +
10005 " ui-corner-all" );
10006
10007 this._mouseDestroy();
10008 },
10009
10010 _mouseCapture: function( event ) {
10011 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
10012 that = this,
10013 o = this.options;
10014
10015 if ( o.disabled ) {
10016 return false;
10017 }
10018
10019 this.elementSize = {
10020 width: this.element.outerWidth(),
10021 height: this.element.outerHeight()
10022 };
10023 this.elementOffset = this.element.offset();
10024
10025 position = { x: event.pageX, y: event.pageY };
10026 normValue = this._normValueFromMouse( position );
10027 distance = this._valueMax() - this._valueMin() + 1;
10028 this.handles.each(function( i ) {
10029 var thisDistance = Math.abs( normValue - that.values(i) );
10030 if ( distance > thisDistance ) {
10031 distance = thisDistance;
10032 closestHandle = $( this );
10033 index = i;
10034 }
10035 });
10036
10037 // workaround for bug #3736 (if both handles of a range are at 0,
10038 // the first is always used as the one with least distance,
10039 // and moving it is obviously prevented by preventing negative ranges)
10040 if( o.range === true && this.values(1) === o.min ) {
10041 index += 1;
10042 closestHandle = $( this.handles[index] );
10043 }
10044
10045 allowed = this._start( event, index );
10046 if ( allowed === false ) {
10047 return false;
10048 }
10049 this._mouseSliding = true;
10050
10051 this._handleIndex = index;
10052
10053 closestHandle
10054 .addClass( "ui-state-active" )
10055 .focus();
10056
10057 offset = closestHandle.offset();
10058 mouseOverHandle = !$( event.target ).parents().andSelf().is( ".ui-slider-handle" );
10059 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
10060 left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
10061 top: event.pageY - offset.top -
10062 ( closestHandle.height() / 2 ) -
10063 ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
10064 ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
10065 ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
10066 };
10067
10068 if ( !this.handles.hasClass( "ui-state-hover" ) ) {
10069 this._slide( event, index, normValue );
10070 }
10071 this._animateOff = true;
10072 return true;
10073 },
10074
10075 _mouseStart: function() {
10076 return true;
10077 },
10078
10079 _mouseDrag: function( event ) {
10080 var position = { x: event.pageX, y: event.pageY },
10081 normValue = this._normValueFromMouse( position );
10082
10083 this._slide( event, this._handleIndex, normValue );
10084
10085 return false;
10086 },
10087
10088 _mouseStop: function( event ) {
10089 this.handles.removeClass( "ui-state-active" );
10090 this._mouseSliding = false;
10091
10092 this._stop( event, this._handleIndex );
10093 this._change( event, this._handleIndex );
10094
10095 this._handleIndex = null;
10096 this._clickOffset = null;
10097 this._animateOff = false;
10098
10099 return false;
10100 },
10101
10102 _detectOrientation: function() {
10103 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
10104 },
10105
10106 _normValueFromMouse: function( position ) {
10107 var pixelTotal,
10108 pixelMouse,
10109 percentMouse,
10110 valueTotal,
10111 valueMouse;
10112
10113 if ( this.orientation === "horizontal" ) {
10114 pixelTotal = this.elementSize.width;
10115 pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
10116 } else {
10117 pixelTotal = this.elementSize.height;
10118 pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
10119 }
10120
10121 percentMouse = ( pixelMouse / pixelTotal );
10122 if ( percentMouse > 1 ) {
10123 percentMouse = 1;
10124 }
10125 if ( percentMouse < 0 ) {
10126 percentMouse = 0;
10127 }
10128 if ( this.orientation === "vertical" ) {
10129 percentMouse = 1 - percentMouse;
10130 }
10131
10132 valueTotal = this._valueMax() - this._valueMin();
10133 valueMouse = this._valueMin() + percentMouse * valueTotal;
10134
10135 return this._trimAlignValue( valueMouse );
10136 },
10137
10138 _start: function( event, index ) {
10139 var uiHash = {
10140 handle: this.handles[ index ],
10141 value: this.value()
10142 };
10143 if ( this.options.values && this.options.values.length ) {
10144 uiHash.value = this.values( index );
10145 uiHash.values = this.values();
10146 }
10147 return this._trigger( "start", event, uiHash );
10148 },
10149
10150 _slide: function( event, index, newVal ) {
10151 var otherVal,
10152 newValues,
10153 allowed;
10154
10155 if ( this.options.values && this.options.values.length ) {
10156 otherVal = this.values( index ? 0 : 1 );
10157
10158 if ( ( this.options.values.length === 2 && this.options.range === true ) &&
10159 ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
10160 ) {
10161 newVal = otherVal;
10162 }
10163
10164 if ( newVal !== this.values( index ) ) {
10165 newValues = this.values();
10166 newValues[ index ] = newVal;
10167 // A slide can be canceled by returning false from the slide callback
10168 allowed = this._trigger( "slide", event, {
10169 handle: this.handles[ index ],
10170 value: newVal,
10171 values: newValues
10172 } );
10173 otherVal = this.values( index ? 0 : 1 );
10174 if ( allowed !== false ) {
10175 this.values( index, newVal, true );
10176 }
10177 }
10178 } else {
10179 if ( newVal !== this.value() ) {
10180 // A slide can be canceled by returning false from the slide callback
10181 allowed = this._trigger( "slide", event, {
10182 handle: this.handles[ index ],
10183 value: newVal
10184 } );
10185 if ( allowed !== false ) {
10186 this.value( newVal );
10187 }
10188 }
10189 }
10190 },
10191
10192 _stop: function( event, index ) {
10193 var uiHash = {
10194 handle: this.handles[ index ],
10195 value: this.value()
10196 };
10197 if ( this.options.values && this.options.values.length ) {
10198 uiHash.value = this.values( index );
10199 uiHash.values = this.values();
10200 }
10201
10202 this._trigger( "stop", event, uiHash );
10203 },
10204
10205 _change: function( event, index ) {
10206 if ( !this._keySliding && !this._mouseSliding ) {
10207 var uiHash = {
10208 handle: this.handles[ index ],
10209 value: this.value()
10210 };
10211 if ( this.options.values && this.options.values.length ) {
10212 uiHash.value = this.values( index );
10213 uiHash.values = this.values();
10214 }
10215
10216 this._trigger( "change", event, uiHash );
10217 }
10218 },
10219
10220 value: function( newValue ) {
10221 if ( arguments.length ) {
10222 this.options.value = this._trimAlignValue( newValue );
10223 this._refreshValue();
10224 this._change( null, 0 );
10225 return;
10226 }
10227
10228 return this._value();
10229 },
10230
10231 values: function( index, newValue ) {
10232 var vals,
10233 newValues,
10234 i;
10235
10236 if ( arguments.length > 1 ) {
10237 this.options.values[ index ] = this._trimAlignValue( newValue );
10238 this._refreshValue();
10239 this._change( null, index );
10240 return;
10241 }
10242
10243 if ( arguments.length ) {
10244 if ( $.isArray( arguments[ 0 ] ) ) {
10245 vals = this.options.values;
10246 newValues = arguments[ 0 ];
10247 for ( i = 0; i < vals.length; i += 1 ) {
10248 vals[ i ] = this._trimAlignValue( newValues[ i ] );
10249 this._change( null, i );
10250 }
10251 this._refreshValue();
10252 } else {
10253 if ( this.options.values && this.options.values.length ) {
10254 return this._values( index );
10255 } else {
10256 return this.value();
10257 }
10258 }
10259 } else {
10260 return this._values();
10261 }
10262 },
10263
10264 _setOption: function( key, value ) {
10265 var i,
10266 valsLength = 0;
10267
10268 if ( $.isArray( this.options.values ) ) {
10269 valsLength = this.options.values.length;
10270 }
10271
10272 $.Widget.prototype._setOption.apply( this, arguments );
10273
10274 switch ( key ) {
10275 case "disabled":
10276 if ( value ) {
10277 this.handles.filter( ".ui-state-focus" ).blur();
10278 this.handles.removeClass( "ui-state-hover" );
10279 this.handles.prop( "disabled", true );
10280 this.element.addClass( "ui-disabled" );
10281 } else {
10282 this.handles.prop( "disabled", false );
10283 this.element.removeClass( "ui-disabled" );
10284 }
10285 break;
10286 case "orientation":
10287 this._detectOrientation();
10288 this.element
10289 .removeClass( "ui-slider-horizontal ui-slider-vertical" )
10290 .addClass( "ui-slider-" + this.orientation );
10291 this._refreshValue();
10292 break;
10293 case "value":
10294 this._animateOff = true;
10295 this._refreshValue();
10296 this._change( null, 0 );
10297 this._animateOff = false;
10298 break;
10299 case "values":
10300 this._animateOff = true;
10301 this._refreshValue();
10302 for ( i = 0; i < valsLength; i += 1 ) {
10303 this._change( null, i );
10304 }
10305 this._animateOff = false;
10306 break;
10307 case "min":
10308 case "max":
10309 this._animateOff = true;
10310 this._refreshValue();
10311 this._animateOff = false;
10312 break;
10313 }
10314 },
10315
10316 //internal value getter
10317 // _value() returns value trimmed by min and max, aligned by step
10318 _value: function() {
10319 var val = this.options.value;
10320 val = this._trimAlignValue( val );
10321
10322 return val;
10323 },
10324
10325 //internal values getter
10326 // _values() returns array of values trimmed by min and max, aligned by step
10327 // _values( index ) returns single value trimmed by min and max, aligned by step
10328 _values: function( index ) {
10329 var val,
10330 vals,
10331 i;
10332
10333 if ( arguments.length ) {
10334 val = this.options.values[ index ];
10335 val = this._trimAlignValue( val );
10336
10337 return val;
10338 } else {
10339 // .slice() creates a copy of the array
10340 // this copy gets trimmed by min and max and then returned
10341 vals = this.options.values.slice();
10342 for ( i = 0; i < vals.length; i+= 1) {
10343 vals[ i ] = this._trimAlignValue( vals[ i ] );
10344 }
10345
10346 return vals;
10347 }
10348 },
10349
10350 // returns the step-aligned value that val is closest to, between (inclusive) min and max
10351 _trimAlignValue: function( val ) {
10352 if ( val <= this._valueMin() ) {
10353 return this._valueMin();
10354 }
10355 if ( val >= this._valueMax() ) {
10356 return this._valueMax();
10357 }
10358 var step = ( this.options.step > 0 ) ? this.options.step : 1,
10359 valModStep = (val - this._valueMin()) % step,
10360 alignValue = val - valModStep;
10361
10362 if ( Math.abs(valModStep) * 2 >= step ) {
10363 alignValue += ( valModStep > 0 ) ? step : ( -step );
10364 }
10365
10366 // Since JavaScript has problems with large floats, round
10367 // the final value to 5 digits after the decimal point (see #4124)
10368 return parseFloat( alignValue.toFixed(5) );
10369 },
10370
10371 _valueMin: function() {
10372 return this.options.min;
10373 },
10374
10375 _valueMax: function() {
10376 return this.options.max;
10377 },
10378
10379 _refreshValue: function() {
10380 var lastValPercent, valPercent, value, valueMin, valueMax,
10381 oRange = this.options.range,
10382 o = this.options,
10383 that = this,
10384 animate = ( !this._animateOff ) ? o.animate : false,
10385 _set = {};
10386
10387 if ( this.options.values && this.options.values.length ) {
10388 this.handles.each(function( i ) {
10389 valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
10390 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
10391 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
10392 if ( that.options.range === true ) {
10393 if ( that.orientation === "horizontal" ) {
10394 if ( i === 0 ) {
10395 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
10396 }
10397 if ( i === 1 ) {
10398 that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
10399 }
10400 } else {
10401 if ( i === 0 ) {
10402 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
10403 }
10404 if ( i === 1 ) {
10405 that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
10406 }
10407 }
10408 }
10409 lastValPercent = valPercent;
10410 });
10411 } else {
10412 value = this.value();
10413 valueMin = this._valueMin();
10414 valueMax = this._valueMax();
10415 valPercent = ( valueMax !== valueMin ) ?
10416 ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
10417 0;
10418 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
10419 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
10420
10421 if ( oRange === "min" && this.orientation === "horizontal" ) {
10422 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
10423 }
10424 if ( oRange === "max" && this.orientation === "horizontal" ) {
10425 this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
10426 }
10427 if ( oRange === "min" && this.orientation === "vertical" ) {
10428 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
10429 }
10430 if ( oRange === "max" && this.orientation === "vertical" ) {
10431 this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
10432 }
10433 }
10434 }
10435
10436 });
10437
10438 }(jQuery));
10439 (function( $ ) {
10440
10441 function modifier( fn ) {
10442 return function() {
10443 var previous = this.element.val();
10444 fn.apply( this, arguments );
10445 this._refresh();
10446 if ( previous !== this.element.val() ) {
10447 this._trigger( "change" );
10448 }
10449 };
10450 }
10451
10452 $.widget( "ui.spinner", {
10453 version: "1.9.2",
10454 defaultElement: "<input>",
10455 widgetEventPrefix: "spin",
10456 options: {
10457 culture: null,
10458 icons: {
10459 down: "ui-icon-triangle-1-s",
10460 up: "ui-icon-triangle-1-n"
10461 },
10462 incremental: true,
10463 max: null,
10464 min: null,
10465 numberFormat: null,
10466 page: 10,
10467 step: 1,
10468
10469 change: null,
10470 spin: null,
10471 start: null,
10472 stop: null
10473 },
10474
10475 _create: function() {
10476 // handle string values that need to be parsed
10477 this._setOption( "max", this.options.max );
10478 this._setOption( "min", this.options.min );
10479 this._setOption( "step", this.options.step );
10480
10481 // format the value, but don't constrain
10482 this._value( this.element.val(), true );
10483
10484 this._draw();
10485 this._on( this._events );
10486 this._refresh();
10487
10488 // turning off autocomplete prevents the browser from remembering the
10489 // value when navigating through history, so we re-enable autocomplete
10490 // if the page is unloaded before the widget is destroyed. #7790
10491 this._on( this.window, {
10492 beforeunload: function() {
10493 this.element.removeAttr( "autocomplete" );
10494 }
10495 });
10496 },
10497
10498 _getCreateOptions: function() {
10499 var options = {},
10500 element = this.element;
10501
10502 $.each( [ "min", "max", "step" ], function( i, option ) {
10503 var value = element.attr( option );
10504 if ( value !== undefined && value.length ) {
10505 options[ option ] = value;
10506 }
10507 });
10508
10509 return options;
10510 },
10511
10512 _events: {
10513 keydown: function( event ) {
10514 if ( this._start( event ) && this._keydown( event ) ) {
10515 event.preventDefault();
10516 }
10517 },
10518 keyup: "_stop",
10519 focus: function() {
10520 this.previous = this.element.val();
10521 },
10522 blur: function( event ) {
10523 if ( this.cancelBlur ) {
10524 delete this.cancelBlur;
10525 return;
10526 }
10527
10528 this._refresh();
10529 if ( this.previous !== this.element.val() ) {
10530 this._trigger( "change", event );
10531 }
10532 },
10533 mousewheel: function( event, delta ) {
10534 if ( !delta ) {
10535 return;
10536 }
10537 if ( !this.spinning && !this._start( event ) ) {
10538 return false;
10539 }
10540
10541 this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
10542 clearTimeout( this.mousewheelTimer );
10543 this.mousewheelTimer = this._delay(function() {
10544 if ( this.spinning ) {
10545 this._stop( event );
10546 }
10547 }, 100 );
10548 event.preventDefault();
10549 },
10550 "mousedown .ui-spinner-button": function( event ) {
10551 var previous;
10552
10553 // We never want the buttons to have focus; whenever the user is
10554 // interacting with the spinner, the focus should be on the input.
10555 // If the input is focused then this.previous is properly set from
10556 // when the input first received focus. If the input is not focused
10557 // then we need to set this.previous based on the value before spinning.
10558 previous = this.element[0] === this.document[0].activeElement ?
10559 this.previous : this.element.val();
10560 function checkFocus() {
10561 var isActive = this.element[0] === this.document[0].activeElement;
10562 if ( !isActive ) {
10563 this.element.focus();
10564 this.previous = previous;
10565 // support: IE
10566 // IE sets focus asynchronously, so we need to check if focus
10567 // moved off of the input because the user clicked on the button.
10568 this._delay(function() {
10569 this.previous = previous;
10570 });
10571 }
10572 }
10573
10574 // ensure focus is on (or stays on) the text field
10575 event.preventDefault();
10576 checkFocus.call( this );
10577
10578 // support: IE
10579 // IE doesn't prevent moving focus even with event.preventDefault()
10580 // so we set a flag to know when we should ignore the blur event
10581 // and check (again) if focus moved off of the input.
10582 this.cancelBlur = true;
10583 this._delay(function() {
10584 delete this.cancelBlur;
10585 checkFocus.call( this );
10586 });
10587
10588 if ( this._start( event ) === false ) {
10589 return;
10590 }
10591
10592 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
10593 },
10594 "mouseup .ui-spinner-button": "_stop",
10595 "mouseenter .ui-spinner-button": function( event ) {
10596 // button will add ui-state-active if mouse was down while mouseleave and kept down
10597 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
10598 return;
10599 }
10600
10601 if ( this._start( event ) === false ) {
10602 return false;
10603 }
10604 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
10605 },
10606 // TODO: do we really want to consider this a stop?
10607 // shouldn't we just stop the repeater and wait until mouseup before
10608 // we trigger the stop event?
10609 "mouseleave .ui-spinner-button": "_stop"
10610 },
10611
10612 _draw: function() {
10613 var uiSpinner = this.uiSpinner = this.element
10614 .addClass( "ui-spinner-input" )
10615 .attr( "autocomplete", "off" )
10616 .wrap( this._uiSpinnerHtml() )
10617 .parent()
10618 // add buttons
10619 .append( this._buttonHtml() );
10620
10621 this.element.attr( "role", "spinbutton" );
10622
10623 // button bindings
10624 this.buttons = uiSpinner.find( ".ui-spinner-button" )
10625 .attr( "tabIndex", -1 )
10626 .button()
10627 .removeClass( "ui-corner-all" );
10628
10629 // IE 6 doesn't understand height: 50% for the buttons
10630 // unless the wrapper has an explicit height
10631 if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&
10632 uiSpinner.height() > 0 ) {
10633 uiSpinner.height( uiSpinner.height() );
10634 }
10635
10636 // disable spinner if element was already disabled
10637 if ( this.options.disabled ) {
10638 this.disable();
10639 }
10640 },
10641
10642 _keydown: function( event ) {
10643 var options = this.options,
10644 keyCode = $.ui.keyCode;
10645
10646 switch ( event.keyCode ) {
10647 case keyCode.UP:
10648 this._repeat( null, 1, event );
10649 return true;
10650 case keyCode.DOWN:
10651 this._repeat( null, -1, event );
10652 return true;
10653 case keyCode.PAGE_UP:
10654 this._repeat( null, options.page, event );
10655 return true;
10656 case keyCode.PAGE_DOWN:
10657 this._repeat( null, -options.page, event );
10658 return true;
10659 }
10660
10661 return false;
10662 },
10663
10664 _uiSpinnerHtml: function() {
10665 return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>";
10666 },
10667
10668 _buttonHtml: function() {
10669 return "" +
10670 "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" +
10671 "<span class='ui-icon " + this.options.icons.up + "'>&#9650;</span>" +
10672 "</a>" +
10673 "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" +
10674 "<span class='ui-icon " + this.options.icons.down + "'>&#9660;</span>" +
10675 "</a>";
10676 },
10677
10678 _start: function( event ) {
10679 if ( !this.spinning && this._trigger( "start", event ) === false ) {
10680 return false;
10681 }
10682
10683 if ( !this.counter ) {
10684 this.counter = 1;
10685 }
10686 this.spinning = true;
10687 return true;
10688 },
10689
10690 _repeat: function( i, steps, event ) {
10691 i = i || 500;
10692
10693 clearTimeout( this.timer );
10694 this.timer = this._delay(function() {
10695 this._repeat( 40, steps, event );
10696 }, i );
10697
10698 this._spin( steps * this.options.step, event );
10699 },
10700
10701 _spin: function( step, event ) {
10702 var value = this.value() || 0;
10703
10704 if ( !this.counter ) {
10705 this.counter = 1;
10706 }
10707
10708 value = this._adjustValue( value + step * this._increment( this.counter ) );
10709
10710 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) {
10711 this._value( value );
10712 this.counter++;
10713 }
10714 },
10715
10716 _increment: function( i ) {
10717 var incremental = this.options.incremental;
10718
10719 if ( incremental ) {
10720 return $.isFunction( incremental ) ?
10721 incremental( i ) :
10722 Math.floor( i*i*i/50000 - i*i/500 + 17*i/200 + 1 );
10723 }
10724
10725 return 1;
10726 },
10727
10728 _precision: function() {
10729 var precision = this._precisionOf( this.options.step );
10730 if ( this.options.min !== null ) {
10731 precision = Math.max( precision, this._precisionOf( this.options.min ) );
10732 }
10733 return precision;
10734 },
10735
10736 _precisionOf: function( num ) {
10737 var str = num.toString(),
10738 decimal = str.indexOf( "." );
10739 return decimal === -1 ? 0 : str.length - decimal - 1;
10740 },
10741
10742 _adjustValue: function( value ) {
10743 var base, aboveMin,
10744 options = this.options;
10745
10746 // make sure we're at a valid step
10747 // - find out where we are relative to the base (min or 0)
10748 base = options.min !== null ? options.min : 0;
10749 aboveMin = value - base;
10750 // - round to the nearest step
10751 aboveMin = Math.round(aboveMin / options.step) * options.step;
10752 // - rounding is based on 0, so adjust back to our base
10753 value = base + aboveMin;
10754
10755 // fix precision from bad JS floating point math
10756 value = parseFloat( value.toFixed( this._precision() ) );
10757
10758 // clamp the value
10759 if ( options.max !== null && value > options.max) {
10760 return options.max;
10761 }
10762 if ( options.min !== null && value < options.min ) {
10763 return options.min;
10764 }
10765
10766 return value;
10767 },
10768
10769 _stop: function( event ) {
10770 if ( !this.spinning ) {
10771 return;
10772 }
10773
10774 clearTimeout( this.timer );
10775 clearTimeout( this.mousewheelTimer );
10776 this.counter = 0;
10777 this.spinning = false;
10778 this._trigger( "stop", event );
10779 },
10780
10781 _setOption: function( key, value ) {
10782 if ( key === "culture" || key === "numberFormat" ) {
10783 var prevValue = this._parse( this.element.val() );
10784 this.options[ key ] = value;
10785 this.element.val( this._format( prevValue ) );
10786 return;
10787 }
10788
10789 if ( key === "max" || key === "min" || key === "step" ) {
10790 if ( typeof value === "string" ) {
10791 value = this._parse( value );
10792 }
10793 }
10794
10795 this._super( key, value );
10796
10797 if ( key === "disabled" ) {
10798 if ( value ) {
10799 this.element.prop( "disabled", true );
10800 this.buttons.button( "disable" );
10801 } else {
10802 this.element.prop( "disabled", false );
10803 this.buttons.button( "enable" );
10804 }
10805 }
10806 },
10807
10808 _setOptions: modifier(function( options ) {
10809 this._super( options );
10810 this._value( this.element.val() );
10811 }),
10812
10813 _parse: function( val ) {
10814 if ( typeof val === "string" && val !== "" ) {
10815 val = window.Globalize && this.options.numberFormat ?
10816 Globalize.parseFloat( val, 10, this.options.culture ) : +val;
10817 }
10818 return val === "" || isNaN( val ) ? null : val;
10819 },
10820
10821 _format: function( value ) {
10822 if ( value === "" ) {
10823 return "";
10824 }
10825 return window.Globalize && this.options.numberFormat ?
10826 Globalize.format( value, this.options.numberFormat, this.options.culture ) :
10827 value;
10828 },
10829
10830 _refresh: function() {
10831 this.element.attr({
10832 "aria-valuemin": this.options.min,
10833 "aria-valuemax": this.options.max,
10834 // TODO: what should we do with values that can't be parsed?
10835 "aria-valuenow": this._parse( this.element.val() )
10836 });
10837 },
10838
10839 // update the value without triggering change
10840 _value: function( value, allowAny ) {
10841 var parsed;
10842 if ( value !== "" ) {
10843 parsed = this._parse( value );
10844 if ( parsed !== null ) {
10845 if ( !allowAny ) {
10846 parsed = this._adjustValue( parsed );
10847 }
10848 value = this._format( parsed );
10849 }
10850 }
10851 this.element.val( value );
10852 this._refresh();
10853 },
10854
10855 _destroy: function() {
10856 this.element
10857 .removeClass( "ui-spinner-input" )
10858 .prop( "disabled", false )
10859 .removeAttr( "autocomplete" )
10860 .removeAttr( "role" )
10861 .removeAttr( "aria-valuemin" )
10862 .removeAttr( "aria-valuemax" )
10863 .removeAttr( "aria-valuenow" );
10864 this.uiSpinner.replaceWith( this.element );
10865 },
10866
10867 stepUp: modifier(function( steps ) {
10868 this._stepUp( steps );
10869 }),
10870 _stepUp: function( steps ) {
10871 this._spin( (steps || 1) * this.options.step );
10872 },
10873
10874 stepDown: modifier(function( steps ) {
10875 this._stepDown( steps );
10876 }),
10877 _stepDown: function( steps ) {
10878 this._spin( (steps || 1) * -this.options.step );
10879 },
10880
10881 pageUp: modifier(function( pages ) {
10882 this._stepUp( (pages || 1) * this.options.page );
10883 }),
10884
10885 pageDown: modifier(function( pages ) {
10886 this._stepDown( (pages || 1) * this.options.page );
10887 }),
10888
10889 value: function( newVal ) {
10890 if ( !arguments.length ) {
10891 return this._parse( this.element.val() );
10892 }
10893 modifier( this._value ).call( this, newVal );
10894 },
10895
10896 widget: function() {
10897 return this.uiSpinner;
10898 }
10899 });
10900
10901 }( jQuery ) );
10902 (function( $, undefined ) {
10903
10904 var tabId = 0,
10905 rhash = /#.*$/;
10906
10907 function getNextTabId() {
10908 return ++tabId;
10909 }
10910
10911 function isLocal( anchor ) {
10912 return anchor.hash.length > 1 &&
10913 anchor.href.replace( rhash, "" ) ===
10914 location.href.replace( rhash, "" )
10915 // support: Safari 5.1
10916 // Safari 5.1 doesn't encode spaces in window.location
10917 // but it does encode spaces from anchors (#8777)
10918 .replace( /\s/g, "%20" );
10919 }
10920
10921 $.widget( "ui.tabs", {
10922 version: "1.9.2",
10923 delay: 300,
10924 options: {
10925 active: null,
10926 collapsible: false,
10927 event: "click",
10928 heightStyle: "content",
10929 hide: null,
10930 show: null,
10931
10932 // callbacks
10933 activate: null,
10934 beforeActivate: null,
10935 beforeLoad: null,
10936 load: null
10937 },
10938
10939 _create: function() {
10940 var that = this,
10941 options = this.options,
10942 active = options.active,
10943 locationHash = location.hash.substring( 1 );
10944
10945 this.running = false;
10946
10947 this.element
10948 .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" )
10949 .toggleClass( "ui-tabs-collapsible", options.collapsible )
10950 // Prevent users from focusing disabled tabs via click
10951 .delegate( ".ui-tabs-nav > li", "mousedown" + this.eventNamespace, function( event ) {
10952 if ( $( this ).is( ".ui-state-disabled" ) ) {
10953 event.preventDefault();
10954 }
10955 })
10956 // support: IE <9
10957 // Preventing the default action in mousedown doesn't prevent IE
10958 // from focusing the element, so if the anchor gets focused, blur.
10959 // We don't have to worry about focusing the previously focused
10960 // element since clicking on a non-focusable element should focus
10961 // the body anyway.
10962 .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() {
10963 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
10964 this.blur();
10965 }
10966 });
10967
10968 this._processTabs();
10969
10970 if ( active === null ) {
10971 // check the fragment identifier in the URL
10972 if ( locationHash ) {
10973 this.tabs.each(function( i, tab ) {
10974 if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
10975 active = i;
10976 return false;
10977 }
10978 });
10979 }
10980
10981 // check for a tab marked active via a class
10982 if ( active === null ) {
10983 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
10984 }
10985
10986 // no active tab, set to false
10987 if ( active === null || active === -1 ) {
10988 active = this.tabs.length ? 0 : false;
10989 }
10990 }
10991
10992 // handle numbers: negative, out of range
10993 if ( active !== false ) {
10994 active = this.tabs.index( this.tabs.eq( active ) );
10995 if ( active === -1 ) {
10996 active = options.collapsible ? false : 0;
10997 }
10998 }
10999 options.active = active;
11000
11001 // don't allow collapsible: false and active: false
11002 if ( !options.collapsible && options.active === false && this.anchors.length ) {
11003 options.active = 0;
11004 }
11005
11006 // Take disabling tabs via class attribute from HTML
11007 // into account and update option properly.
11008 if ( $.isArray( options.disabled ) ) {
11009 options.disabled = $.unique( options.disabled.concat(
11010 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
11011 return that.tabs.index( li );
11012 })
11013 ) ).sort();
11014 }
11015
11016 // check for length avoids error when initializing empty list
11017 if ( this.options.active !== false && this.anchors.length ) {
11018 this.active = this._findActive( this.options.active );
11019 } else {
11020 this.active = $();
11021 }
11022
11023 this._refresh();
11024
11025 if ( this.active.length ) {
11026 this.load( options.active );
11027 }
11028 },
11029
11030 _getCreateEventData: function() {
11031 return {
11032 tab: this.active,
11033 panel: !this.active.length ? $() : this._getPanelForTab( this.active )
11034 };
11035 },
11036
11037 _tabKeydown: function( event ) {
11038 var focusedTab = $( this.document[0].activeElement ).closest( "li" ),
11039 selectedIndex = this.tabs.index( focusedTab ),
11040 goingForward = true;
11041
11042 if ( this._handlePageNav( event ) ) {
11043 return;
11044 }
11045
11046 switch ( event.keyCode ) {
11047 case $.ui.keyCode.RIGHT:
11048 case $.ui.keyCode.DOWN:
11049 selectedIndex++;
11050 break;
11051 case $.ui.keyCode.UP:
11052 case $.ui.keyCode.LEFT:
11053 goingForward = false;
11054 selectedIndex--;
11055 break;
11056 case $.ui.keyCode.END:
11057 selectedIndex = this.anchors.length - 1;
11058 break;
11059 case $.ui.keyCode.HOME:
11060 selectedIndex = 0;
11061 break;
11062 case $.ui.keyCode.SPACE:
11063 // Activate only, no collapsing
11064 event.preventDefault();
11065 clearTimeout( this.activating );
11066 this._activate( selectedIndex );
11067 return;
11068 case $.ui.keyCode.ENTER:
11069 // Toggle (cancel delayed activation, allow collapsing)
11070 event.preventDefault();
11071 clearTimeout( this.activating );
11072 // Determine if we should collapse or activate
11073 this._activate( selectedIndex === this.options.active ? false : selectedIndex );
11074 return;
11075 default:
11076 return;
11077 }
11078
11079 // Focus the appropriate tab, based on which key was pressed
11080 event.preventDefault();
11081 clearTimeout( this.activating );
11082 selectedIndex = this._focusNextTab( selectedIndex, goingForward );
11083
11084 // Navigating with control key will prevent automatic activation
11085 if ( !event.ctrlKey ) {
11086 // Update aria-selected immediately so that AT think the tab is already selected.
11087 // Otherwise AT may confuse the user by stating that they need to activate the tab,
11088 // but the tab will already be activated by the time the announcement finishes.
11089 focusedTab.attr( "aria-selected", "false" );
11090 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
11091
11092 this.activating = this._delay(function() {
11093 this.option( "active", selectedIndex );
11094 }, this.delay );
11095 }
11096 },
11097
11098 _panelKeydown: function( event ) {
11099 if ( this._handlePageNav( event ) ) {
11100 return;
11101 }
11102
11103 // Ctrl+up moves focus to the current tab
11104 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
11105 event.preventDefault();
11106 this.active.focus();
11107 }
11108 },
11109
11110 // Alt+page up/down moves focus to the previous/next tab (and activates)
11111 _handlePageNav: function( event ) {
11112 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
11113 this._activate( this._focusNextTab( this.options.active - 1, false ) );
11114 return true;
11115 }
11116 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
11117 this._activate( this._focusNextTab( this.options.active + 1, true ) );
11118 return true;
11119 }
11120 },
11121
11122 _findNextTab: function( index, goingForward ) {
11123 var lastTabIndex = this.tabs.length - 1;
11124
11125 function constrain() {
11126 if ( index > lastTabIndex ) {
11127 index = 0;
11128 }
11129 if ( index < 0 ) {
11130 index = lastTabIndex;
11131 }
11132 return index;
11133 }
11134
11135 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
11136 index = goingForward ? index + 1 : index - 1;
11137 }
11138
11139 return index;
11140 },
11141
11142 _focusNextTab: function( index, goingForward ) {
11143 index = this._findNextTab( index, goingForward );
11144 this.tabs.eq( index ).focus();
11145 return index;
11146 },
11147
11148 _setOption: function( key, value ) {
11149 if ( key === "active" ) {
11150 // _activate() will handle invalid values and update this.options
11151 this._activate( value );
11152 return;
11153 }
11154
11155 if ( key === "disabled" ) {
11156 // don't use the widget factory's disabled handling
11157 this._setupDisabled( value );
11158 return;
11159 }
11160
11161 this._super( key, value);
11162
11163 if ( key === "collapsible" ) {
11164 this.element.toggleClass( "ui-tabs-collapsible", value );
11165 // Setting collapsible: false while collapsed; open first panel
11166 if ( !value && this.options.active === false ) {
11167 this._activate( 0 );
11168 }
11169 }
11170
11171 if ( key === "event" ) {
11172 this._setupEvents( value );
11173 }
11174
11175 if ( key === "heightStyle" ) {
11176 this._setupHeightStyle( value );
11177 }
11178 },
11179
11180 _tabId: function( tab ) {
11181 return tab.attr( "aria-controls" ) || "ui-tabs-" + getNextTabId();
11182 },
11183
11184 _sanitizeSelector: function( hash ) {
11185 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
11186 },
11187
11188 refresh: function() {
11189 var options = this.options,
11190 lis = this.tablist.children( ":has(a[href])" );
11191
11192 // get disabled tabs from class attribute from HTML
11193 // this will get converted to a boolean if needed in _refresh()
11194 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
11195 return lis.index( tab );
11196 });
11197
11198 this._processTabs();
11199
11200 // was collapsed or no tabs
11201 if ( options.active === false || !this.anchors.length ) {
11202 options.active = false;
11203 this.active = $();
11204 // was active, but active tab is gone
11205 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
11206 // all remaining tabs are disabled
11207 if ( this.tabs.length === options.disabled.length ) {
11208 options.active = false;
11209 this.active = $();
11210 // activate previous tab
11211 } else {
11212 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
11213 }
11214 // was active, active tab still exists
11215 } else {
11216 // make sure active index is correct
11217 options.active = this.tabs.index( this.active );
11218 }
11219
11220 this._refresh();
11221 },
11222
11223 _refresh: function() {
11224 this._setupDisabled( this.options.disabled );
11225 this._setupEvents( this.options.event );
11226 this._setupHeightStyle( this.options.heightStyle );
11227
11228 this.tabs.not( this.active ).attr({
11229 "aria-selected": "false",
11230 tabIndex: -1
11231 });
11232 this.panels.not( this._getPanelForTab( this.active ) )
11233 .hide()
11234 .attr({
11235 "aria-expanded": "false",
11236 "aria-hidden": "true"
11237 });
11238
11239 // Make sure one tab is in the tab order
11240 if ( !this.active.length ) {
11241 this.tabs.eq( 0 ).attr( "tabIndex", 0 );
11242 } else {
11243 this.active
11244 .addClass( "ui-tabs-active ui-state-active" )
11245 .attr({
11246 "aria-selected": "true",
11247 tabIndex: 0
11248 });
11249 this._getPanelForTab( this.active )
11250 .show()
11251 .attr({
11252 "aria-expanded": "true",
11253 "aria-hidden": "false"
11254 });
11255 }
11256 },
11257
11258 _processTabs: function() {
11259 var that = this;
11260
11261 this.tablist = this._getList()
11262 .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
11263 .attr( "role", "tablist" );
11264
11265 this.tabs = this.tablist.find( "> li:has(a[href])" )
11266 .addClass( "ui-state-default ui-corner-top" )
11267 .attr({
11268 role: "tab",
11269 tabIndex: -1
11270 });
11271
11272 this.anchors = this.tabs.map(function() {
11273 return $( "a", this )[ 0 ];
11274 })
11275 .addClass( "ui-tabs-anchor" )
11276 .attr({
11277 role: "presentation",
11278 tabIndex: -1
11279 });
11280
11281 this.panels = $();
11282
11283 this.anchors.each(function( i, anchor ) {
11284 var selector, panel, panelId,
11285 anchorId = $( anchor ).uniqueId().attr( "id" ),
11286 tab = $( anchor ).closest( "li" ),
11287 originalAriaControls = tab.attr( "aria-controls" );
11288
11289 // inline tab
11290 if ( isLocal( anchor ) ) {
11291 selector = anchor.hash;
11292 panel = that.element.find( that._sanitizeSelector( selector ) );
11293 // remote tab
11294 } else {
11295 panelId = that._tabId( tab );
11296 selector = "#" + panelId;
11297 panel = that.element.find( selector );
11298 if ( !panel.length ) {
11299 panel = that._createPanel( panelId );
11300 panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
11301 }
11302 panel.attr( "aria-live", "polite" );
11303 }
11304
11305 if ( panel.length) {
11306 that.panels = that.panels.add( panel );
11307 }
11308 if ( originalAriaControls ) {
11309 tab.data( "ui-tabs-aria-controls", originalAriaControls );
11310 }
11311 tab.attr({
11312 "aria-controls": selector.substring( 1 ),
11313 "aria-labelledby": anchorId
11314 });
11315 panel.attr( "aria-labelledby", anchorId );
11316 });
11317
11318 this.panels
11319 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
11320 .attr( "role", "tabpanel" );
11321 },
11322
11323 // allow overriding how to find the list for rare usage scenarios (#7715)
11324 _getList: function() {
11325 return this.element.find( "ol,ul" ).eq( 0 );
11326 },
11327
11328 _createPanel: function( id ) {
11329 return $( "<div>" )
11330 .attr( "id", id )
11331 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
11332 .data( "ui-tabs-destroy", true );
11333 },
11334
11335 _setupDisabled: function( disabled ) {
11336 if ( $.isArray( disabled ) ) {
11337 if ( !disabled.length ) {
11338 disabled = false;
11339 } else if ( disabled.length === this.anchors.length ) {
11340 disabled = true;
11341 }
11342 }
11343
11344 // disable tabs
11345 for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {
11346 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
11347 $( li )
11348 .addClass( "ui-state-disabled" )
11349 .attr( "aria-disabled", "true" );
11350 } else {
11351 $( li )
11352 .removeClass( "ui-state-disabled" )
11353 .removeAttr( "aria-disabled" );
11354 }
11355 }
11356
11357 this.options.disabled = disabled;
11358 },
11359
11360 _setupEvents: function( event ) {
11361 var events = {
11362 click: function( event ) {
11363 event.preventDefault();
11364 }
11365 };
11366 if ( event ) {
11367 $.each( event.split(" "), function( index, eventName ) {
11368 events[ eventName ] = "_eventHandler";
11369 });
11370 }
11371
11372 this._off( this.anchors.add( this.tabs ).add( this.panels ) );
11373 this._on( this.anchors, events );
11374 this._on( this.tabs, { keydown: "_tabKeydown" } );
11375 this._on( this.panels, { keydown: "_panelKeydown" } );
11376
11377 this._focusable( this.tabs );
11378 this._hoverable( this.tabs );
11379 },
11380
11381 _setupHeightStyle: function( heightStyle ) {
11382 var maxHeight, overflow,
11383 parent = this.element.parent();
11384
11385 if ( heightStyle === "fill" ) {
11386 // IE 6 treats height like minHeight, so we need to turn off overflow
11387 // in order to get a reliable height
11388 // we use the minHeight support test because we assume that only
11389 // browsers that don't support minHeight will treat height as minHeight
11390 if ( !$.support.minHeight ) {
11391 overflow = parent.css( "overflow" );
11392 parent.css( "overflow", "hidden");
11393 }
11394 maxHeight = parent.height();
11395 this.element.siblings( ":visible" ).each(function() {
11396 var elem = $( this ),
11397 position = elem.css( "position" );
11398
11399 if ( position === "absolute" || position === "fixed" ) {
11400 return;
11401 }
11402 maxHeight -= elem.outerHeight( true );
11403 });
11404 if ( overflow ) {
11405 parent.css( "overflow", overflow );
11406 }
11407
11408 this.element.children().not( this.panels ).each(function() {
11409 maxHeight -= $( this ).outerHeight( true );
11410 });
11411
11412 this.panels.each(function() {
11413 $( this ).height( Math.max( 0, maxHeight -
11414 $( this ).innerHeight() + $( this ).height() ) );
11415 })
11416 .css( "overflow", "auto" );
11417 } else if ( heightStyle === "auto" ) {
11418 maxHeight = 0;
11419 this.panels.each(function() {
11420 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
11421 }).height( maxHeight );
11422 }
11423 },
11424
11425 _eventHandler: function( event ) {
11426 var options = this.options,
11427 active = this.active,
11428 anchor = $( event.currentTarget ),
11429 tab = anchor.closest( "li" ),
11430 clickedIsActive = tab[ 0 ] === active[ 0 ],
11431 collapsing = clickedIsActive && options.collapsible,
11432 toShow = collapsing ? $() : this._getPanelForTab( tab ),
11433 toHide = !active.length ? $() : this._getPanelForTab( active ),
11434 eventData = {
11435 oldTab: active,
11436 oldPanel: toHide,
11437 newTab: collapsing ? $() : tab,
11438 newPanel: toShow
11439 };
11440
11441 event.preventDefault();
11442
11443 if ( tab.hasClass( "ui-state-disabled" ) ||
11444 // tab is already loading
11445 tab.hasClass( "ui-tabs-loading" ) ||
11446 // can't switch durning an animation
11447 this.running ||
11448 // click on active header, but not collapsible
11449 ( clickedIsActive && !options.collapsible ) ||
11450 // allow canceling activation
11451 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
11452 return;
11453 }
11454
11455 options.active = collapsing ? false : this.tabs.index( tab );
11456
11457 this.active = clickedIsActive ? $() : tab;
11458 if ( this.xhr ) {
11459 this.xhr.abort();
11460 }
11461
11462 if ( !toHide.length && !toShow.length ) {
11463 $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
11464 }
11465
11466 if ( toShow.length ) {
11467 this.load( this.tabs.index( tab ), event );
11468 }
11469 this._toggle( event, eventData );
11470 },
11471
11472 // handles show/hide for selecting tabs
11473 _toggle: function( event, eventData ) {
11474 var that = this,
11475 toShow = eventData.newPanel,
11476 toHide = eventData.oldPanel;
11477
11478 this.running = true;
11479
11480 function complete() {
11481 that.running = false;
11482 that._trigger( "activate", event, eventData );
11483 }
11484
11485 function show() {
11486 eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
11487
11488 if ( toShow.length && that.options.show ) {
11489 that._show( toShow, that.options.show, complete );
11490 } else {
11491 toShow.show();
11492 complete();
11493 }
11494 }
11495
11496 // start out by hiding, then showing, then completing
11497 if ( toHide.length && this.options.hide ) {
11498 this._hide( toHide, this.options.hide, function() {
11499 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
11500 show();
11501 });
11502 } else {
11503 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
11504 toHide.hide();
11505 show();
11506 }
11507
11508 toHide.attr({
11509 "aria-expanded": "false",
11510 "aria-hidden": "true"
11511 });
11512 eventData.oldTab.attr( "aria-selected", "false" );
11513 // If we're switching tabs, remove the old tab from the tab order.
11514 // If we're opening from collapsed state, remove the previous tab from the tab order.
11515 // If we're collapsing, then keep the collapsing tab in the tab order.
11516 if ( toShow.length && toHide.length ) {
11517 eventData.oldTab.attr( "tabIndex", -1 );
11518 } else if ( toShow.length ) {
11519 this.tabs.filter(function() {
11520 return $( this ).attr( "tabIndex" ) === 0;
11521 })
11522 .attr( "tabIndex", -1 );
11523 }
11524
11525 toShow.attr({
11526 "aria-expanded": "true",
11527 "aria-hidden": "false"
11528 });
11529 eventData.newTab.attr({
11530 "aria-selected": "true",
11531 tabIndex: 0
11532 });
11533 },
11534
11535 _activate: function( index ) {
11536 var anchor,
11537 active = this._findActive( index );
11538
11539 // trying to activate the already active panel
11540 if ( active[ 0 ] === this.active[ 0 ] ) {
11541 return;
11542 }
11543
11544 // trying to collapse, simulate a click on the current active header
11545 if ( !active.length ) {
11546 active = this.active;
11547 }
11548
11549 anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
11550 this._eventHandler({
11551 target: anchor,
11552 currentTarget: anchor,
11553 preventDefault: $.noop
11554 });
11555 },
11556
11557 _findActive: function( index ) {
11558 return index === false ? $() : this.tabs.eq( index );
11559 },
11560
11561 _getIndex: function( index ) {
11562 // meta-function to give users option to provide a href string instead of a numerical index.
11563 if ( typeof index === "string" ) {
11564 index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) );
11565 }
11566
11567 return index;
11568 },
11569
11570 _destroy: function() {
11571 if ( this.xhr ) {
11572 this.xhr.abort();
11573 }
11574
11575 this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" );
11576
11577 this.tablist
11578 .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
11579 .removeAttr( "role" );
11580
11581 this.anchors
11582 .removeClass( "ui-tabs-anchor" )
11583 .removeAttr( "role" )
11584 .removeAttr( "tabIndex" )
11585 .removeData( "href.tabs" )
11586 .removeData( "load.tabs" )
11587 .removeUniqueId();
11588
11589 this.tabs.add( this.panels ).each(function() {
11590 if ( $.data( this, "ui-tabs-destroy" ) ) {
11591 $( this ).remove();
11592 } else {
11593 $( this )
11594 .removeClass( "ui-state-default ui-state-active ui-state-disabled " +
11595 "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" )
11596 .removeAttr( "tabIndex" )
11597 .removeAttr( "aria-live" )
11598 .removeAttr( "aria-busy" )
11599 .removeAttr( "aria-selected" )
11600 .removeAttr( "aria-labelledby" )
11601 .removeAttr( "aria-hidden" )
11602 .removeAttr( "aria-expanded" )
11603 .removeAttr( "role" );
11604 }
11605 });
11606
11607 this.tabs.each(function() {
11608 var li = $( this ),
11609 prev = li.data( "ui-tabs-aria-controls" );
11610 if ( prev ) {
11611 li.attr( "aria-controls", prev );
11612 } else {
11613 li.removeAttr( "aria-controls" );
11614 }
11615 });
11616
11617 this.panels.show();
11618
11619 if ( this.options.heightStyle !== "content" ) {
11620 this.panels.css( "height", "" );
11621 }
11622 },
11623
11624 enable: function( index ) {
11625 var disabled = this.options.disabled;
11626 if ( disabled === false ) {
11627 return;
11628 }
11629
11630 if ( index === undefined ) {
11631 disabled = false;
11632 } else {
11633 index = this._getIndex( index );
11634 if ( $.isArray( disabled ) ) {
11635 disabled = $.map( disabled, function( num ) {
11636 return num !== index ? num : null;
11637 });
11638 } else {
11639 disabled = $.map( this.tabs, function( li, num ) {
11640 return num !== index ? num : null;
11641 });
11642 }
11643 }
11644 this._setupDisabled( disabled );
11645 },
11646
11647 disable: function( index ) {
11648 var disabled = this.options.disabled;
11649 if ( disabled === true ) {
11650 return;
11651 }
11652
11653 if ( index === undefined ) {
11654 disabled = true;
11655 } else {
11656 index = this._getIndex( index );
11657 if ( $.inArray( index, disabled ) !== -1 ) {
11658 return;
11659 }
11660 if ( $.isArray( disabled ) ) {
11661 disabled = $.merge( [ index ], disabled ).sort();
11662 } else {
11663 disabled = [ index ];
11664 }
11665 }
11666 this._setupDisabled( disabled );
11667 },
11668
11669 load: function( index, event ) {
11670 index = this._getIndex( index );
11671 var that = this,
11672 tab = this.tabs.eq( index ),
11673 anchor = tab.find( ".ui-tabs-anchor" ),
11674 panel = this._getPanelForTab( tab ),
11675 eventData = {
11676 tab: tab,
11677 panel: panel
11678 };
11679
11680 // not remote
11681 if ( isLocal( anchor[ 0 ] ) ) {
11682 return;
11683 }
11684
11685 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
11686
11687 // support: jQuery <1.8
11688 // jQuery <1.8 returns false if the request is canceled in beforeSend,
11689 // but as of 1.8, $.ajax() always returns a jqXHR object.
11690 if ( this.xhr && this.xhr.statusText !== "canceled" ) {
11691 tab.addClass( "ui-tabs-loading" );
11692 panel.attr( "aria-busy", "true" );
11693
11694 this.xhr
11695 .success(function( response ) {
11696 // support: jQuery <1.8
11697 // http://bugs.jquery.com/ticket/11778
11698 setTimeout(function() {
11699 panel.html( response );
11700 that._trigger( "load", event, eventData );
11701 }, 1 );
11702 })
11703 .complete(function( jqXHR, status ) {
11704 // support: jQuery <1.8
11705 // http://bugs.jquery.com/ticket/11778
11706 setTimeout(function() {
11707 if ( status === "abort" ) {
11708 that.panels.stop( false, true );
11709 }
11710
11711 tab.removeClass( "ui-tabs-loading" );
11712 panel.removeAttr( "aria-busy" );
11713
11714 if ( jqXHR === that.xhr ) {
11715 delete that.xhr;
11716 }
11717 }, 1 );
11718 });
11719 }
11720 },
11721
11722 // TODO: Remove this function in 1.10 when ajaxOptions is removed
11723 _ajaxSettings: function( anchor, event, eventData ) {
11724 var that = this;
11725 return {
11726 url: anchor.attr( "href" ),
11727 beforeSend: function( jqXHR, settings ) {
11728 return that._trigger( "beforeLoad", event,
11729 $.extend( { jqXHR : jqXHR, ajaxSettings: settings }, eventData ) );
11730 }
11731 };
11732 },
11733
11734 _getPanelForTab: function( tab ) {
11735 var id = $( tab ).attr( "aria-controls" );
11736 return this.element.find( this._sanitizeSelector( "#" + id ) );
11737 }
11738 });
11739
11740 // DEPRECATED
11741 if ( $.uiBackCompat !== false ) {
11742
11743 // helper method for a lot of the back compat extensions
11744 $.ui.tabs.prototype._ui = function( tab, panel ) {
11745 return {
11746 tab: tab,
11747 panel: panel,
11748 index: this.anchors.index( tab )
11749 };
11750 };
11751
11752 // url method
11753 $.widget( "ui.tabs", $.ui.tabs, {
11754 url: function( index, url ) {
11755 this.anchors.eq( index ).attr( "href", url );
11756 }
11757 });
11758
11759 // TODO: Remove _ajaxSettings() method when removing this extension
11760 // ajaxOptions and cache options
11761 $.widget( "ui.tabs", $.ui.tabs, {
11762 options: {
11763 ajaxOptions: null,
11764 cache: false
11765 },
11766
11767 _create: function() {
11768 this._super();
11769
11770 var that = this;
11771
11772 this._on({ tabsbeforeload: function( event, ui ) {
11773 // tab is already cached
11774 if ( $.data( ui.tab[ 0 ], "cache.tabs" ) ) {
11775 event.preventDefault();
11776 return;
11777 }
11778
11779 ui.jqXHR.success(function() {
11780 if ( that.options.cache ) {
11781 $.data( ui.tab[ 0 ], "cache.tabs", true );
11782 }
11783 });
11784 }});
11785 },
11786
11787 _ajaxSettings: function( anchor, event, ui ) {
11788 var ajaxOptions = this.options.ajaxOptions;
11789 return $.extend( {}, ajaxOptions, {
11790 error: function( xhr, status ) {
11791 try {
11792 // Passing index avoid a race condition when this method is
11793 // called after the user has selected another tab.
11794 // Pass the anchor that initiated this request allows
11795 // loadError to manipulate the tab content panel via $(a.hash)
11796 ajaxOptions.error(
11797 xhr, status, ui.tab.closest( "li" ).index(), ui.tab[ 0 ] );
11798 }
11799 catch ( error ) {}
11800 }
11801 }, this._superApply( arguments ) );
11802 },
11803
11804 _setOption: function( key, value ) {
11805 // reset cache if switching from cached to not cached
11806 if ( key === "cache" && value === false ) {
11807 this.anchors.removeData( "cache.tabs" );
11808 }
11809 this._super( key, value );
11810 },
11811
11812 _destroy: function() {
11813 this.anchors.removeData( "cache.tabs" );
11814 this._super();
11815 },
11816
11817 url: function( index ){
11818 this.anchors.eq( index ).removeData( "cache.tabs" );
11819 this._superApply( arguments );
11820 }
11821 });
11822
11823 // abort method
11824 $.widget( "ui.tabs", $.ui.tabs, {
11825 abort: function() {
11826 if ( this.xhr ) {
11827 this.xhr.abort();
11828 }
11829 }
11830 });
11831
11832 // spinner
11833 $.widget( "ui.tabs", $.ui.tabs, {
11834 options: {
11835 spinner: "<em>Loading&#8230;</em>"
11836 },
11837 _create: function() {
11838 this._super();
11839 this._on({
11840 tabsbeforeload: function( event, ui ) {
11841 // Don't react to nested tabs or tabs that don't use a spinner
11842 if ( event.target !== this.element[ 0 ] ||
11843 !this.options.spinner ) {
11844 return;
11845 }
11846
11847 var span = ui.tab.find( "span" ),
11848 html = span.html();
11849 span.html( this.options.spinner );
11850 ui.jqXHR.complete(function() {
11851 span.html( html );
11852 });
11853 }
11854 });
11855 }
11856 });
11857
11858 // enable/disable events
11859 $.widget( "ui.tabs", $.ui.tabs, {
11860 options: {
11861 enable: null,
11862 disable: null
11863 },
11864
11865 enable: function( index ) {
11866 var options = this.options,
11867 trigger;
11868
11869 if ( index && options.disabled === true ||
11870 ( $.isArray( options.disabled ) && $.inArray( index, options.disabled ) !== -1 ) ) {
11871 trigger = true;
11872 }
11873
11874 this._superApply( arguments );
11875
11876 if ( trigger ) {
11877 this._trigger( "enable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
11878 }
11879 },
11880
11881 disable: function( index ) {
11882 var options = this.options,
11883 trigger;
11884
11885 if ( index && options.disabled === false ||
11886 ( $.isArray( options.disabled ) && $.inArray( index, options.disabled ) === -1 ) ) {
11887 trigger = true;
11888 }
11889
11890 this._superApply( arguments );
11891
11892 if ( trigger ) {
11893 this._trigger( "disable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
11894 }
11895 }
11896 });
11897
11898 // add/remove methods and events
11899 $.widget( "ui.tabs", $.ui.tabs, {
11900 options: {
11901 add: null,
11902 remove: null,
11903 tabTemplate: "<li><a href='#{href}'><span>#{label}</span></a></li>"
11904 },
11905
11906 add: function( url, label, index ) {
11907 if ( index === undefined ) {
11908 index = this.anchors.length;
11909 }
11910
11911 var doInsertAfter, panel,
11912 options = this.options,
11913 li = $( options.tabTemplate
11914 .replace( /#\{href\}/g, url )
11915 .replace( /#\{label\}/g, label ) ),
11916 id = !url.indexOf( "#" ) ?
11917 url.replace( "#", "" ) :
11918 this._tabId( li );
11919
11920 li.addClass( "ui-state-default ui-corner-top" ).data( "ui-tabs-destroy", true );
11921 li.attr( "aria-controls", id );
11922
11923 doInsertAfter = index >= this.tabs.length;
11924
11925 // try to find an existing element before creating a new one
11926 panel = this.element.find( "#" + id );
11927 if ( !panel.length ) {
11928 panel = this._createPanel( id );
11929 if ( doInsertAfter ) {
11930 if ( index > 0 ) {
11931 panel.insertAfter( this.panels.eq( -1 ) );
11932 } else {
11933 panel.appendTo( this.element );
11934 }
11935 } else {
11936 panel.insertBefore( this.panels[ index ] );
11937 }
11938 }
11939 panel.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ).hide();
11940
11941 if ( doInsertAfter ) {
11942 li.appendTo( this.tablist );
11943 } else {
11944 li.insertBefore( this.tabs[ index ] );
11945 }
11946
11947 options.disabled = $.map( options.disabled, function( n ) {
11948 return n >= index ? ++n : n;
11949 });
11950
11951 this.refresh();
11952 if ( this.tabs.length === 1 && options.active === false ) {
11953 this.option( "active", 0 );
11954 }
11955
11956 this._trigger( "add", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
11957 return this;
11958 },
11959
11960 remove: function( index ) {
11961 index = this._getIndex( index );
11962 var options = this.options,
11963 tab = this.tabs.eq( index ).remove(),
11964 panel = this._getPanelForTab( tab ).remove();
11965
11966 // If selected tab was removed focus tab to the right or
11967 // in case the last tab was removed the tab to the left.
11968 // We check for more than 2 tabs, because if there are only 2,
11969 // then when we remove this tab, there will only be one tab left
11970 // so we don't need to detect which tab to activate.
11971 if ( tab.hasClass( "ui-tabs-active" ) && this.anchors.length > 2 ) {
11972 this._activate( index + ( index + 1 < this.anchors.length ? 1 : -1 ) );
11973 }
11974
11975 options.disabled = $.map(
11976 $.grep( options.disabled, function( n ) {
11977 return n !== index;
11978 }),
11979 function( n ) {
11980 return n >= index ? --n : n;
11981 });
11982
11983 this.refresh();
11984
11985 this._trigger( "remove", null, this._ui( tab.find( "a" )[ 0 ], panel[ 0 ] ) );
11986 return this;
11987 }
11988 });
11989
11990 // length method
11991 $.widget( "ui.tabs", $.ui.tabs, {
11992 length: function() {
11993 return this.anchors.length;
11994 }
11995 });
11996
11997 // panel ids (idPrefix option + title attribute)
11998 $.widget( "ui.tabs", $.ui.tabs, {
11999 options: {
12000 idPrefix: "ui-tabs-"
12001 },
12002
12003 _tabId: function( tab ) {
12004 var a = tab.is( "li" ) ? tab.find( "a[href]" ) : tab;
12005 a = a[0];
12006 return $( a ).closest( "li" ).attr( "aria-controls" ) ||
12007 a.title && a.title.replace( /\s/g, "_" ).replace( /[^\w\u00c0-\uFFFF\-]/g, "" ) ||
12008 this.options.idPrefix + getNextTabId();
12009 }
12010 });
12011
12012 // _createPanel method
12013 $.widget( "ui.tabs", $.ui.tabs, {
12014 options: {
12015 panelTemplate: "<div></div>"
12016 },
12017
12018 _createPanel: function( id ) {
12019 return $( this.options.panelTemplate )
12020 .attr( "id", id )
12021 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
12022 .data( "ui-tabs-destroy", true );
12023 }
12024 });
12025
12026 // selected option
12027 $.widget( "ui.tabs", $.ui.tabs, {
12028 _create: function() {
12029 var options = this.options;
12030 if ( options.active === null && options.selected !== undefined ) {
12031 options.active = options.selected === -1 ? false : options.selected;
12032 }
12033 this._super();
12034 options.selected = options.active;
12035 if ( options.selected === false ) {
12036 options.selected = -1;
12037 }
12038 },
12039
12040 _setOption: function( key, value ) {
12041 if ( key !== "selected" ) {
12042 return this._super( key, value );
12043 }
12044
12045 var options = this.options;
12046 this._super( "active", value === -1 ? false : value );
12047 options.selected = options.active;
12048 if ( options.selected === false ) {
12049 options.selected = -1;
12050 }
12051 },
12052
12053 _eventHandler: function() {
12054 this._superApply( arguments );
12055 this.options.selected = this.options.active;
12056 if ( this.options.selected === false ) {
12057 this.options.selected = -1;
12058 }
12059 }
12060 });
12061
12062 // show and select event
12063 $.widget( "ui.tabs", $.ui.tabs, {
12064 options: {
12065 show: null,
12066 select: null
12067 },
12068 _create: function() {
12069 this._super();
12070 if ( this.options.active !== false ) {
12071 this._trigger( "show", null, this._ui(
12072 this.active.find( ".ui-tabs-anchor" )[ 0 ],
12073 this._getPanelForTab( this.active )[ 0 ] ) );
12074 }
12075 },
12076 _trigger: function( type, event, data ) {
12077 var tab, panel,
12078 ret = this._superApply( arguments );
12079
12080 if ( !ret ) {
12081 return false;
12082 }
12083
12084 if ( type === "beforeActivate" ) {
12085 tab = data.newTab.length ? data.newTab : data.oldTab;
12086 panel = data.newPanel.length ? data.newPanel : data.oldPanel;
12087 ret = this._super( "select", event, {
12088 tab: tab.find( ".ui-tabs-anchor" )[ 0],
12089 panel: panel[ 0 ],
12090 index: tab.closest( "li" ).index()
12091 });
12092 } else if ( type === "activate" && data.newTab.length ) {
12093 ret = this._super( "show", event, {
12094 tab: data.newTab.find( ".ui-tabs-anchor" )[ 0 ],
12095 panel: data.newPanel[ 0 ],
12096 index: data.newTab.closest( "li" ).index()
12097 });
12098 }
12099 return ret;
12100 }
12101 });
12102
12103 // select method
12104 $.widget( "ui.tabs", $.ui.tabs, {
12105 select: function( index ) {
12106 index = this._getIndex( index );
12107 if ( index === -1 ) {
12108 if ( this.options.collapsible && this.options.selected !== -1 ) {
12109 index = this.options.selected;
12110 } else {
12111 return;
12112 }
12113 }
12114 this.anchors.eq( index ).trigger( this.options.event + this.eventNamespace );
12115 }
12116 });
12117
12118 // cookie option
12119 (function() {
12120
12121 var listId = 0;
12122
12123 $.widget( "ui.tabs", $.ui.tabs, {
12124 options: {
12125 cookie: null // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
12126 },
12127 _create: function() {
12128 var options = this.options,
12129 active;
12130 if ( options.active == null && options.cookie ) {
12131 active = parseInt( this._cookie(), 10 );
12132 if ( active === -1 ) {
12133 active = false;
12134 }
12135 options.active = active;
12136 }
12137 this._super();
12138 },
12139 _cookie: function( active ) {
12140 var cookie = [ this.cookie ||
12141 ( this.cookie = this.options.cookie.name || "ui-tabs-" + (++listId) ) ];
12142 if ( arguments.length ) {
12143 cookie.push( active === false ? -1 : active );
12144 cookie.push( this.options.cookie );
12145 }
12146 return $.cookie.apply( null, cookie );
12147 },
12148 _refresh: function() {
12149 this._super();
12150 if ( this.options.cookie ) {
12151 this._cookie( this.options.active, this.options.cookie );
12152 }
12153 },
12154 _eventHandler: function() {
12155 this._superApply( arguments );
12156 if ( this.options.cookie ) {
12157 this._cookie( this.options.active, this.options.cookie );
12158 }
12159 },
12160 _destroy: function() {
12161 this._super();
12162 if ( this.options.cookie ) {
12163 this._cookie( null, this.options.cookie );
12164 }
12165 }
12166 });
12167
12168 })();
12169
12170 // load event
12171 $.widget( "ui.tabs", $.ui.tabs, {
12172 _trigger: function( type, event, data ) {
12173 var _data = $.extend( {}, data );
12174 if ( type === "load" ) {
12175 _data.panel = _data.panel[ 0 ];
12176 _data.tab = _data.tab.find( ".ui-tabs-anchor" )[ 0 ];
12177 }
12178 return this._super( type, event, _data );
12179 }
12180 });
12181
12182 // fx option
12183 // The new animation options (show, hide) conflict with the old show callback.
12184 // The old fx option wins over show/hide anyway (always favor back-compat).
12185 // If a user wants to use the new animation API, they must give up the old API.
12186 $.widget( "ui.tabs", $.ui.tabs, {
12187 options: {
12188 fx: null // e.g. { height: "toggle", opacity: "toggle", duration: 200 }
12189 },
12190
12191 _getFx: function() {
12192 var hide, show,
12193 fx = this.options.fx;
12194
12195 if ( fx ) {
12196 if ( $.isArray( fx ) ) {
12197 hide = fx[ 0 ];
12198 show = fx[ 1 ];
12199 } else {
12200 hide = show = fx;
12201 }
12202 }
12203
12204 return fx ? { show: show, hide: hide } : null;
12205 },
12206
12207 _toggle: function( event, eventData ) {
12208 var that = this,
12209 toShow = eventData.newPanel,
12210 toHide = eventData.oldPanel,
12211 fx = this._getFx();
12212
12213 if ( !fx ) {
12214 return this._super( event, eventData );
12215 }
12216
12217 that.running = true;
12218
12219 function complete() {
12220 that.running = false;
12221 that._trigger( "activate", event, eventData );
12222 }
12223
12224 function show() {
12225 eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
12226
12227 if ( toShow.length && fx.show ) {
12228 toShow
12229 .animate( fx.show, fx.show.duration, function() {
12230 complete();
12231 });
12232 } else {
12233 toShow.show();
12234 complete();
12235 }
12236 }
12237
12238 // start out by hiding, then showing, then completing
12239 if ( toHide.length && fx.hide ) {
12240 toHide.animate( fx.hide, fx.hide.duration, function() {
12241 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
12242 show();
12243 });
12244 } else {
12245 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
12246 toHide.hide();
12247 show();
12248 }
12249 }
12250 });
12251 }
12252
12253 })( jQuery );
12254 (function( $ ) {
12255
12256 var increments = 0;
12257
12258 function addDescribedBy( elem, id ) {
12259 var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ );
12260 describedby.push( id );
12261 elem
12262 .data( "ui-tooltip-id", id )
12263 .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
12264 }
12265
12266 function removeDescribedBy( elem ) {
12267 var id = elem.data( "ui-tooltip-id" ),
12268 describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ),
12269 index = $.inArray( id, describedby );
12270 if ( index !== -1 ) {
12271 describedby.splice( index, 1 );
12272 }
12273
12274 elem.removeData( "ui-tooltip-id" );
12275 describedby = $.trim( describedby.join( " " ) );
12276 if ( describedby ) {
12277 elem.attr( "aria-describedby", describedby );
12278 } else {
12279 elem.removeAttr( "aria-describedby" );
12280 }
12281 }
12282
12283 $.widget( "ui.tooltip", {
12284 version: "1.9.2",
12285 options: {
12286 content: function() {
12287 return $( this ).attr( "title" );
12288 },
12289 hide: true,
12290 // Disabled elements have inconsistent behavior across browsers (#8661)
12291 items: "[title]:not([disabled])",
12292 position: {
12293 my: "left top+15",
12294 at: "left bottom",
12295 collision: "flipfit flip"
12296 },
12297 show: true,
12298 tooltipClass: null,
12299 track: false,
12300
12301 // callbacks
12302 close: null,
12303 open: null
12304 },
12305
12306 _create: function() {
12307 this._on({
12308 mouseover: "open",
12309 focusin: "open"
12310 });
12311
12312 // IDs of generated tooltips, needed for destroy
12313 this.tooltips = {};
12314 // IDs of parent tooltips where we removed the title attribute
12315 this.parents = {};
12316
12317 if ( this.options.disabled ) {
12318 this._disable();
12319 }
12320 },
12321
12322 _setOption: function( key, value ) {
12323 var that = this;
12324
12325 if ( key === "disabled" ) {
12326 this[ value ? "_disable" : "_enable" ]();
12327 this.options[ key ] = value;
12328 // disable element style changes
12329 return;
12330 }
12331
12332 this._super( key, value );
12333
12334 if ( key === "content" ) {
12335 $.each( this.tooltips, function( id, element ) {
12336 that._updateContent( element );
12337 });
12338 }
12339 },
12340
12341 _disable: function() {
12342 var that = this;
12343
12344 // close open tooltips
12345 $.each( this.tooltips, function( id, element ) {
12346 var event = $.Event( "blur" );
12347 event.target = event.currentTarget = element[0];
12348 that.close( event, true );
12349 });
12350
12351 // remove title attributes to prevent native tooltips
12352 this.element.find( this.options.items ).andSelf().each(function() {
12353 var element = $( this );
12354 if ( element.is( "[title]" ) ) {
12355 element
12356 .data( "ui-tooltip-title", element.attr( "title" ) )
12357 .attr( "title", "" );
12358 }
12359 });
12360 },
12361
12362 _enable: function() {
12363 // restore title attributes
12364 this.element.find( this.options.items ).andSelf().each(function() {
12365 var element = $( this );
12366 if ( element.data( "ui-tooltip-title" ) ) {
12367 element.attr( "title", element.data( "ui-tooltip-title" ) );
12368 }
12369 });
12370 },
12371
12372 open: function( event ) {
12373 var that = this,
12374 target = $( event ? event.target : this.element )
12375 // we need closest here due to mouseover bubbling,
12376 // but always pointing at the same event target
12377 .closest( this.options.items );
12378
12379 // No element to show a tooltip for or the tooltip is already open
12380 if ( !target.length || target.data( "ui-tooltip-id" ) ) {
12381 return;
12382 }
12383
12384 if ( target.attr( "title" ) ) {
12385 target.data( "ui-tooltip-title", target.attr( "title" ) );
12386 }
12387
12388 target.data( "ui-tooltip-open", true );
12389
12390 // kill parent tooltips, custom or native, for hover
12391 if ( event && event.type === "mouseover" ) {
12392 target.parents().each(function() {
12393 var parent = $( this ),
12394 blurEvent;
12395 if ( parent.data( "ui-tooltip-open" ) ) {
12396 blurEvent = $.Event( "blur" );
12397 blurEvent.target = blurEvent.currentTarget = this;
12398 that.close( blurEvent, true );
12399 }
12400 if ( parent.attr( "title" ) ) {
12401 parent.uniqueId();
12402 that.parents[ this.id ] = {
12403 element: this,
12404 title: parent.attr( "title" )
12405 };
12406 parent.attr( "title", "" );
12407 }
12408 });
12409 }
12410
12411 this._updateContent( target, event );
12412 },
12413
12414 _updateContent: function( target, event ) {
12415 var content,
12416 contentOption = this.options.content,
12417 that = this,
12418 eventType = event ? event.type : null;
12419
12420 if ( typeof contentOption === "string" ) {
12421 return this._open( event, target, contentOption );
12422 }
12423
12424 content = contentOption.call( target[0], function( response ) {
12425 // ignore async response if tooltip was closed already
12426 if ( !target.data( "ui-tooltip-open" ) ) {
12427 return;
12428 }
12429 // IE may instantly serve a cached response for ajax requests
12430 // delay this call to _open so the other call to _open runs first
12431 that._delay(function() {
12432 // jQuery creates a special event for focusin when it doesn't
12433 // exist natively. To improve performance, the native event
12434 // object is reused and the type is changed. Therefore, we can't
12435 // rely on the type being correct after the event finished
12436 // bubbling, so we set it back to the previous value. (#8740)
12437 if ( event ) {
12438 event.type = eventType;
12439 }
12440 this._open( event, target, response );
12441 });
12442 });
12443 if ( content ) {
12444 this._open( event, target, content );
12445 }
12446 },
12447
12448 _open: function( event, target, content ) {
12449 var tooltip, events, delayedShow,
12450 positionOption = $.extend( {}, this.options.position );
12451
12452 if ( !content ) {
12453 return;
12454 }
12455
12456 // Content can be updated multiple times. If the tooltip already
12457 // exists, then just update the content and bail.
12458 tooltip = this._find( target );
12459 if ( tooltip.length ) {
12460 tooltip.find( ".ui-tooltip-content" ).html( content );
12461 return;
12462 }
12463
12464 // if we have a title, clear it to prevent the native tooltip
12465 // we have to check first to avoid defining a title if none exists
12466 // (we don't want to cause an element to start matching [title])
12467 //
12468 // We use removeAttr only for key events, to allow IE to export the correct
12469 // accessible attributes. For mouse events, set to empty string to avoid
12470 // native tooltip showing up (happens only when removing inside mouseover).
12471 if ( target.is( "[title]" ) ) {
12472 if ( event && event.type === "mouseover" ) {
12473 target.attr( "title", "" );
12474 } else {
12475 target.removeAttr( "title" );
12476 }
12477 }
12478
12479 tooltip = this._tooltip( target );
12480 addDescribedBy( target, tooltip.attr( "id" ) );
12481 tooltip.find( ".ui-tooltip-content" ).html( content );
12482
12483 function position( event ) {
12484 positionOption.of = event;
12485 if ( tooltip.is( ":hidden" ) ) {
12486 return;
12487 }
12488 tooltip.position( positionOption );
12489 }
12490 if ( this.options.track && event && /^mouse/.test( event.type ) ) {
12491 this._on( this.document, {
12492 mousemove: position
12493 });
12494 // trigger once to override element-relative positioning
12495 position( event );
12496 } else {
12497 tooltip.position( $.extend({
12498 of: target
12499 }, this.options.position ) );
12500 }
12501
12502 tooltip.hide();
12503
12504 this._show( tooltip, this.options.show );
12505 // Handle tracking tooltips that are shown with a delay (#8644). As soon
12506 // as the tooltip is visible, position the tooltip using the most recent
12507 // event.
12508 if ( this.options.show && this.options.show.delay ) {
12509 delayedShow = setInterval(function() {
12510 if ( tooltip.is( ":visible" ) ) {
12511 position( positionOption.of );
12512 clearInterval( delayedShow );
12513 }
12514 }, $.fx.interval );
12515 }
12516
12517 this._trigger( "open", event, { tooltip: tooltip } );
12518
12519 events = {
12520 keyup: function( event ) {
12521 if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
12522 var fakeEvent = $.Event(event);
12523 fakeEvent.currentTarget = target[0];
12524 this.close( fakeEvent, true );
12525 }
12526 },
12527 remove: function() {
12528 this._removeTooltip( tooltip );
12529 }
12530 };
12531 if ( !event || event.type === "mouseover" ) {
12532 events.mouseleave = "close";
12533 }
12534 if ( !event || event.type === "focusin" ) {
12535 events.focusout = "close";
12536 }
12537 this._on( true, target, events );
12538 },
12539
12540 close: function( event ) {
12541 var that = this,
12542 target = $( event ? event.currentTarget : this.element ),
12543 tooltip = this._find( target );
12544
12545 // disabling closes the tooltip, so we need to track when we're closing
12546 // to avoid an infinite loop in case the tooltip becomes disabled on close
12547 if ( this.closing ) {
12548 return;
12549 }
12550
12551 // only set title if we had one before (see comment in _open())
12552 if ( target.data( "ui-tooltip-title" ) ) {
12553 target.attr( "title", target.data( "ui-tooltip-title" ) );
12554 }
12555
12556 removeDescribedBy( target );
12557
12558 tooltip.stop( true );
12559 this._hide( tooltip, this.options.hide, function() {
12560 that._removeTooltip( $( this ) );
12561 });
12562
12563 target.removeData( "ui-tooltip-open" );
12564 this._off( target, "mouseleave focusout keyup" );
12565 // Remove 'remove' binding only on delegated targets
12566 if ( target[0] !== this.element[0] ) {
12567 this._off( target, "remove" );
12568 }
12569 this._off( this.document, "mousemove" );
12570
12571 if ( event && event.type === "mouseleave" ) {
12572 $.each( this.parents, function( id, parent ) {
12573 $( parent.element ).attr( "title", parent.title );
12574 delete that.parents[ id ];
12575 });
12576 }
12577
12578 this.closing = true;
12579 this._trigger( "close", event, { tooltip: tooltip } );
12580 this.closing = false;
12581 },
12582
12583 _tooltip: function( element ) {
12584 var id = "ui-tooltip-" + increments++,
12585 tooltip = $( "<div>" )
12586 .attr({
12587 id: id,
12588 role: "tooltip"
12589 })
12590 .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " +
12591 ( this.options.tooltipClass || "" ) );
12592 $( "<div>" )
12593 .addClass( "ui-tooltip-content" )
12594 .appendTo( tooltip );
12595 tooltip.appendTo( this.document[0].body );
12596 if ( $.fn.bgiframe ) {
12597 tooltip.bgiframe();
12598 }
12599 this.tooltips[ id ] = element;
12600 return tooltip;
12601 },
12602
12603 _find: function( target ) {
12604 var id = target.data( "ui-tooltip-id" );
12605 return id ? $( "#" + id ) : $();
12606 },
12607
12608 _removeTooltip: function( tooltip ) {
12609 tooltip.remove();
12610 delete this.tooltips[ tooltip.attr( "id" ) ];
12611 },
12612
12613 _destroy: function() {
12614 var that = this;
12615
12616 // close open tooltips
12617 $.each( this.tooltips, function( id, element ) {
12618 // Delegate to close method to handle common cleanup
12619 var event = $.Event( "blur" );
12620 event.target = event.currentTarget = element[0];
12621 that.close( event, true );
12622
12623 // Remove immediately; destroying an open tooltip doesn't use the
12624 // hide animation
12625 $( "#" + id ).remove();
12626
12627 // Restore the title
12628 if ( element.data( "ui-tooltip-title" ) ) {
12629 element.attr( "title", element.data( "ui-tooltip-title" ) );
12630 element.removeData( "ui-tooltip-title" );
12631 }
12632 });
12633 }
12634 });
12635
12636 }( jQuery ) );
12637 ;(jQuery.effects || (function($, undefined) {
12638
12639 var backCompat = $.uiBackCompat !== false,
12640 // prefix used for storing data on .data()
12641 dataSpace = "ui-effects-";
12642
12643 $.effects = {
12644 effect: {}
12645 };
12646
12647 /*!
12648 * jQuery Color Animations v2.0.0
12649 * http://jquery.com/
12650 *
12651 * Copyright 2012 jQuery Foundation and other contributors
12652 * Released under the MIT license.
12653 * http://jquery.org/license
12654 *
12655 * Date: Mon Aug 13 13:41:02 2012 -0500
12656 */
12657 (function( jQuery, undefined ) {
12658
12659 var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor".split(" "),
12660
12661 // plusequals test for += 100 -= 100
12662 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
12663 // a set of RE's that can match strings and generate color tuples.
12664 stringParsers = [{
12665 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,
12666 parse: function( execResult ) {
12667 return [
12668 execResult[ 1 ],
12669 execResult[ 2 ],
12670 execResult[ 3 ],
12671 execResult[ 4 ]
12672 ];
12673 }
12674 }, {
12675 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,
12676 parse: function( execResult ) {
12677 return [
12678 execResult[ 1 ] * 2.55,
12679 execResult[ 2 ] * 2.55,
12680 execResult[ 3 ] * 2.55,
12681 execResult[ 4 ]
12682 ];
12683 }
12684 }, {
12685 // this regex ignores A-F because it's compared against an already lowercased string
12686 re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
12687 parse: function( execResult ) {
12688 return [
12689 parseInt( execResult[ 1 ], 16 ),
12690 parseInt( execResult[ 2 ], 16 ),
12691 parseInt( execResult[ 3 ], 16 )
12692 ];
12693 }
12694 }, {
12695 // this regex ignores A-F because it's compared against an already lowercased string
12696 re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
12697 parse: function( execResult ) {
12698 return [
12699 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
12700 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
12701 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
12702 ];
12703 }
12704 }, {
12705 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,
12706 space: "hsla",
12707 parse: function( execResult ) {
12708 return [
12709 execResult[ 1 ],
12710 execResult[ 2 ] / 100,
12711 execResult[ 3 ] / 100,
12712 execResult[ 4 ]
12713 ];
12714 }
12715 }],
12716
12717 // jQuery.Color( )
12718 color = jQuery.Color = function( color, green, blue, alpha ) {
12719 return new jQuery.Color.fn.parse( color, green, blue, alpha );
12720 },
12721 spaces = {
12722 rgba: {
12723 props: {
12724 red: {
12725 idx: 0,
12726 type: "byte"
12727 },
12728 green: {
12729 idx: 1,
12730 type: "byte"
12731 },
12732 blue: {
12733 idx: 2,
12734 type: "byte"
12735 }
12736 }
12737 },
12738
12739 hsla: {
12740 props: {
12741 hue: {
12742 idx: 0,
12743 type: "degrees"
12744 },
12745 saturation: {
12746 idx: 1,
12747 type: "percent"
12748 },
12749 lightness: {
12750 idx: 2,
12751 type: "percent"
12752 }
12753 }
12754 }
12755 },
12756 propTypes = {
12757 "byte": {
12758 floor: true,
12759 max: 255
12760 },
12761 "percent": {
12762 max: 1
12763 },
12764 "degrees": {
12765 mod: 360,
12766 floor: true
12767 }
12768 },
12769 support = color.support = {},
12770
12771 // element for support tests
12772 supportElem = jQuery( "<p>" )[ 0 ],
12773
12774 // colors = jQuery.Color.names
12775 colors,
12776
12777 // local aliases of functions called often
12778 each = jQuery.each;
12779
12780 // determine rgba support immediately
12781 supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
12782 support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
12783
12784 // define cache name and alpha properties
12785 // for rgba and hsla spaces
12786 each( spaces, function( spaceName, space ) {
12787 space.cache = "_" + spaceName;
12788 space.props.alpha = {
12789 idx: 3,
12790 type: "percent",
12791 def: 1
12792 };
12793 });
12794
12795 function clamp( value, prop, allowEmpty ) {
12796 var type = propTypes[ prop.type ] || {};
12797
12798 if ( value == null ) {
12799 return (allowEmpty || !prop.def) ? null : prop.def;
12800 }
12801
12802 // ~~ is an short way of doing floor for positive numbers
12803 value = type.floor ? ~~value : parseFloat( value );
12804
12805 // IE will pass in empty strings as value for alpha,
12806 // which will hit this case
12807 if ( isNaN( value ) ) {
12808 return prop.def;
12809 }
12810
12811 if ( type.mod ) {
12812 // we add mod before modding to make sure that negatives values
12813 // get converted properly: -10 -> 350
12814 return (value + type.mod) % type.mod;
12815 }
12816
12817 // for now all property types without mod have min and max
12818 return 0 > value ? 0 : type.max < value ? type.max : value;
12819 }
12820
12821 function stringParse( string ) {
12822 var inst = color(),
12823 rgba = inst._rgba = [];
12824
12825 string = string.toLowerCase();
12826
12827 each( stringParsers, function( i, parser ) {
12828 var parsed,
12829 match = parser.re.exec( string ),
12830 values = match && parser.parse( match ),
12831 spaceName = parser.space || "rgba";
12832
12833 if ( values ) {
12834 parsed = inst[ spaceName ]( values );
12835
12836 // if this was an rgba parse the assignment might happen twice
12837 // oh well....
12838 inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
12839 rgba = inst._rgba = parsed._rgba;
12840
12841 // exit each( stringParsers ) here because we matched
12842 return false;
12843 }
12844 });
12845
12846 // Found a stringParser that handled it
12847 if ( rgba.length ) {
12848
12849 // if this came from a parsed string, force "transparent" when alpha is 0
12850 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
12851 if ( rgba.join() === "0,0,0,0" ) {
12852 jQuery.extend( rgba, colors.transparent );
12853 }
12854 return inst;
12855 }
12856
12857 // named colors
12858 return colors[ string ];
12859 }
12860
12861 color.fn = jQuery.extend( color.prototype, {
12862 parse: function( red, green, blue, alpha ) {
12863 if ( red === undefined ) {
12864 this._rgba = [ null, null, null, null ];
12865 return this;
12866 }
12867 if ( red.jquery || red.nodeType ) {
12868 red = jQuery( red ).css( green );
12869 green = undefined;
12870 }
12871
12872 var inst = this,
12873 type = jQuery.type( red ),
12874 rgba = this._rgba = [];
12875
12876 // more than 1 argument specified - assume ( red, green, blue, alpha )
12877 if ( green !== undefined ) {
12878 red = [ red, green, blue, alpha ];
12879 type = "array";
12880 }
12881
12882 if ( type === "string" ) {
12883 return this.parse( stringParse( red ) || colors._default );
12884 }
12885
12886 if ( type === "array" ) {
12887 each( spaces.rgba.props, function( key, prop ) {
12888 rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
12889 });
12890 return this;
12891 }
12892
12893 if ( type === "object" ) {
12894 if ( red instanceof color ) {
12895 each( spaces, function( spaceName, space ) {
12896 if ( red[ space.cache ] ) {
12897 inst[ space.cache ] = red[ space.cache ].slice();
12898 }
12899 });
12900 } else {
12901 each( spaces, function( spaceName, space ) {
12902 var cache = space.cache;
12903 each( space.props, function( key, prop ) {
12904
12905 // if the cache doesn't exist, and we know how to convert
12906 if ( !inst[ cache ] && space.to ) {
12907
12908 // if the value was null, we don't need to copy it
12909 // if the key was alpha, we don't need to copy it either
12910 if ( key === "alpha" || red[ key ] == null ) {
12911 return;
12912 }
12913 inst[ cache ] = space.to( inst._rgba );
12914 }
12915
12916 // this is the only case where we allow nulls for ALL properties.
12917 // call clamp with alwaysAllowEmpty
12918 inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
12919 });
12920
12921 // everything defined but alpha?
12922 if ( inst[ cache ] && $.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
12923 // use the default of 1
12924 inst[ cache ][ 3 ] = 1;
12925 if ( space.from ) {
12926 inst._rgba = space.from( inst[ cache ] );
12927 }
12928 }
12929 });
12930 }
12931 return this;
12932 }
12933 },
12934 is: function( compare ) {
12935 var is = color( compare ),
12936 same = true,
12937 inst = this;
12938
12939 each( spaces, function( _, space ) {
12940 var localCache,
12941 isCache = is[ space.cache ];
12942 if (isCache) {
12943 localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
12944 each( space.props, function( _, prop ) {
12945 if ( isCache[ prop.idx ] != null ) {
12946 same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
12947 return same;
12948 }
12949 });
12950 }
12951 return same;
12952 });
12953 return same;
12954 },
12955 _space: function() {
12956 var used = [],
12957 inst = this;
12958 each( spaces, function( spaceName, space ) {
12959 if ( inst[ space.cache ] ) {
12960 used.push( spaceName );
12961 }
12962 });
12963 return used.pop();
12964 },
12965 transition: function( other, distance ) {
12966 var end = color( other ),
12967 spaceName = end._space(),
12968 space = spaces[ spaceName ],
12969 startColor = this.alpha() === 0 ? color( "transparent" ) : this,
12970 start = startColor[ space.cache ] || space.to( startColor._rgba ),
12971 result = start.slice();
12972
12973 end = end[ space.cache ];
12974 each( space.props, function( key, prop ) {
12975 var index = prop.idx,
12976 startValue = start[ index ],
12977 endValue = end[ index ],
12978 type = propTypes[ prop.type ] || {};
12979
12980 // if null, don't override start value
12981 if ( endValue === null ) {
12982 return;
12983 }
12984 // if null - use end
12985 if ( startValue === null ) {
12986 result[ index ] = endValue;
12987 } else {
12988 if ( type.mod ) {
12989 if ( endValue - startValue > type.mod / 2 ) {
12990 startValue += type.mod;
12991 } else if ( startValue - endValue > type.mod / 2 ) {
12992 startValue -= type.mod;
12993 }
12994 }
12995 result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
12996 }
12997 });
12998 return this[ spaceName ]( result );
12999 },
13000 blend: function( opaque ) {
13001 // if we are already opaque - return ourself
13002 if ( this._rgba[ 3 ] === 1 ) {
13003 return this;
13004 }
13005
13006 var rgb = this._rgba.slice(),
13007 a = rgb.pop(),
13008 blend = color( opaque )._rgba;
13009
13010 return color( jQuery.map( rgb, function( v, i ) {
13011 return ( 1 - a ) * blend[ i ] + a * v;
13012 }));
13013 },
13014 toRgbaString: function() {
13015 var prefix = "rgba(",
13016 rgba = jQuery.map( this._rgba, function( v, i ) {
13017 return v == null ? ( i > 2 ? 1 : 0 ) : v;
13018 });
13019
13020 if ( rgba[ 3 ] === 1 ) {
13021 rgba.pop();
13022 prefix = "rgb(";
13023 }
13024
13025 return prefix + rgba.join() + ")";
13026 },
13027 toHslaString: function() {
13028 var prefix = "hsla(",
13029 hsla = jQuery.map( this.hsla(), function( v, i ) {
13030 if ( v == null ) {
13031 v = i > 2 ? 1 : 0;
13032 }
13033
13034 // catch 1 and 2
13035 if ( i && i < 3 ) {
13036 v = Math.round( v * 100 ) + "%";
13037 }
13038 return v;
13039 });
13040
13041 if ( hsla[ 3 ] === 1 ) {
13042 hsla.pop();
13043 prefix = "hsl(";
13044 }
13045 return prefix + hsla.join() + ")";
13046 },
13047 toHexString: function( includeAlpha ) {
13048 var rgba = this._rgba.slice(),
13049 alpha = rgba.pop();
13050
13051 if ( includeAlpha ) {
13052 rgba.push( ~~( alpha * 255 ) );
13053 }
13054
13055 return "#" + jQuery.map( rgba, function( v ) {
13056
13057 // default to 0 when nulls exist
13058 v = ( v || 0 ).toString( 16 );
13059 return v.length === 1 ? "0" + v : v;
13060 }).join("");
13061 },
13062 toString: function() {
13063 return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
13064 }
13065 });
13066 color.fn.parse.prototype = color.fn;
13067
13068 // hsla conversions adapted from:
13069 // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
13070
13071 function hue2rgb( p, q, h ) {
13072 h = ( h + 1 ) % 1;
13073 if ( h * 6 < 1 ) {
13074 return p + (q - p) * h * 6;
13075 }
13076 if ( h * 2 < 1) {
13077 return q;
13078 }
13079 if ( h * 3 < 2 ) {
13080 return p + (q - p) * ((2/3) - h) * 6;
13081 }
13082 return p;
13083 }
13084
13085 spaces.hsla.to = function ( rgba ) {
13086 if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
13087 return [ null, null, null, rgba[ 3 ] ];
13088 }
13089 var r = rgba[ 0 ] / 255,
13090 g = rgba[ 1 ] / 255,
13091 b = rgba[ 2 ] / 255,
13092 a = rgba[ 3 ],
13093 max = Math.max( r, g, b ),
13094 min = Math.min( r, g, b ),
13095 diff = max - min,
13096 add = max + min,
13097 l = add * 0.5,
13098 h, s;
13099
13100 if ( min === max ) {
13101 h = 0;
13102 } else if ( r === max ) {
13103 h = ( 60 * ( g - b ) / diff ) + 360;
13104 } else if ( g === max ) {
13105 h = ( 60 * ( b - r ) / diff ) + 120;
13106 } else {
13107 h = ( 60 * ( r - g ) / diff ) + 240;
13108 }
13109
13110 if ( l === 0 || l === 1 ) {
13111 s = l;
13112 } else if ( l <= 0.5 ) {
13113 s = diff / add;
13114 } else {
13115 s = diff / ( 2 - add );
13116 }
13117 return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
13118 };
13119
13120 spaces.hsla.from = function ( hsla ) {
13121 if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
13122 return [ null, null, null, hsla[ 3 ] ];
13123 }
13124 var h = hsla[ 0 ] / 360,
13125 s = hsla[ 1 ],
13126 l = hsla[ 2 ],
13127 a = hsla[ 3 ],
13128 q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
13129 p = 2 * l - q;
13130
13131 return [
13132 Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
13133 Math.round( hue2rgb( p, q, h ) * 255 ),
13134 Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
13135 a
13136 ];
13137 };
13138
13139
13140 each( spaces, function( spaceName, space ) {
13141 var props = space.props,
13142 cache = space.cache,
13143 to = space.to,
13144 from = space.from;
13145
13146 // makes rgba() and hsla()
13147 color.fn[ spaceName ] = function( value ) {
13148
13149 // generate a cache for this space if it doesn't exist
13150 if ( to && !this[ cache ] ) {
13151 this[ cache ] = to( this._rgba );
13152 }
13153 if ( value === undefined ) {
13154 return this[ cache ].slice();
13155 }
13156
13157 var ret,
13158 type = jQuery.type( value ),
13159 arr = ( type === "array" || type === "object" ) ? value : arguments,
13160 local = this[ cache ].slice();
13161
13162 each( props, function( key, prop ) {
13163 var val = arr[ type === "object" ? key : prop.idx ];
13164 if ( val == null ) {
13165 val = local[ prop.idx ];
13166 }
13167 local[ prop.idx ] = clamp( val, prop );
13168 });
13169
13170 if ( from ) {
13171 ret = color( from( local ) );
13172 ret[ cache ] = local;
13173 return ret;
13174 } else {
13175 return color( local );
13176 }
13177 };
13178
13179 // makes red() green() blue() alpha() hue() saturation() lightness()
13180 each( props, function( key, prop ) {
13181 // alpha is included in more than one space
13182 if ( color.fn[ key ] ) {
13183 return;
13184 }
13185 color.fn[ key ] = function( value ) {
13186 var vtype = jQuery.type( value ),
13187 fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
13188 local = this[ fn ](),
13189 cur = local[ prop.idx ],
13190 match;
13191
13192 if ( vtype === "undefined" ) {
13193 return cur;
13194 }
13195
13196 if ( vtype === "function" ) {
13197 value = value.call( this, cur );
13198 vtype = jQuery.type( value );
13199 }
13200 if ( value == null && prop.empty ) {
13201 return this;
13202 }
13203 if ( vtype === "string" ) {
13204 match = rplusequals.exec( value );
13205 if ( match ) {
13206 value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
13207 }
13208 }
13209 local[ prop.idx ] = value;
13210 return this[ fn ]( local );
13211 };
13212 });
13213 });
13214
13215 // add .fx.step functions
13216 each( stepHooks, function( i, hook ) {
13217 jQuery.cssHooks[ hook ] = {
13218 set: function( elem, value ) {
13219 var parsed, curElem,
13220 backgroundColor = "";
13221
13222 if ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) {
13223 value = color( parsed || value );
13224 if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
13225 curElem = hook === "backgroundColor" ? elem.parentNode : elem;
13226 while (
13227 (backgroundColor === "" || backgroundColor === "transparent") &&
13228 curElem && curElem.style
13229 ) {
13230 try {
13231 backgroundColor = jQuery.css( curElem, "backgroundColor" );
13232 curElem = curElem.parentNode;
13233 } catch ( e ) {
13234 }
13235 }
13236
13237 value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
13238 backgroundColor :
13239 "_default" );
13240 }
13241
13242 value = value.toRgbaString();
13243 }
13244 try {
13245 elem.style[ hook ] = value;
13246 } catch( error ) {
13247 // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
13248 }
13249 }
13250 };
13251 jQuery.fx.step[ hook ] = function( fx ) {
13252 if ( !fx.colorInit ) {
13253 fx.start = color( fx.elem, hook );
13254 fx.end = color( fx.end );
13255 fx.colorInit = true;
13256 }
13257 jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
13258 };
13259 });
13260
13261 jQuery.cssHooks.borderColor = {
13262 expand: function( value ) {
13263 var expanded = {};
13264
13265 each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
13266 expanded[ "border" + part + "Color" ] = value;
13267 });
13268 return expanded;
13269 }
13270 };
13271
13272 // Basic color names only.
13273 // Usage of any of the other color names requires adding yourself or including
13274 // jquery.color.svg-names.js.
13275 colors = jQuery.Color.names = {
13276 // 4.1. Basic color keywords
13277 aqua: "#00ffff",
13278 black: "#000000",
13279 blue: "#0000ff",
13280 fuchsia: "#ff00ff",
13281 gray: "#808080",
13282 green: "#008000",
13283 lime: "#00ff00",
13284 maroon: "#800000",
13285 navy: "#000080",
13286 olive: "#808000",
13287 purple: "#800080",
13288 red: "#ff0000",
13289 silver: "#c0c0c0",
13290 teal: "#008080",
13291 white: "#ffffff",
13292 yellow: "#ffff00",
13293
13294 // 4.2.3. "transparent" color keyword
13295 transparent: [ null, null, null, 0 ],
13296
13297 _default: "#ffffff"
13298 };
13299
13300 })( jQuery );
13301
13302
13303
13304 /******************************************************************************/
13305 /****************************** CLASS ANIMATIONS ******************************/
13306 /******************************************************************************/
13307 (function() {
13308
13309 var classAnimationActions = [ "add", "remove", "toggle" ],
13310 shorthandStyles = {
13311 border: 1,
13312 borderBottom: 1,
13313 borderColor: 1,
13314 borderLeft: 1,
13315 borderRight: 1,
13316 borderTop: 1,
13317 borderWidth: 1,
13318 margin: 1,
13319 padding: 1
13320 };
13321
13322 $.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) {
13323 $.fx.step[ prop ] = function( fx ) {
13324 if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
13325 jQuery.style( fx.elem, prop, fx.end );
13326 fx.setAttr = true;
13327 }
13328 };
13329 });
13330
13331 function getElementStyles() {
13332 var style = this.ownerDocument.defaultView ?
13333 this.ownerDocument.defaultView.getComputedStyle( this, null ) :
13334 this.currentStyle,
13335 newStyle = {},
13336 key,
13337 len;
13338
13339 // webkit enumerates style porperties
13340 if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
13341 len = style.length;
13342 while ( len-- ) {
13343 key = style[ len ];
13344 if ( typeof style[ key ] === "string" ) {
13345 newStyle[ $.camelCase( key ) ] = style[ key ];
13346 }
13347 }
13348 } else {
13349 for ( key in style ) {
13350 if ( typeof style[ key ] === "string" ) {
13351 newStyle[ key ] = style[ key ];
13352 }
13353 }
13354 }
13355
13356 return newStyle;
13357 }
13358
13359
13360 function styleDifference( oldStyle, newStyle ) {
13361 var diff = {},
13362 name, value;
13363
13364 for ( name in newStyle ) {
13365 value = newStyle[ name ];
13366 if ( oldStyle[ name ] !== value ) {
13367 if ( !shorthandStyles[ name ] ) {
13368 if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
13369 diff[ name ] = value;
13370 }
13371 }
13372 }
13373 }
13374
13375 return diff;
13376 }
13377
13378 $.effects.animateClass = function( value, duration, easing, callback ) {
13379 var o = $.speed( duration, easing, callback );
13380
13381 return this.queue( function() {
13382 var animated = $( this ),
13383 baseClass = animated.attr( "class" ) || "",
13384 applyClassChange,
13385 allAnimations = o.children ? animated.find( "*" ).andSelf() : animated;
13386
13387 // map the animated objects to store the original styles.
13388 allAnimations = allAnimations.map(function() {
13389 var el = $( this );
13390 return {
13391 el: el,
13392 start: getElementStyles.call( this )
13393 };
13394 });
13395
13396 // apply class change
13397 applyClassChange = function() {
13398 $.each( classAnimationActions, function(i, action) {
13399 if ( value[ action ] ) {
13400 animated[ action + "Class" ]( value[ action ] );
13401 }
13402 });
13403 };
13404 applyClassChange();
13405
13406 // map all animated objects again - calculate new styles and diff
13407 allAnimations = allAnimations.map(function() {
13408 this.end = getElementStyles.call( this.el[ 0 ] );
13409 this.diff = styleDifference( this.start, this.end );
13410 return this;
13411 });
13412
13413 // apply original class
13414 animated.attr( "class", baseClass );
13415
13416 // map all animated objects again - this time collecting a promise
13417 allAnimations = allAnimations.map(function() {
13418 var styleInfo = this,
13419 dfd = $.Deferred(),
13420 opts = jQuery.extend({}, o, {
13421 queue: false,
13422 complete: function() {
13423 dfd.resolve( styleInfo );
13424 }
13425 });
13426
13427 this.el.animate( this.diff, opts );
13428 return dfd.promise();
13429 });
13430
13431 // once all animations have completed:
13432 $.when.apply( $, allAnimations.get() ).done(function() {
13433
13434 // set the final class
13435 applyClassChange();
13436
13437 // for each animated element,
13438 // clear all css properties that were animated
13439 $.each( arguments, function() {
13440 var el = this.el;
13441 $.each( this.diff, function(key) {
13442 el.css( key, '' );
13443 });
13444 });
13445
13446 // this is guarnteed to be there if you use jQuery.speed()
13447 // it also handles dequeuing the next anim...
13448 o.complete.call( animated[ 0 ] );
13449 });
13450 });
13451 };
13452
13453 $.fn.extend({
13454 _addClass: $.fn.addClass,
13455 addClass: function( classNames, speed, easing, callback ) {
13456 return speed ?
13457 $.effects.animateClass.call( this,
13458 { add: classNames }, speed, easing, callback ) :
13459 this._addClass( classNames );
13460 },
13461
13462 _removeClass: $.fn.removeClass,
13463 removeClass: function( classNames, speed, easing, callback ) {
13464 return speed ?
13465 $.effects.animateClass.call( this,
13466 { remove: classNames }, speed, easing, callback ) :
13467 this._removeClass( classNames );
13468 },
13469
13470 _toggleClass: $.fn.toggleClass,
13471 toggleClass: function( classNames, force, speed, easing, callback ) {
13472 if ( typeof force === "boolean" || force === undefined ) {
13473 if ( !speed ) {
13474 // without speed parameter
13475 return this._toggleClass( classNames, force );
13476 } else {
13477 return $.effects.animateClass.call( this,
13478 (force ? { add: classNames } : { remove: classNames }),
13479 speed, easing, callback );
13480 }
13481 } else {
13482 // without force parameter
13483 return $.effects.animateClass.call( this,
13484 { toggle: classNames }, force, speed, easing );
13485 }
13486 },
13487
13488 switchClass: function( remove, add, speed, easing, callback) {
13489 return $.effects.animateClass.call( this, {
13490 add: add,
13491 remove: remove
13492 }, speed, easing, callback );
13493 }
13494 });
13495
13496 })();
13497
13498 /******************************************************************************/
13499 /*********************************** EFFECTS **********************************/
13500 /******************************************************************************/
13501
13502 (function() {
13503
13504 $.extend( $.effects, {
13505 version: "1.9.2",
13506
13507 // Saves a set of properties in a data storage
13508 save: function( element, set ) {
13509 for( var i=0; i < set.length; i++ ) {
13510 if ( set[ i ] !== null ) {
13511 element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
13512 }
13513 }
13514 },
13515
13516 // Restores a set of previously saved properties from a data storage
13517 restore: function( element, set ) {
13518 var val, i;
13519 for( i=0; i < set.length; i++ ) {
13520 if ( set[ i ] !== null ) {
13521 val = element.data( dataSpace + set[ i ] );
13522 // support: jQuery 1.6.2
13523 // http://bugs.jquery.com/ticket/9917
13524 // jQuery 1.6.2 incorrectly returns undefined for any falsy value.
13525 // We can't differentiate between "" and 0 here, so we just assume
13526 // empty string since it's likely to be a more common value...
13527 if ( val === undefined ) {
13528 val = "";
13529 }
13530 element.css( set[ i ], val );
13531 }
13532 }
13533 },
13534
13535 setMode: function( el, mode ) {
13536 if (mode === "toggle") {
13537 mode = el.is( ":hidden" ) ? "show" : "hide";
13538 }
13539 return mode;
13540 },
13541
13542 // Translates a [top,left] array into a baseline value
13543 // this should be a little more flexible in the future to handle a string & hash
13544 getBaseline: function( origin, original ) {
13545 var y, x;
13546 switch ( origin[ 0 ] ) {
13547 case "top": y = 0; break;
13548 case "middle": y = 0.5; break;
13549 case "bottom": y = 1; break;
13550 default: y = origin[ 0 ] / original.height;
13551 }
13552 switch ( origin[ 1 ] ) {
13553 case "left": x = 0; break;
13554 case "center": x = 0.5; break;
13555 case "right": x = 1; break;
13556 default: x = origin[ 1 ] / original.width;
13557 }
13558 return {
13559 x: x,
13560 y: y
13561 };
13562 },
13563
13564 // Wraps the element around a wrapper that copies position properties
13565 createWrapper: function( element ) {
13566
13567 // if the element is already wrapped, return it
13568 if ( element.parent().is( ".ui-effects-wrapper" )) {
13569 return element.parent();
13570 }
13571
13572 // wrap the element
13573 var props = {
13574 width: element.outerWidth(true),
13575 height: element.outerHeight(true),
13576 "float": element.css( "float" )
13577 },
13578 wrapper = $( "<div></div>" )
13579 .addClass( "ui-effects-wrapper" )
13580 .css({
13581 fontSize: "100%",
13582 background: "transparent",
13583 border: "none",
13584 margin: 0,
13585 padding: 0
13586 }),
13587 // Store the size in case width/height are defined in % - Fixes #5245
13588 size = {
13589 width: element.width(),
13590 height: element.height()
13591 },
13592 active = document.activeElement;
13593
13594 // support: Firefox
13595 // Firefox incorrectly exposes anonymous content
13596 // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
13597 try {
13598 active.id;
13599 } catch( e ) {
13600 active = document.body;
13601 }
13602
13603 element.wrap( wrapper );
13604
13605 // Fixes #7595 - Elements lose focus when wrapped.
13606 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
13607 $( active ).focus();
13608 }
13609
13610 wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element
13611
13612 // transfer positioning properties to the wrapper
13613 if ( element.css( "position" ) === "static" ) {
13614 wrapper.css({ position: "relative" });
13615 element.css({ position: "relative" });
13616 } else {
13617 $.extend( props, {
13618 position: element.css( "position" ),
13619 zIndex: element.css( "z-index" )
13620 });
13621 $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
13622 props[ pos ] = element.css( pos );
13623 if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
13624 props[ pos ] = "auto";
13625 }
13626 });
13627 element.css({
13628 position: "relative",
13629 top: 0,
13630 left: 0,
13631 right: "auto",
13632 bottom: "auto"
13633 });
13634 }
13635 element.css(size);
13636
13637 return wrapper.css( props ).show();
13638 },
13639
13640 removeWrapper: function( element ) {
13641 var active = document.activeElement;
13642
13643 if ( element.parent().is( ".ui-effects-wrapper" ) ) {
13644 element.parent().replaceWith( element );
13645
13646 // Fixes #7595 - Elements lose focus when wrapped.
13647 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
13648 $( active ).focus();
13649 }
13650 }
13651
13652
13653 return element;
13654 },
13655
13656 setTransition: function( element, list, factor, value ) {
13657 value = value || {};
13658 $.each( list, function( i, x ) {
13659 var unit = element.cssUnit( x );
13660 if ( unit[ 0 ] > 0 ) {
13661 value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
13662 }
13663 });
13664 return value;
13665 }
13666 });
13667
13668 // return an effect options object for the given parameters:
13669 function _normalizeArguments( effect, options, speed, callback ) {
13670
13671 // allow passing all options as the first parameter
13672 if ( $.isPlainObject( effect ) ) {
13673 options = effect;
13674 effect = effect.effect;
13675 }
13676
13677 // convert to an object
13678 effect = { effect: effect };
13679
13680 // catch (effect, null, ...)
13681 if ( options == null ) {
13682 options = {};
13683 }
13684
13685 // catch (effect, callback)
13686 if ( $.isFunction( options ) ) {
13687 callback = options;
13688 speed = null;
13689 options = {};
13690 }
13691
13692 // catch (effect, speed, ?)
13693 if ( typeof options === "number" || $.fx.speeds[ options ] ) {
13694 callback = speed;
13695 speed = options;
13696 options = {};
13697 }
13698
13699 // catch (effect, options, callback)
13700 if ( $.isFunction( speed ) ) {
13701 callback = speed;
13702 speed = null;
13703 }
13704
13705 // add options to effect
13706 if ( options ) {
13707 $.extend( effect, options );
13708 }
13709
13710 speed = speed || options.duration;
13711 effect.duration = $.fx.off ? 0 :
13712 typeof speed === "number" ? speed :
13713 speed in $.fx.speeds ? $.fx.speeds[ speed ] :
13714 $.fx.speeds._default;
13715
13716 effect.complete = callback || options.complete;
13717
13718 return effect;
13719 }
13720
13721 function standardSpeed( speed ) {
13722 // valid standard speeds
13723 if ( !speed || typeof speed === "number" || $.fx.speeds[ speed ] ) {
13724 return true;
13725 }
13726
13727 // invalid strings - treat as "normal" speed
13728 if ( typeof speed === "string" && !$.effects.effect[ speed ] ) {
13729 // TODO: remove in 2.0 (#7115)
13730 if ( backCompat && $.effects[ speed ] ) {
13731 return false;
13732 }
13733 return true;
13734 }
13735
13736 return false;
13737 }
13738
13739 $.fn.extend({
13740 effect: function( /* effect, options, speed, callback */ ) {
13741 var args = _normalizeArguments.apply( this, arguments ),
13742 mode = args.mode,
13743 queue = args.queue,
13744 effectMethod = $.effects.effect[ args.effect ],
13745
13746 // DEPRECATED: remove in 2.0 (#7115)
13747 oldEffectMethod = !effectMethod && backCompat && $.effects[ args.effect ];
13748
13749 if ( $.fx.off || !( effectMethod || oldEffectMethod ) ) {
13750 // delegate to the original method (e.g., .show()) if possible
13751 if ( mode ) {
13752 return this[ mode ]( args.duration, args.complete );
13753 } else {
13754 return this.each( function() {
13755 if ( args.complete ) {
13756 args.complete.call( this );
13757 }
13758 });
13759 }
13760 }
13761
13762 function run( next ) {
13763 var elem = $( this ),
13764 complete = args.complete,
13765 mode = args.mode;
13766
13767 function done() {
13768 if ( $.isFunction( complete ) ) {
13769 complete.call( elem[0] );
13770 }
13771 if ( $.isFunction( next ) ) {
13772 next();
13773 }
13774 }
13775
13776 // if the element is hiddden and mode is hide,
13777 // or element is visible and mode is show
13778 if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
13779 done();
13780 } else {
13781 effectMethod.call( elem[0], args, done );
13782 }
13783 }
13784
13785 // TODO: remove this check in 2.0, effectMethod will always be true
13786 if ( effectMethod ) {
13787 return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
13788 } else {
13789 // DEPRECATED: remove in 2.0 (#7115)
13790 return oldEffectMethod.call(this, {
13791 options: args,
13792 duration: args.duration,
13793 callback: args.complete,
13794 mode: args.mode
13795 });
13796 }
13797 },
13798
13799 _show: $.fn.show,
13800 show: function( speed ) {
13801 if ( standardSpeed( speed ) ) {
13802 return this._show.apply( this, arguments );
13803 } else {
13804 var args = _normalizeArguments.apply( this, arguments );
13805 args.mode = "show";
13806 return this.effect.call( this, args );
13807 }
13808 },
13809
13810 _hide: $.fn.hide,
13811 hide: function( speed ) {
13812 if ( standardSpeed( speed ) ) {
13813 return this._hide.apply( this, arguments );
13814 } else {
13815 var args = _normalizeArguments.apply( this, arguments );
13816 args.mode = "hide";
13817 return this.effect.call( this, args );
13818 }
13819 },
13820
13821 // jQuery core overloads toggle and creates _toggle
13822 __toggle: $.fn.toggle,
13823 toggle: function( speed ) {
13824 if ( standardSpeed( speed ) || typeof speed === "boolean" || $.isFunction( speed ) ) {
13825 return this.__toggle.apply( this, arguments );
13826 } else {
13827 var args = _normalizeArguments.apply( this, arguments );
13828 args.mode = "toggle";
13829 return this.effect.call( this, args );
13830 }
13831 },
13832
13833 // helper functions
13834 cssUnit: function(key) {
13835 var style = this.css( key ),
13836 val = [];
13837
13838 $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
13839 if ( style.indexOf( unit ) > 0 ) {
13840 val = [ parseFloat( style ), unit ];
13841 }
13842 });
13843 return val;
13844 }
13845 });
13846
13847 })();
13848
13849 /******************************************************************************/
13850 /*********************************** EASING ***********************************/
13851 /******************************************************************************/
13852
13853 (function() {
13854
13855 // based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
13856
13857 var baseEasings = {};
13858
13859 $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
13860 baseEasings[ name ] = function( p ) {
13861 return Math.pow( p, i + 2 );
13862 };
13863 });
13864
13865 $.extend( baseEasings, {
13866 Sine: function ( p ) {
13867 return 1 - Math.cos( p * Math.PI / 2 );
13868 },
13869 Circ: function ( p ) {
13870 return 1 - Math.sqrt( 1 - p * p );
13871 },
13872 Elastic: function( p ) {
13873 return p === 0 || p === 1 ? p :
13874 -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 );
13875 },
13876 Back: function( p ) {
13877 return p * p * ( 3 * p - 2 );
13878 },
13879 Bounce: function ( p ) {
13880 var pow2,
13881 bounce = 4;
13882
13883 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
13884 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
13885 }
13886 });
13887
13888 $.each( baseEasings, function( name, easeIn ) {
13889 $.easing[ "easeIn" + name ] = easeIn;
13890 $.easing[ "easeOut" + name ] = function( p ) {
13891 return 1 - easeIn( 1 - p );
13892 };
13893 $.easing[ "easeInOut" + name ] = function( p ) {
13894 return p < 0.5 ?
13895 easeIn( p * 2 ) / 2 :
13896 1 - easeIn( p * -2 + 2 ) / 2;
13897 };
13898 });
13899
13900 })();
13901
13902 })(jQuery));
13903 (function( $, undefined ) {
13904
13905 var rvertical = /up|down|vertical/,
13906 rpositivemotion = /up|left|vertical|horizontal/;
13907
13908 $.effects.effect.blind = function( o, done ) {
13909 // Create element
13910 var el = $( this ),
13911 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
13912 mode = $.effects.setMode( el, o.mode || "hide" ),
13913 direction = o.direction || "up",
13914 vertical = rvertical.test( direction ),
13915 ref = vertical ? "height" : "width",
13916 ref2 = vertical ? "top" : "left",
13917 motion = rpositivemotion.test( direction ),
13918 animation = {},
13919 show = mode === "show",
13920 wrapper, distance, margin;
13921
13922 // if already wrapped, the wrapper's properties are my property. #6245
13923 if ( el.parent().is( ".ui-effects-wrapper" ) ) {
13924 $.effects.save( el.parent(), props );
13925 } else {
13926 $.effects.save( el, props );
13927 }
13928 el.show();
13929 wrapper = $.effects.createWrapper( el ).css({
13930 overflow: "hidden"
13931 });
13932
13933 distance = wrapper[ ref ]();
13934 margin = parseFloat( wrapper.css( ref2 ) ) || 0;
13935
13936 animation[ ref ] = show ? distance : 0;
13937 if ( !motion ) {
13938 el
13939 .css( vertical ? "bottom" : "right", 0 )
13940 .css( vertical ? "top" : "left", "auto" )
13941 .css({ position: "absolute" });
13942
13943 animation[ ref2 ] = show ? margin : distance + margin;
13944 }
13945
13946 // start at 0 if we are showing
13947 if ( show ) {
13948 wrapper.css( ref, 0 );
13949 if ( ! motion ) {
13950 wrapper.css( ref2, margin + distance );
13951 }
13952 }
13953
13954 // Animate
13955 wrapper.animate( animation, {
13956 duration: o.duration,
13957 easing: o.easing,
13958 queue: false,
13959 complete: function() {
13960 if ( mode === "hide" ) {
13961 el.hide();
13962 }
13963 $.effects.restore( el, props );
13964 $.effects.removeWrapper( el );
13965 done();
13966 }
13967 });
13968
13969 };
13970
13971 })(jQuery);
13972 (function( $, undefined ) {
13973
13974 $.effects.effect.bounce = function( o, done ) {
13975 var el = $( this ),
13976 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
13977
13978 // defaults:
13979 mode = $.effects.setMode( el, o.mode || "effect" ),
13980 hide = mode === "hide",
13981 show = mode === "show",
13982 direction = o.direction || "up",
13983 distance = o.distance,
13984 times = o.times || 5,
13985
13986 // number of internal animations
13987 anims = times * 2 + ( show || hide ? 1 : 0 ),
13988 speed = o.duration / anims,
13989 easing = o.easing,
13990
13991 // utility:
13992 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
13993 motion = ( direction === "up" || direction === "left" ),
13994 i,
13995 upAnim,
13996 downAnim,
13997
13998 // we will need to re-assemble the queue to stack our animations in place
13999 queue = el.queue(),
14000 queuelen = queue.length;
14001
14002 // Avoid touching opacity to prevent clearType and PNG issues in IE
14003 if ( show || hide ) {
14004 props.push( "opacity" );
14005 }
14006
14007 $.effects.save( el, props );
14008 el.show();
14009 $.effects.createWrapper( el ); // Create Wrapper
14010
14011 // default distance for the BIGGEST bounce is the outer Distance / 3
14012 if ( !distance ) {
14013 distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
14014 }
14015
14016 if ( show ) {
14017 downAnim = { opacity: 1 };
14018 downAnim[ ref ] = 0;
14019
14020 // if we are showing, force opacity 0 and set the initial position
14021 // then do the "first" animation
14022 el.css( "opacity", 0 )
14023 .css( ref, motion ? -distance * 2 : distance * 2 )
14024 .animate( downAnim, speed, easing );
14025 }
14026
14027 // start at the smallest distance if we are hiding
14028 if ( hide ) {
14029 distance = distance / Math.pow( 2, times - 1 );
14030 }
14031
14032 downAnim = {};
14033 downAnim[ ref ] = 0;
14034 // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
14035 for ( i = 0; i < times; i++ ) {
14036 upAnim = {};
14037 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
14038
14039 el.animate( upAnim, speed, easing )
14040 .animate( downAnim, speed, easing );
14041
14042 distance = hide ? distance * 2 : distance / 2;
14043 }
14044
14045 // Last Bounce when Hiding
14046 if ( hide ) {
14047 upAnim = { opacity: 0 };
14048 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
14049
14050 el.animate( upAnim, speed, easing );
14051 }
14052
14053 el.queue(function() {
14054 if ( hide ) {
14055 el.hide();
14056 }
14057 $.effects.restore( el, props );
14058 $.effects.removeWrapper( el );
14059 done();
14060 });
14061
14062 // inject all the animations we just queued to be first in line (after "inprogress")
14063 if ( queuelen > 1) {
14064 queue.splice.apply( queue,
14065 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
14066 }
14067 el.dequeue();
14068
14069 };
14070
14071 })(jQuery);
14072 (function( $, undefined ) {
14073
14074 $.effects.effect.clip = function( o, done ) {
14075 // Create element
14076 var el = $( this ),
14077 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
14078 mode = $.effects.setMode( el, o.mode || "hide" ),
14079 show = mode === "show",
14080 direction = o.direction || "vertical",
14081 vert = direction === "vertical",
14082 size = vert ? "height" : "width",
14083 position = vert ? "top" : "left",
14084 animation = {},
14085 wrapper, animate, distance;
14086
14087 // Save & Show
14088 $.effects.save( el, props );
14089 el.show();
14090
14091 // Create Wrapper
14092 wrapper = $.effects.createWrapper( el ).css({
14093 overflow: "hidden"
14094 });
14095 animate = ( el[0].tagName === "IMG" ) ? wrapper : el;
14096 distance = animate[ size ]();
14097
14098 // Shift
14099 if ( show ) {
14100 animate.css( size, 0 );
14101 animate.css( position, distance / 2 );
14102 }
14103
14104 // Create Animation Object:
14105 animation[ size ] = show ? distance : 0;
14106 animation[ position ] = show ? 0 : distance / 2;
14107
14108 // Animate
14109 animate.animate( animation, {
14110 queue: false,
14111 duration: o.duration,
14112 easing: o.easing,
14113 complete: function() {
14114 if ( !show ) {
14115 el.hide();
14116 }
14117 $.effects.restore( el, props );
14118 $.effects.removeWrapper( el );
14119 done();
14120 }
14121 });
14122
14123 };
14124
14125 })(jQuery);
14126 (function( $, undefined ) {
14127
14128 $.effects.effect.drop = function( o, done ) {
14129
14130 var el = $( this ),
14131 props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
14132 mode = $.effects.setMode( el, o.mode || "hide" ),
14133 show = mode === "show",
14134 direction = o.direction || "left",
14135 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
14136 motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
14137 animation = {
14138 opacity: show ? 1 : 0
14139 },
14140 distance;
14141
14142 // Adjust
14143 $.effects.save( el, props );
14144 el.show();
14145 $.effects.createWrapper( el );
14146
14147 distance = o.distance || el[ ref === "top" ? "outerHeight": "outerWidth" ]( true ) / 2;
14148
14149 if ( show ) {
14150 el
14151 .css( "opacity", 0 )
14152 .css( ref, motion === "pos" ? -distance : distance );
14153 }
14154
14155 // Animation
14156 animation[ ref ] = ( show ?
14157 ( motion === "pos" ? "+=" : "-=" ) :
14158 ( motion === "pos" ? "-=" : "+=" ) ) +
14159 distance;
14160
14161 // Animate
14162 el.animate( animation, {
14163 queue: false,
14164 duration: o.duration,
14165 easing: o.easing,
14166 complete: function() {
14167 if ( mode === "hide" ) {
14168 el.hide();
14169 }
14170 $.effects.restore( el, props );
14171 $.effects.removeWrapper( el );
14172 done();
14173 }
14174 });
14175 };
14176
14177 })(jQuery);
14178 (function( $, undefined ) {
14179
14180 $.effects.effect.explode = function( o, done ) {
14181
14182 var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3,
14183 cells = rows,
14184 el = $( this ),
14185 mode = $.effects.setMode( el, o.mode || "hide" ),
14186 show = mode === "show",
14187
14188 // show and then visibility:hidden the element before calculating offset
14189 offset = el.show().css( "visibility", "hidden" ).offset(),
14190
14191 // width and height of a piece
14192 width = Math.ceil( el.outerWidth() / cells ),
14193 height = Math.ceil( el.outerHeight() / rows ),
14194 pieces = [],
14195
14196 // loop
14197 i, j, left, top, mx, my;
14198
14199 // children animate complete:
14200 function childComplete() {
14201 pieces.push( this );
14202 if ( pieces.length === rows * cells ) {
14203 animComplete();
14204 }
14205 }
14206
14207 // clone the element for each row and cell.
14208 for( i = 0; i < rows ; i++ ) { // ===>
14209 top = offset.top + i * height;
14210 my = i - ( rows - 1 ) / 2 ;
14211
14212 for( j = 0; j < cells ; j++ ) { // |||
14213 left = offset.left + j * width;
14214 mx = j - ( cells - 1 ) / 2 ;
14215
14216 // Create a clone of the now hidden main element that will be absolute positioned
14217 // within a wrapper div off the -left and -top equal to size of our pieces
14218 el
14219 .clone()
14220 .appendTo( "body" )
14221 .wrap( "<div></div>" )
14222 .css({
14223 position: "absolute",
14224 visibility: "visible",
14225 left: -j * width,
14226 top: -i * height
14227 })
14228
14229 // select the wrapper - make it overflow: hidden and absolute positioned based on
14230 // where the original was located +left and +top equal to the size of pieces
14231 .parent()
14232 .addClass( "ui-effects-explode" )
14233 .css({
14234 position: "absolute",
14235 overflow: "hidden",
14236 width: width,
14237 height: height,
14238 left: left + ( show ? mx * width : 0 ),
14239 top: top + ( show ? my * height : 0 ),
14240 opacity: show ? 0 : 1
14241 }).animate({
14242 left: left + ( show ? 0 : mx * width ),
14243 top: top + ( show ? 0 : my * height ),
14244 opacity: show ? 1 : 0
14245 }, o.duration || 500, o.easing, childComplete );
14246 }
14247 }
14248
14249 function animComplete() {
14250 el.css({
14251 visibility: "visible"
14252 });
14253 $( pieces ).remove();
14254 if ( !show ) {
14255 el.hide();
14256 }
14257 done();
14258 }
14259 };
14260
14261 })(jQuery);
14262 (function( $, undefined ) {
14263
14264 $.effects.effect.fade = function( o, done ) {
14265 var el = $( this ),
14266 mode = $.effects.setMode( el, o.mode || "toggle" );
14267
14268 el.animate({
14269 opacity: mode
14270 }, {
14271 queue: false,
14272 duration: o.duration,
14273 easing: o.easing,
14274 complete: done
14275 });
14276 };
14277
14278 })( jQuery );
14279 (function( $, undefined ) {
14280
14281 $.effects.effect.fold = function( o, done ) {
14282
14283 // Create element
14284 var el = $( this ),
14285 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
14286 mode = $.effects.setMode( el, o.mode || "hide" ),
14287 show = mode === "show",
14288 hide = mode === "hide",
14289 size = o.size || 15,
14290 percent = /([0-9]+)%/.exec( size ),
14291 horizFirst = !!o.horizFirst,
14292 widthFirst = show !== horizFirst,
14293 ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ],
14294 duration = o.duration / 2,
14295 wrapper, distance,
14296 animation1 = {},
14297 animation2 = {};
14298
14299 $.effects.save( el, props );
14300 el.show();
14301
14302 // Create Wrapper
14303 wrapper = $.effects.createWrapper( el ).css({
14304 overflow: "hidden"
14305 });
14306 distance = widthFirst ?
14307 [ wrapper.width(), wrapper.height() ] :
14308 [ wrapper.height(), wrapper.width() ];
14309
14310 if ( percent ) {
14311 size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
14312 }
14313 if ( show ) {
14314 wrapper.css( horizFirst ? {
14315 height: 0,
14316 width: size
14317 } : {
14318 height: size,
14319 width: 0
14320 });
14321 }
14322
14323 // Animation
14324 animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size;
14325 animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0;
14326
14327 // Animate
14328 wrapper
14329 .animate( animation1, duration, o.easing )
14330 .animate( animation2, duration, o.easing, function() {
14331 if ( hide ) {
14332 el.hide();
14333 }
14334 $.effects.restore( el, props );
14335 $.effects.removeWrapper( el );
14336 done();
14337 });
14338
14339 };
14340
14341 })(jQuery);
14342 (function( $, undefined ) {
14343
14344 $.effects.effect.highlight = function( o, done ) {
14345 var elem = $( this ),
14346 props = [ "backgroundImage", "backgroundColor", "opacity" ],
14347 mode = $.effects.setMode( elem, o.mode || "show" ),
14348 animation = {
14349 backgroundColor: elem.css( "backgroundColor" )
14350 };
14351
14352 if (mode === "hide") {
14353 animation.opacity = 0;
14354 }
14355
14356 $.effects.save( elem, props );
14357
14358 elem
14359 .show()
14360 .css({
14361 backgroundImage: "none",
14362 backgroundColor: o.color || "#ffff99"
14363 })
14364 .animate( animation, {
14365 queue: false,
14366 duration: o.duration,
14367 easing: o.easing,
14368 complete: function() {
14369 if ( mode === "hide" ) {
14370 elem.hide();
14371 }
14372 $.effects.restore( elem, props );
14373 done();
14374 }
14375 });
14376 };
14377
14378 })(jQuery);
14379 (function( $, undefined ) {
14380
14381 $.effects.effect.pulsate = function( o, done ) {
14382 var elem = $( this ),
14383 mode = $.effects.setMode( elem, o.mode || "show" ),
14384 show = mode === "show",
14385 hide = mode === "hide",
14386 showhide = ( show || mode === "hide" ),
14387
14388 // showing or hiding leaves of the "last" animation
14389 anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
14390 duration = o.duration / anims,
14391 animateTo = 0,
14392 queue = elem.queue(),
14393 queuelen = queue.length,
14394 i;
14395
14396 if ( show || !elem.is(":visible")) {
14397 elem.css( "opacity", 0 ).show();
14398 animateTo = 1;
14399 }
14400
14401 // anims - 1 opacity "toggles"
14402 for ( i = 1; i < anims; i++ ) {
14403 elem.animate({
14404 opacity: animateTo
14405 }, duration, o.easing );
14406 animateTo = 1 - animateTo;
14407 }
14408
14409 elem.animate({
14410 opacity: animateTo
14411 }, duration, o.easing);
14412
14413 elem.queue(function() {
14414 if ( hide ) {
14415 elem.hide();
14416 }
14417 done();
14418 });
14419
14420 // We just queued up "anims" animations, we need to put them next in the queue
14421 if ( queuelen > 1 ) {
14422 queue.splice.apply( queue,
14423 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
14424 }
14425 elem.dequeue();
14426 };
14427
14428 })(jQuery);
14429 (function( $, undefined ) {
14430
14431 $.effects.effect.puff = function( o, done ) {
14432 var elem = $( this ),
14433 mode = $.effects.setMode( elem, o.mode || "hide" ),
14434 hide = mode === "hide",
14435 percent = parseInt( o.percent, 10 ) || 150,
14436 factor = percent / 100,
14437 original = {
14438 height: elem.height(),
14439 width: elem.width(),
14440 outerHeight: elem.outerHeight(),
14441 outerWidth: elem.outerWidth()
14442 };
14443
14444 $.extend( o, {
14445 effect: "scale",
14446 queue: false,
14447 fade: true,
14448 mode: mode,
14449 complete: done,
14450 percent: hide ? percent : 100,
14451 from: hide ?
14452 original :
14453 {
14454 height: original.height * factor,
14455 width: original.width * factor,
14456 outerHeight: original.outerHeight * factor,
14457 outerWidth: original.outerWidth * factor
14458 }
14459 });
14460
14461 elem.effect( o );
14462 };
14463
14464 $.effects.effect.scale = function( o, done ) {
14465
14466 // Create element
14467 var el = $( this ),
14468 options = $.extend( true, {}, o ),
14469 mode = $.effects.setMode( el, o.mode || "effect" ),
14470 percent = parseInt( o.percent, 10 ) ||
14471 ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ),
14472 direction = o.direction || "both",
14473 origin = o.origin,
14474 original = {
14475 height: el.height(),
14476 width: el.width(),
14477 outerHeight: el.outerHeight(),
14478 outerWidth: el.outerWidth()
14479 },
14480 factor = {
14481 y: direction !== "horizontal" ? (percent / 100) : 1,
14482 x: direction !== "vertical" ? (percent / 100) : 1
14483 };
14484
14485 // We are going to pass this effect to the size effect:
14486 options.effect = "size";
14487 options.queue = false;
14488 options.complete = done;
14489
14490 // Set default origin and restore for show/hide
14491 if ( mode !== "effect" ) {
14492 options.origin = origin || ["middle","center"];
14493 options.restore = true;
14494 }
14495
14496 options.from = o.from || ( mode === "show" ? {
14497 height: 0,
14498 width: 0,
14499 outerHeight: 0,
14500 outerWidth: 0
14501 } : original );
14502 options.to = {
14503 height: original.height * factor.y,
14504 width: original.width * factor.x,
14505 outerHeight: original.outerHeight * factor.y,
14506 outerWidth: original.outerWidth * factor.x
14507 };
14508
14509 // Fade option to support puff
14510 if ( options.fade ) {
14511 if ( mode === "show" ) {
14512 options.from.opacity = 0;
14513 options.to.opacity = 1;
14514 }
14515 if ( mode === "hide" ) {
14516 options.from.opacity = 1;
14517 options.to.opacity = 0;
14518 }
14519 }
14520
14521 // Animate
14522 el.effect( options );
14523
14524 };
14525
14526 $.effects.effect.size = function( o, done ) {
14527
14528 // Create element
14529 var original, baseline, factor,
14530 el = $( this ),
14531 props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ],
14532
14533 // Always restore
14534 props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ],
14535
14536 // Copy for children
14537 props2 = [ "width", "height", "overflow" ],
14538 cProps = [ "fontSize" ],
14539 vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
14540 hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
14541
14542 // Set options
14543 mode = $.effects.setMode( el, o.mode || "effect" ),
14544 restore = o.restore || mode !== "effect",
14545 scale = o.scale || "both",
14546 origin = o.origin || [ "middle", "center" ],
14547 position = el.css( "position" ),
14548 props = restore ? props0 : props1,
14549 zero = {
14550 height: 0,
14551 width: 0,
14552 outerHeight: 0,
14553 outerWidth: 0
14554 };
14555
14556 if ( mode === "show" ) {
14557 el.show();
14558 }
14559 original = {
14560 height: el.height(),
14561 width: el.width(),
14562 outerHeight: el.outerHeight(),
14563 outerWidth: el.outerWidth()
14564 };
14565
14566 if ( o.mode === "toggle" && mode === "show" ) {
14567 el.from = o.to || zero;
14568 el.to = o.from || original;
14569 } else {
14570 el.from = o.from || ( mode === "show" ? zero : original );
14571 el.to = o.to || ( mode === "hide" ? zero : original );
14572 }
14573
14574 // Set scaling factor
14575 factor = {
14576 from: {
14577 y: el.from.height / original.height,
14578 x: el.from.width / original.width
14579 },
14580 to: {
14581 y: el.to.height / original.height,
14582 x: el.to.width / original.width
14583 }
14584 };
14585
14586 // Scale the css box
14587 if ( scale === "box" || scale === "both" ) {
14588
14589 // Vertical props scaling
14590 if ( factor.from.y !== factor.to.y ) {
14591 props = props.concat( vProps );
14592 el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
14593 el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
14594 }
14595
14596 // Horizontal props scaling
14597 if ( factor.from.x !== factor.to.x ) {
14598 props = props.concat( hProps );
14599 el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
14600 el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
14601 }
14602 }
14603
14604 // Scale the content
14605 if ( scale === "content" || scale === "both" ) {
14606
14607 // Vertical props scaling
14608 if ( factor.from.y !== factor.to.y ) {
14609 props = props.concat( cProps ).concat( props2 );
14610 el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
14611 el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
14612 }
14613 }
14614
14615 $.effects.save( el, props );
14616 el.show();
14617 $.effects.createWrapper( el );
14618 el.css( "overflow", "hidden" ).css( el.from );
14619
14620 // Adjust
14621 if (origin) { // Calculate baseline shifts
14622 baseline = $.effects.getBaseline( origin, original );
14623 el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
14624 el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
14625 el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
14626 el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
14627 }
14628 el.css( el.from ); // set top & left
14629
14630 // Animate
14631 if ( scale === "content" || scale === "both" ) { // Scale the children
14632
14633 // Add margins/font-size
14634 vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps);
14635 hProps = hProps.concat([ "marginLeft", "marginRight" ]);
14636 props2 = props0.concat(vProps).concat(hProps);
14637
14638 el.find( "*[width]" ).each( function(){
14639 var child = $( this ),
14640 c_original = {
14641 height: child.height(),
14642 width: child.width(),
14643 outerHeight: child.outerHeight(),
14644 outerWidth: child.outerWidth()
14645 };
14646 if (restore) {
14647 $.effects.save(child, props2);
14648 }
14649
14650 child.from = {
14651 height: c_original.height * factor.from.y,
14652 width: c_original.width * factor.from.x,
14653 outerHeight: c_original.outerHeight * factor.from.y,
14654 outerWidth: c_original.outerWidth * factor.from.x
14655 };
14656 child.to = {
14657 height: c_original.height * factor.to.y,
14658 width: c_original.width * factor.to.x,
14659 outerHeight: c_original.height * factor.to.y,
14660 outerWidth: c_original.width * factor.to.x
14661 };
14662
14663 // Vertical props scaling
14664 if ( factor.from.y !== factor.to.y ) {
14665 child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
14666 child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
14667 }
14668
14669 // Horizontal props scaling
14670 if ( factor.from.x !== factor.to.x ) {
14671 child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
14672 child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
14673 }
14674
14675 // Animate children
14676 child.css( child.from );
14677 child.animate( child.to, o.duration, o.easing, function() {
14678
14679 // Restore children
14680 if ( restore ) {
14681 $.effects.restore( child, props2 );
14682 }
14683 });
14684 });
14685 }
14686
14687 // Animate
14688 el.animate( el.to, {
14689 queue: false,
14690 duration: o.duration,
14691 easing: o.easing,
14692 complete: function() {
14693 if ( el.to.opacity === 0 ) {
14694 el.css( "opacity", el.from.opacity );
14695 }
14696 if( mode === "hide" ) {
14697 el.hide();
14698 }
14699 $.effects.restore( el, props );
14700 if ( !restore ) {
14701
14702 // we need to calculate our new positioning based on the scaling
14703 if ( position === "static" ) {
14704 el.css({
14705 position: "relative",
14706 top: el.to.top,
14707 left: el.to.left
14708 });
14709 } else {
14710 $.each([ "top", "left" ], function( idx, pos ) {
14711 el.css( pos, function( _, str ) {
14712 var val = parseInt( str, 10 ),
14713 toRef = idx ? el.to.left : el.to.top;
14714
14715 // if original was "auto", recalculate the new value from wrapper
14716 if ( str === "auto" ) {
14717 return toRef + "px";
14718 }
14719
14720 return val + toRef + "px";
14721 });
14722 });
14723 }
14724 }
14725
14726 $.effects.removeWrapper( el );
14727 done();
14728 }
14729 });
14730
14731 };
14732
14733 })(jQuery);
14734 (function( $, undefined ) {
14735
14736 $.effects.effect.shake = function( o, done ) {
14737
14738 var el = $( this ),
14739 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
14740 mode = $.effects.setMode( el, o.mode || "effect" ),
14741 direction = o.direction || "left",
14742 distance = o.distance || 20,
14743 times = o.times || 3,
14744 anims = times * 2 + 1,
14745 speed = Math.round(o.duration/anims),
14746 ref = (direction === "up" || direction === "down") ? "top" : "left",
14747 positiveMotion = (direction === "up" || direction === "left"),
14748 animation = {},
14749 animation1 = {},
14750 animation2 = {},
14751 i,
14752
14753 // we will need to re-assemble the queue to stack our animations in place
14754 queue = el.queue(),
14755 queuelen = queue.length;
14756
14757 $.effects.save( el, props );
14758 el.show();
14759 $.effects.createWrapper( el );
14760
14761 // Animation
14762 animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
14763 animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
14764 animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
14765
14766 // Animate
14767 el.animate( animation, speed, o.easing );
14768
14769 // Shakes
14770 for ( i = 1; i < times; i++ ) {
14771 el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing );
14772 }
14773 el
14774 .animate( animation1, speed, o.easing )
14775 .animate( animation, speed / 2, o.easing )
14776 .queue(function() {
14777 if ( mode === "hide" ) {
14778 el.hide();
14779 }
14780 $.effects.restore( el, props );
14781 $.effects.removeWrapper( el );
14782 done();
14783 });
14784
14785 // inject all the animations we just queued to be first in line (after "inprogress")
14786 if ( queuelen > 1) {
14787 queue.splice.apply( queue,
14788 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
14789 }
14790 el.dequeue();
14791
14792 };
14793
14794 })(jQuery);
14795 (function( $, undefined ) {
14796
14797 $.effects.effect.slide = function( o, done ) {
14798
14799 // Create element
14800 var el = $( this ),
14801 props = [ "position", "top", "bottom", "left", "right", "width", "height" ],
14802 mode = $.effects.setMode( el, o.mode || "show" ),
14803 show = mode === "show",
14804 direction = o.direction || "left",
14805 ref = (direction === "up" || direction === "down") ? "top" : "left",
14806 positiveMotion = (direction === "up" || direction === "left"),
14807 distance,
14808 animation = {};
14809
14810 // Adjust
14811 $.effects.save( el, props );
14812 el.show();
14813 distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true );
14814
14815 $.effects.createWrapper( el ).css({
14816 overflow: "hidden"
14817 });
14818
14819 if ( show ) {
14820 el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance );
14821 }
14822
14823 // Animation
14824 animation[ ref ] = ( show ?
14825 ( positiveMotion ? "+=" : "-=") :
14826 ( positiveMotion ? "-=" : "+=")) +
14827 distance;
14828
14829 // Animate
14830 el.animate( animation, {
14831 queue: false,
14832 duration: o.duration,
14833 easing: o.easing,
14834 complete: function() {
14835 if ( mode === "hide" ) {
14836 el.hide();
14837 }
14838 $.effects.restore( el, props );
14839 $.effects.removeWrapper( el );
14840 done();
14841 }
14842 });
14843 };
14844
14845 })(jQuery);
14846 (function( $, undefined ) {
14847
14848 $.effects.effect.transfer = function( o, done ) {
14849 var elem = $( this ),
14850 target = $( o.to ),
14851 targetFixed = target.css( "position" ) === "fixed",
14852 body = $("body"),
14853 fixTop = targetFixed ? body.scrollTop() : 0,
14854 fixLeft = targetFixed ? body.scrollLeft() : 0,
14855 endPosition = target.offset(),
14856 animation = {
14857 top: endPosition.top - fixTop ,
14858 left: endPosition.left - fixLeft ,
14859 height: target.innerHeight(),
14860 width: target.innerWidth()
14861 },
14862 startPosition = elem.offset(),
14863 transfer = $( '<div class="ui-effects-transfer"></div>' )
14864 .appendTo( document.body )
14865 .addClass( o.className )
14866 .css({
14867 top: startPosition.top - fixTop ,
14868 left: startPosition.left - fixLeft ,
14869 height: elem.innerHeight(),
14870 width: elem.innerWidth(),
14871 position: targetFixed ? "fixed" : "absolute"
14872 })
14873 .animate( animation, o.duration, o.easing, function() {
14874 transfer.remove();
14875 done();
14876 });
14877 };
14878
14879 })(jQuery);

Небольшая справка по веткам

cnddist – контейнер, в котором хранятся все дистрибутивы всех библиотек и программных пакетов, которые использовались при построении различных версий Contenido. Если какой-то библиотеки в данном хранилище нет, инсталлятор сделает попытку "подтянуть" ее с веба (например, с CPAN). Если библиотека слишком старая, есть очень большая вероятность, что ее там уже нет. Поэтому мы храним весь хлам от всех сборок. Если какой-то дистрибутив вдруг отсутствует в cnddist - напишите нам, мы положим его туда.

koi8 – отмирающая ветка, чей код, выдача и все внутренние библиотеки заточены на кодировку KOI8-R. Вносятся только те дополнения, которые касаются внешнего вида и функционала админки, баги ядра, обязательные обновления портов и мелочи, которые легко скопипастить. В дальнейшем планируется полная остановка поддержки по данной ветке.

utf8 – актуальная ветка, заточенная под UTF-8.

Внутри каждой ветки: core – исходники ядра; install – скрипт установки инсталляции; plugins – плагины; samples – "готовые к употреблению" проекты, которые можно поставить, запустить и посмотреть, как они работают.