comparison js/jquery/jquery-ui.js @ 12:7e04cbe8b2a0

add required libraries to server
author Zoe Hong <zhong@mpiwg-berlin.mpg.de>
date Wed, 24 Jun 2015 11:11:31 +0200
parents
children
comparison
equal deleted inserted replaced
11:0a03c75499e6 12:7e04cbe8b2a0
1 /*! jQuery UI - v1.10.4 - 2014-01-17
2 * http://jqueryui.com
3 * Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.position.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.draggable.js, jquery.ui.droppable.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, jquery.ui.menu.js, jquery.ui.progressbar.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.slider.js, jquery.ui.sortable.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js
4 * Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
5
6 (function( $, undefined ) {
7
8 var uuid = 0,
9 runiqueId = /^ui-id-\d+$/;
10
11 // $.ui might exist from components with no dependencies, e.g., $.ui.position
12 $.ui = $.ui || {};
13
14 $.extend( $.ui, {
15 version: "1.10.4",
16
17 keyCode: {
18 BACKSPACE: 8,
19 COMMA: 188,
20 DELETE: 46,
21 DOWN: 40,
22 END: 35,
23 ENTER: 13,
24 ESCAPE: 27,
25 HOME: 36,
26 LEFT: 37,
27 NUMPAD_ADD: 107,
28 NUMPAD_DECIMAL: 110,
29 NUMPAD_DIVIDE: 111,
30 NUMPAD_ENTER: 108,
31 NUMPAD_MULTIPLY: 106,
32 NUMPAD_SUBTRACT: 109,
33 PAGE_DOWN: 34,
34 PAGE_UP: 33,
35 PERIOD: 190,
36 RIGHT: 39,
37 SPACE: 32,
38 TAB: 9,
39 UP: 38
40 }
41 });
42
43 // plugins
44 $.fn.extend({
45 focus: (function( orig ) {
46 return function( delay, fn ) {
47 return typeof delay === "number" ?
48 this.each(function() {
49 var elem = this;
50 setTimeout(function() {
51 $( elem ).focus();
52 if ( fn ) {
53 fn.call( elem );
54 }
55 }, delay );
56 }) :
57 orig.apply( this, arguments );
58 };
59 })( $.fn.focus ),
60
61 scrollParent: function() {
62 var scrollParent;
63 if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) {
64 scrollParent = this.parents().filter(function() {
65 return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
66 }).eq(0);
67 } else {
68 scrollParent = this.parents().filter(function() {
69 return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
70 }).eq(0);
71 }
72
73 return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent;
74 },
75
76 zIndex: function( zIndex ) {
77 if ( zIndex !== undefined ) {
78 return this.css( "zIndex", zIndex );
79 }
80
81 if ( this.length ) {
82 var elem = $( this[ 0 ] ), position, value;
83 while ( elem.length && elem[ 0 ] !== document ) {
84 // Ignore z-index if position is set to a value where z-index is ignored by the browser
85 // This makes behavior of this function consistent across browsers
86 // WebKit always returns auto if the element is positioned
87 position = elem.css( "position" );
88 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
89 // IE returns 0 when zIndex is not specified
90 // other browsers return a string
91 // we ignore the case of nested elements with an explicit value of 0
92 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
93 value = parseInt( elem.css( "zIndex" ), 10 );
94 if ( !isNaN( value ) && value !== 0 ) {
95 return value;
96 }
97 }
98 elem = elem.parent();
99 }
100 }
101
102 return 0;
103 },
104
105 uniqueId: function() {
106 return this.each(function() {
107 if ( !this.id ) {
108 this.id = "ui-id-" + (++uuid);
109 }
110 });
111 },
112
113 removeUniqueId: function() {
114 return this.each(function() {
115 if ( runiqueId.test( this.id ) ) {
116 $( this ).removeAttr( "id" );
117 }
118 });
119 }
120 });
121
122 // selectors
123 function focusable( element, isTabIndexNotNaN ) {
124 var map, mapName, img,
125 nodeName = element.nodeName.toLowerCase();
126 if ( "area" === nodeName ) {
127 map = element.parentNode;
128 mapName = map.name;
129 if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
130 return false;
131 }
132 img = $( "img[usemap=#" + mapName + "]" )[0];
133 return !!img && visible( img );
134 }
135 return ( /input|select|textarea|button|object/.test( nodeName ) ?
136 !element.disabled :
137 "a" === nodeName ?
138 element.href || isTabIndexNotNaN :
139 isTabIndexNotNaN) &&
140 // the element and all of its ancestors must be visible
141 visible( element );
142 }
143
144 function visible( element ) {
145 return $.expr.filters.visible( element ) &&
146 !$( element ).parents().addBack().filter(function() {
147 return $.css( this, "visibility" ) === "hidden";
148 }).length;
149 }
150
151 $.extend( $.expr[ ":" ], {
152 data: $.expr.createPseudo ?
153 $.expr.createPseudo(function( dataName ) {
154 return function( elem ) {
155 return !!$.data( elem, dataName );
156 };
157 }) :
158 // support: jQuery <1.8
159 function( elem, i, match ) {
160 return !!$.data( elem, match[ 3 ] );
161 },
162
163 focusable: function( element ) {
164 return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
165 },
166
167 tabbable: function( element ) {
168 var tabIndex = $.attr( element, "tabindex" ),
169 isTabIndexNaN = isNaN( tabIndex );
170 return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
171 }
172 });
173
174 // support: jQuery <1.8
175 if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
176 $.each( [ "Width", "Height" ], function( i, name ) {
177 var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
178 type = name.toLowerCase(),
179 orig = {
180 innerWidth: $.fn.innerWidth,
181 innerHeight: $.fn.innerHeight,
182 outerWidth: $.fn.outerWidth,
183 outerHeight: $.fn.outerHeight
184 };
185
186 function reduce( elem, size, border, margin ) {
187 $.each( side, function() {
188 size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
189 if ( border ) {
190 size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
191 }
192 if ( margin ) {
193 size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
194 }
195 });
196 return size;
197 }
198
199 $.fn[ "inner" + name ] = function( size ) {
200 if ( size === undefined ) {
201 return orig[ "inner" + name ].call( this );
202 }
203
204 return this.each(function() {
205 $( this ).css( type, reduce( this, size ) + "px" );
206 });
207 };
208
209 $.fn[ "outer" + name] = function( size, margin ) {
210 if ( typeof size !== "number" ) {
211 return orig[ "outer" + name ].call( this, size );
212 }
213
214 return this.each(function() {
215 $( this).css( type, reduce( this, size, true, margin ) + "px" );
216 });
217 };
218 });
219 }
220
221 // support: jQuery <1.8
222 if ( !$.fn.addBack ) {
223 $.fn.addBack = function( selector ) {
224 return this.add( selector == null ?
225 this.prevObject : this.prevObject.filter( selector )
226 );
227 };
228 }
229
230 // support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
231 if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
232 $.fn.removeData = (function( removeData ) {
233 return function( key ) {
234 if ( arguments.length ) {
235 return removeData.call( this, $.camelCase( key ) );
236 } else {
237 return removeData.call( this );
238 }
239 };
240 })( $.fn.removeData );
241 }
242
243
244
245
246
247 // deprecated
248 $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
249
250 $.support.selectstart = "onselectstart" in document.createElement( "div" );
251 $.fn.extend({
252 disableSelection: function() {
253 return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
254 ".ui-disableSelection", function( event ) {
255 event.preventDefault();
256 });
257 },
258
259 enableSelection: function() {
260 return this.unbind( ".ui-disableSelection" );
261 }
262 });
263
264 $.extend( $.ui, {
265 // $.ui.plugin is deprecated. Use $.widget() extensions instead.
266 plugin: {
267 add: function( module, option, set ) {
268 var i,
269 proto = $.ui[ module ].prototype;
270 for ( i in set ) {
271 proto.plugins[ i ] = proto.plugins[ i ] || [];
272 proto.plugins[ i ].push( [ option, set[ i ] ] );
273 }
274 },
275 call: function( instance, name, args ) {
276 var i,
277 set = instance.plugins[ name ];
278 if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) {
279 return;
280 }
281
282 for ( i = 0; i < set.length; i++ ) {
283 if ( instance.options[ set[ i ][ 0 ] ] ) {
284 set[ i ][ 1 ].apply( instance.element, args );
285 }
286 }
287 }
288 },
289
290 // only used by resizable
291 hasScroll: function( el, a ) {
292
293 //If overflow is hidden, the element might have extra content, but the user wants to hide it
294 if ( $( el ).css( "overflow" ) === "hidden") {
295 return false;
296 }
297
298 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
299 has = false;
300
301 if ( el[ scroll ] > 0 ) {
302 return true;
303 }
304
305 // TODO: determine which cases actually cause this to happen
306 // if the element doesn't have the scroll set, see if it's possible to
307 // set the scroll
308 el[ scroll ] = 1;
309 has = ( el[ scroll ] > 0 );
310 el[ scroll ] = 0;
311 return has;
312 }
313 });
314
315 })( jQuery );
316 (function( $, undefined ) {
317
318 var uuid = 0,
319 slice = Array.prototype.slice,
320 _cleanData = $.cleanData;
321 $.cleanData = function( elems ) {
322 for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
323 try {
324 $( elem ).triggerHandler( "remove" );
325 // http://bugs.jquery.com/ticket/8235
326 } catch( e ) {}
327 }
328 _cleanData( elems );
329 };
330
331 $.widget = function( name, base, prototype ) {
332 var fullName, existingConstructor, constructor, basePrototype,
333 // proxiedPrototype allows the provided prototype to remain unmodified
334 // so that it can be used as a mixin for multiple widgets (#8876)
335 proxiedPrototype = {},
336 namespace = name.split( "." )[ 0 ];
337
338 name = name.split( "." )[ 1 ];
339 fullName = namespace + "-" + name;
340
341 if ( !prototype ) {
342 prototype = base;
343 base = $.Widget;
344 }
345
346 // create selector for plugin
347 $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
348 return !!$.data( elem, fullName );
349 };
350
351 $[ namespace ] = $[ namespace ] || {};
352 existingConstructor = $[ namespace ][ name ];
353 constructor = $[ namespace ][ name ] = function( options, element ) {
354 // allow instantiation without "new" keyword
355 if ( !this._createWidget ) {
356 return new constructor( options, element );
357 }
358
359 // allow instantiation without initializing for simple inheritance
360 // must use "new" keyword (the code above always passes args)
361 if ( arguments.length ) {
362 this._createWidget( options, element );
363 }
364 };
365 // extend with the existing constructor to carry over any static properties
366 $.extend( constructor, existingConstructor, {
367 version: prototype.version,
368 // copy the object used to create the prototype in case we need to
369 // redefine the widget later
370 _proto: $.extend( {}, prototype ),
371 // track widgets that inherit from this widget in case this widget is
372 // redefined after a widget inherits from it
373 _childConstructors: []
374 });
375
376 basePrototype = new base();
377 // we need to make the options hash a property directly on the new instance
378 // otherwise we'll modify the options hash on the prototype that we're
379 // inheriting from
380 basePrototype.options = $.widget.extend( {}, basePrototype.options );
381 $.each( prototype, function( prop, value ) {
382 if ( !$.isFunction( value ) ) {
383 proxiedPrototype[ prop ] = value;
384 return;
385 }
386 proxiedPrototype[ prop ] = (function() {
387 var _super = function() {
388 return base.prototype[ prop ].apply( this, arguments );
389 },
390 _superApply = function( args ) {
391 return base.prototype[ prop ].apply( this, args );
392 };
393 return function() {
394 var __super = this._super,
395 __superApply = this._superApply,
396 returnValue;
397
398 this._super = _super;
399 this._superApply = _superApply;
400
401 returnValue = value.apply( this, arguments );
402
403 this._super = __super;
404 this._superApply = __superApply;
405
406 return returnValue;
407 };
408 })();
409 });
410 constructor.prototype = $.widget.extend( basePrototype, {
411 // TODO: remove support for widgetEventPrefix
412 // always use the name + a colon as the prefix, e.g., draggable:start
413 // don't prefix for widgets that aren't DOM-based
414 widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name
415 }, proxiedPrototype, {
416 constructor: constructor,
417 namespace: namespace,
418 widgetName: name,
419 widgetFullName: fullName
420 });
421
422 // If this widget is being redefined then we need to find all widgets that
423 // are inheriting from it and redefine all of them so that they inherit from
424 // the new version of this widget. We're essentially trying to replace one
425 // level in the prototype chain.
426 if ( existingConstructor ) {
427 $.each( existingConstructor._childConstructors, function( i, child ) {
428 var childPrototype = child.prototype;
429
430 // redefine the child widget using the same prototype that was
431 // originally used, but inherit from the new version of the base
432 $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
433 });
434 // remove the list of existing child constructors from the old constructor
435 // so the old child constructors can be garbage collected
436 delete existingConstructor._childConstructors;
437 } else {
438 base._childConstructors.push( constructor );
439 }
440
441 $.widget.bridge( name, constructor );
442 };
443
444 $.widget.extend = function( target ) {
445 var input = slice.call( arguments, 1 ),
446 inputIndex = 0,
447 inputLength = input.length,
448 key,
449 value;
450 for ( ; inputIndex < inputLength; inputIndex++ ) {
451 for ( key in input[ inputIndex ] ) {
452 value = input[ inputIndex ][ key ];
453 if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
454 // Clone objects
455 if ( $.isPlainObject( value ) ) {
456 target[ key ] = $.isPlainObject( target[ key ] ) ?
457 $.widget.extend( {}, target[ key ], value ) :
458 // Don't extend strings, arrays, etc. with objects
459 $.widget.extend( {}, value );
460 // Copy everything else by reference
461 } else {
462 target[ key ] = value;
463 }
464 }
465 }
466 }
467 return target;
468 };
469
470 $.widget.bridge = function( name, object ) {
471 var fullName = object.prototype.widgetFullName || name;
472 $.fn[ name ] = function( options ) {
473 var isMethodCall = typeof options === "string",
474 args = slice.call( arguments, 1 ),
475 returnValue = this;
476
477 // allow multiple hashes to be passed on init
478 options = !isMethodCall && args.length ?
479 $.widget.extend.apply( null, [ options ].concat(args) ) :
480 options;
481
482 if ( isMethodCall ) {
483 this.each(function() {
484 var methodValue,
485 instance = $.data( this, fullName );
486 if ( !instance ) {
487 return $.error( "cannot call methods on " + name + " prior to initialization; " +
488 "attempted to call method '" + options + "'" );
489 }
490 if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
491 return $.error( "no such method '" + options + "' for " + name + " widget instance" );
492 }
493 methodValue = instance[ options ].apply( instance, args );
494 if ( methodValue !== instance && methodValue !== undefined ) {
495 returnValue = methodValue && methodValue.jquery ?
496 returnValue.pushStack( methodValue.get() ) :
497 methodValue;
498 return false;
499 }
500 });
501 } else {
502 this.each(function() {
503 var instance = $.data( this, fullName );
504 if ( instance ) {
505 instance.option( options || {} )._init();
506 } else {
507 $.data( this, fullName, new object( options, this ) );
508 }
509 });
510 }
511
512 return returnValue;
513 };
514 };
515
516 $.Widget = function( /* options, element */ ) {};
517 $.Widget._childConstructors = [];
518
519 $.Widget.prototype = {
520 widgetName: "widget",
521 widgetEventPrefix: "",
522 defaultElement: "<div>",
523 options: {
524 disabled: false,
525
526 // callbacks
527 create: null
528 },
529 _createWidget: function( options, element ) {
530 element = $( element || this.defaultElement || this )[ 0 ];
531 this.element = $( element );
532 this.uuid = uuid++;
533 this.eventNamespace = "." + this.widgetName + this.uuid;
534 this.options = $.widget.extend( {},
535 this.options,
536 this._getCreateOptions(),
537 options );
538
539 this.bindings = $();
540 this.hoverable = $();
541 this.focusable = $();
542
543 if ( element !== this ) {
544 $.data( element, this.widgetFullName, this );
545 this._on( true, this.element, {
546 remove: function( event ) {
547 if ( event.target === element ) {
548 this.destroy();
549 }
550 }
551 });
552 this.document = $( element.style ?
553 // element within the document
554 element.ownerDocument :
555 // element is window or document
556 element.document || element );
557 this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
558 }
559
560 this._create();
561 this._trigger( "create", null, this._getCreateEventData() );
562 this._init();
563 },
564 _getCreateOptions: $.noop,
565 _getCreateEventData: $.noop,
566 _create: $.noop,
567 _init: $.noop,
568
569 destroy: function() {
570 this._destroy();
571 // we can probably remove the unbind calls in 2.0
572 // all event bindings should go through this._on()
573 this.element
574 .unbind( this.eventNamespace )
575 // 1.9 BC for #7810
576 // TODO remove dual storage
577 .removeData( this.widgetName )
578 .removeData( this.widgetFullName )
579 // support: jquery <1.6.3
580 // http://bugs.jquery.com/ticket/9413
581 .removeData( $.camelCase( this.widgetFullName ) );
582 this.widget()
583 .unbind( this.eventNamespace )
584 .removeAttr( "aria-disabled" )
585 .removeClass(
586 this.widgetFullName + "-disabled " +
587 "ui-state-disabled" );
588
589 // clean up events and states
590 this.bindings.unbind( this.eventNamespace );
591 this.hoverable.removeClass( "ui-state-hover" );
592 this.focusable.removeClass( "ui-state-focus" );
593 },
594 _destroy: $.noop,
595
596 widget: function() {
597 return this.element;
598 },
599
600 option: function( key, value ) {
601 var options = key,
602 parts,
603 curOption,
604 i;
605
606 if ( arguments.length === 0 ) {
607 // don't return a reference to the internal hash
608 return $.widget.extend( {}, this.options );
609 }
610
611 if ( typeof key === "string" ) {
612 // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
613 options = {};
614 parts = key.split( "." );
615 key = parts.shift();
616 if ( parts.length ) {
617 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
618 for ( i = 0; i < parts.length - 1; i++ ) {
619 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
620 curOption = curOption[ parts[ i ] ];
621 }
622 key = parts.pop();
623 if ( arguments.length === 1 ) {
624 return curOption[ key ] === undefined ? null : curOption[ key ];
625 }
626 curOption[ key ] = value;
627 } else {
628 if ( arguments.length === 1 ) {
629 return this.options[ key ] === undefined ? null : this.options[ key ];
630 }
631 options[ key ] = value;
632 }
633 }
634
635 this._setOptions( options );
636
637 return this;
638 },
639 _setOptions: function( options ) {
640 var key;
641
642 for ( key in options ) {
643 this._setOption( key, options[ key ] );
644 }
645
646 return this;
647 },
648 _setOption: function( key, value ) {
649 this.options[ key ] = value;
650
651 if ( key === "disabled" ) {
652 this.widget()
653 .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value )
654 .attr( "aria-disabled", value );
655 this.hoverable.removeClass( "ui-state-hover" );
656 this.focusable.removeClass( "ui-state-focus" );
657 }
658
659 return this;
660 },
661
662 enable: function() {
663 return this._setOption( "disabled", false );
664 },
665 disable: function() {
666 return this._setOption( "disabled", true );
667 },
668
669 _on: function( suppressDisabledCheck, element, handlers ) {
670 var delegateElement,
671 instance = this;
672
673 // no suppressDisabledCheck flag, shuffle arguments
674 if ( typeof suppressDisabledCheck !== "boolean" ) {
675 handlers = element;
676 element = suppressDisabledCheck;
677 suppressDisabledCheck = false;
678 }
679
680 // no element argument, shuffle and use this.element
681 if ( !handlers ) {
682 handlers = element;
683 element = this.element;
684 delegateElement = this.widget();
685 } else {
686 // accept selectors, DOM elements
687 element = delegateElement = $( element );
688 this.bindings = this.bindings.add( element );
689 }
690
691 $.each( handlers, function( event, handler ) {
692 function handlerProxy() {
693 // allow widgets to customize the disabled handling
694 // - disabled as an array instead of boolean
695 // - disabled class as method for disabling individual parts
696 if ( !suppressDisabledCheck &&
697 ( instance.options.disabled === true ||
698 $( this ).hasClass( "ui-state-disabled" ) ) ) {
699 return;
700 }
701 return ( typeof handler === "string" ? instance[ handler ] : handler )
702 .apply( instance, arguments );
703 }
704
705 // copy the guid so direct unbinding works
706 if ( typeof handler !== "string" ) {
707 handlerProxy.guid = handler.guid =
708 handler.guid || handlerProxy.guid || $.guid++;
709 }
710
711 var match = event.match( /^(\w+)\s*(.*)$/ ),
712 eventName = match[1] + instance.eventNamespace,
713 selector = match[2];
714 if ( selector ) {
715 delegateElement.delegate( selector, eventName, handlerProxy );
716 } else {
717 element.bind( eventName, handlerProxy );
718 }
719 });
720 },
721
722 _off: function( element, eventName ) {
723 eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
724 element.unbind( eventName ).undelegate( eventName );
725 },
726
727 _delay: function( handler, delay ) {
728 function handlerProxy() {
729 return ( typeof handler === "string" ? instance[ handler ] : handler )
730 .apply( instance, arguments );
731 }
732 var instance = this;
733 return setTimeout( handlerProxy, delay || 0 );
734 },
735
736 _hoverable: function( element ) {
737 this.hoverable = this.hoverable.add( element );
738 this._on( element, {
739 mouseenter: function( event ) {
740 $( event.currentTarget ).addClass( "ui-state-hover" );
741 },
742 mouseleave: function( event ) {
743 $( event.currentTarget ).removeClass( "ui-state-hover" );
744 }
745 });
746 },
747
748 _focusable: function( element ) {
749 this.focusable = this.focusable.add( element );
750 this._on( element, {
751 focusin: function( event ) {
752 $( event.currentTarget ).addClass( "ui-state-focus" );
753 },
754 focusout: function( event ) {
755 $( event.currentTarget ).removeClass( "ui-state-focus" );
756 }
757 });
758 },
759
760 _trigger: function( type, event, data ) {
761 var prop, orig,
762 callback = this.options[ type ];
763
764 data = data || {};
765 event = $.Event( event );
766 event.type = ( type === this.widgetEventPrefix ?
767 type :
768 this.widgetEventPrefix + type ).toLowerCase();
769 // the original event may come from any element
770 // so we need to reset the target on the new event
771 event.target = this.element[ 0 ];
772
773 // copy original event properties over to the new event
774 orig = event.originalEvent;
775 if ( orig ) {
776 for ( prop in orig ) {
777 if ( !( prop in event ) ) {
778 event[ prop ] = orig[ prop ];
779 }
780 }
781 }
782
783 this.element.trigger( event, data );
784 return !( $.isFunction( callback ) &&
785 callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
786 event.isDefaultPrevented() );
787 }
788 };
789
790 $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
791 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
792 if ( typeof options === "string" ) {
793 options = { effect: options };
794 }
795 var hasOptions,
796 effectName = !options ?
797 method :
798 options === true || typeof options === "number" ?
799 defaultEffect :
800 options.effect || defaultEffect;
801 options = options || {};
802 if ( typeof options === "number" ) {
803 options = { duration: options };
804 }
805 hasOptions = !$.isEmptyObject( options );
806 options.complete = callback;
807 if ( options.delay ) {
808 element.delay( options.delay );
809 }
810 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
811 element[ method ]( options );
812 } else if ( effectName !== method && element[ effectName ] ) {
813 element[ effectName ]( options.duration, options.easing, callback );
814 } else {
815 element.queue(function( next ) {
816 $( this )[ method ]();
817 if ( callback ) {
818 callback.call( element[ 0 ] );
819 }
820 next();
821 });
822 }
823 };
824 });
825
826 })( jQuery );
827 (function( $, undefined ) {
828
829 var mouseHandled = false;
830 $( document ).mouseup( function() {
831 mouseHandled = false;
832 });
833
834 $.widget("ui.mouse", {
835 version: "1.10.4",
836 options: {
837 cancel: "input,textarea,button,select,option",
838 distance: 1,
839 delay: 0
840 },
841 _mouseInit: function() {
842 var that = this;
843
844 this.element
845 .bind("mousedown."+this.widgetName, function(event) {
846 return that._mouseDown(event);
847 })
848 .bind("click."+this.widgetName, function(event) {
849 if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) {
850 $.removeData(event.target, that.widgetName + ".preventClickEvent");
851 event.stopImmediatePropagation();
852 return false;
853 }
854 });
855
856 this.started = false;
857 },
858
859 // TODO: make sure destroying one instance of mouse doesn't mess with
860 // other instances of mouse
861 _mouseDestroy: function() {
862 this.element.unbind("."+this.widgetName);
863 if ( this._mouseMoveDelegate ) {
864 $(document)
865 .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate)
866 .unbind("mouseup."+this.widgetName, this._mouseUpDelegate);
867 }
868 },
869
870 _mouseDown: function(event) {
871 // don't let more than one widget handle mouseStart
872 if( mouseHandled ) { return; }
873
874 // we may have missed mouseup (out of window)
875 (this._mouseStarted && this._mouseUp(event));
876
877 this._mouseDownEvent = event;
878
879 var that = this,
880 btnIsLeft = (event.which === 1),
881 // event.target.nodeName works around a bug in IE 8 with
882 // disabled inputs (#7620)
883 elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
884 if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
885 return true;
886 }
887
888 this.mouseDelayMet = !this.options.delay;
889 if (!this.mouseDelayMet) {
890 this._mouseDelayTimer = setTimeout(function() {
891 that.mouseDelayMet = true;
892 }, this.options.delay);
893 }
894
895 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
896 this._mouseStarted = (this._mouseStart(event) !== false);
897 if (!this._mouseStarted) {
898 event.preventDefault();
899 return true;
900 }
901 }
902
903 // Click event may never have fired (Gecko & Opera)
904 if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) {
905 $.removeData(event.target, this.widgetName + ".preventClickEvent");
906 }
907
908 // these delegates are required to keep context
909 this._mouseMoveDelegate = function(event) {
910 return that._mouseMove(event);
911 };
912 this._mouseUpDelegate = function(event) {
913 return that._mouseUp(event);
914 };
915 $(document)
916 .bind("mousemove."+this.widgetName, this._mouseMoveDelegate)
917 .bind("mouseup."+this.widgetName, this._mouseUpDelegate);
918
919 event.preventDefault();
920
921 mouseHandled = true;
922 return true;
923 },
924
925 _mouseMove: function(event) {
926 // IE mouseup check - mouseup happened when mouse was out of window
927 if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) {
928 return this._mouseUp(event);
929 }
930
931 if (this._mouseStarted) {
932 this._mouseDrag(event);
933 return event.preventDefault();
934 }
935
936 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
937 this._mouseStarted =
938 (this._mouseStart(this._mouseDownEvent, event) !== false);
939 (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
940 }
941
942 return !this._mouseStarted;
943 },
944
945 _mouseUp: function(event) {
946 $(document)
947 .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate)
948 .unbind("mouseup."+this.widgetName, this._mouseUpDelegate);
949
950 if (this._mouseStarted) {
951 this._mouseStarted = false;
952
953 if (event.target === this._mouseDownEvent.target) {
954 $.data(event.target, this.widgetName + ".preventClickEvent", true);
955 }
956
957 this._mouseStop(event);
958 }
959
960 return false;
961 },
962
963 _mouseDistanceMet: function(event) {
964 return (Math.max(
965 Math.abs(this._mouseDownEvent.pageX - event.pageX),
966 Math.abs(this._mouseDownEvent.pageY - event.pageY)
967 ) >= this.options.distance
968 );
969 },
970
971 _mouseDelayMet: function(/* event */) {
972 return this.mouseDelayMet;
973 },
974
975 // These are placeholder methods, to be overriden by extending plugin
976 _mouseStart: function(/* event */) {},
977 _mouseDrag: function(/* event */) {},
978 _mouseStop: function(/* event */) {},
979 _mouseCapture: function(/* event */) { return true; }
980 });
981
982 })(jQuery);
983 (function( $, undefined ) {
984
985 $.ui = $.ui || {};
986
987 var cachedScrollbarWidth,
988 max = Math.max,
989 abs = Math.abs,
990 round = Math.round,
991 rhorizontal = /left|center|right/,
992 rvertical = /top|center|bottom/,
993 roffset = /[\+\-]\d+(\.[\d]+)?%?/,
994 rposition = /^\w+/,
995 rpercent = /%$/,
996 _position = $.fn.position;
997
998 function getOffsets( offsets, width, height ) {
999 return [
1000 parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
1001 parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
1002 ];
1003 }
1004
1005 function parseCss( element, property ) {
1006 return parseInt( $.css( element, property ), 10 ) || 0;
1007 }
1008
1009 function getDimensions( elem ) {
1010 var raw = elem[0];
1011 if ( raw.nodeType === 9 ) {
1012 return {
1013 width: elem.width(),
1014 height: elem.height(),
1015 offset: { top: 0, left: 0 }
1016 };
1017 }
1018 if ( $.isWindow( raw ) ) {
1019 return {
1020 width: elem.width(),
1021 height: elem.height(),
1022 offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
1023 };
1024 }
1025 if ( raw.preventDefault ) {
1026 return {
1027 width: 0,
1028 height: 0,
1029 offset: { top: raw.pageY, left: raw.pageX }
1030 };
1031 }
1032 return {
1033 width: elem.outerWidth(),
1034 height: elem.outerHeight(),
1035 offset: elem.offset()
1036 };
1037 }
1038
1039 $.position = {
1040 scrollbarWidth: function() {
1041 if ( cachedScrollbarWidth !== undefined ) {
1042 return cachedScrollbarWidth;
1043 }
1044 var w1, w2,
1045 div = $( "<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
1046 innerDiv = div.children()[0];
1047
1048 $( "body" ).append( div );
1049 w1 = innerDiv.offsetWidth;
1050 div.css( "overflow", "scroll" );
1051
1052 w2 = innerDiv.offsetWidth;
1053
1054 if ( w1 === w2 ) {
1055 w2 = div[0].clientWidth;
1056 }
1057
1058 div.remove();
1059
1060 return (cachedScrollbarWidth = w1 - w2);
1061 },
1062 getScrollInfo: function( within ) {
1063 var overflowX = within.isWindow || within.isDocument ? "" :
1064 within.element.css( "overflow-x" ),
1065 overflowY = within.isWindow || within.isDocument ? "" :
1066 within.element.css( "overflow-y" ),
1067 hasOverflowX = overflowX === "scroll" ||
1068 ( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
1069 hasOverflowY = overflowY === "scroll" ||
1070 ( overflowY === "auto" && within.height < within.element[0].scrollHeight );
1071 return {
1072 width: hasOverflowY ? $.position.scrollbarWidth() : 0,
1073 height: hasOverflowX ? $.position.scrollbarWidth() : 0
1074 };
1075 },
1076 getWithinInfo: function( element ) {
1077 var withinElement = $( element || window ),
1078 isWindow = $.isWindow( withinElement[0] ),
1079 isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9;
1080 return {
1081 element: withinElement,
1082 isWindow: isWindow,
1083 isDocument: isDocument,
1084 offset: withinElement.offset() || { left: 0, top: 0 },
1085 scrollLeft: withinElement.scrollLeft(),
1086 scrollTop: withinElement.scrollTop(),
1087 width: isWindow ? withinElement.width() : withinElement.outerWidth(),
1088 height: isWindow ? withinElement.height() : withinElement.outerHeight()
1089 };
1090 }
1091 };
1092
1093 $.fn.position = function( options ) {
1094 if ( !options || !options.of ) {
1095 return _position.apply( this, arguments );
1096 }
1097
1098 // make a copy, we don't want to modify arguments
1099 options = $.extend( {}, options );
1100
1101 var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
1102 target = $( options.of ),
1103 within = $.position.getWithinInfo( options.within ),
1104 scrollInfo = $.position.getScrollInfo( within ),
1105 collision = ( options.collision || "flip" ).split( " " ),
1106 offsets = {};
1107
1108 dimensions = getDimensions( target );
1109 if ( target[0].preventDefault ) {
1110 // force left top to allow flipping
1111 options.at = "left top";
1112 }
1113 targetWidth = dimensions.width;
1114 targetHeight = dimensions.height;
1115 targetOffset = dimensions.offset;
1116 // clone to reuse original targetOffset later
1117 basePosition = $.extend( {}, targetOffset );
1118
1119 // force my and at to have valid horizontal and vertical positions
1120 // if a value is missing or invalid, it will be converted to center
1121 $.each( [ "my", "at" ], function() {
1122 var pos = ( options[ this ] || "" ).split( " " ),
1123 horizontalOffset,
1124 verticalOffset;
1125
1126 if ( pos.length === 1) {
1127 pos = rhorizontal.test( pos[ 0 ] ) ?
1128 pos.concat( [ "center" ] ) :
1129 rvertical.test( pos[ 0 ] ) ?
1130 [ "center" ].concat( pos ) :
1131 [ "center", "center" ];
1132 }
1133 pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
1134 pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
1135
1136 // calculate offsets
1137 horizontalOffset = roffset.exec( pos[ 0 ] );
1138 verticalOffset = roffset.exec( pos[ 1 ] );
1139 offsets[ this ] = [
1140 horizontalOffset ? horizontalOffset[ 0 ] : 0,
1141 verticalOffset ? verticalOffset[ 0 ] : 0
1142 ];
1143
1144 // reduce to just the positions without the offsets
1145 options[ this ] = [
1146 rposition.exec( pos[ 0 ] )[ 0 ],
1147 rposition.exec( pos[ 1 ] )[ 0 ]
1148 ];
1149 });
1150
1151 // normalize collision option
1152 if ( collision.length === 1 ) {
1153 collision[ 1 ] = collision[ 0 ];
1154 }
1155
1156 if ( options.at[ 0 ] === "right" ) {
1157 basePosition.left += targetWidth;
1158 } else if ( options.at[ 0 ] === "center" ) {
1159 basePosition.left += targetWidth / 2;
1160 }
1161
1162 if ( options.at[ 1 ] === "bottom" ) {
1163 basePosition.top += targetHeight;
1164 } else if ( options.at[ 1 ] === "center" ) {
1165 basePosition.top += targetHeight / 2;
1166 }
1167
1168 atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
1169 basePosition.left += atOffset[ 0 ];
1170 basePosition.top += atOffset[ 1 ];
1171
1172 return this.each(function() {
1173 var collisionPosition, using,
1174 elem = $( this ),
1175 elemWidth = elem.outerWidth(),
1176 elemHeight = elem.outerHeight(),
1177 marginLeft = parseCss( this, "marginLeft" ),
1178 marginTop = parseCss( this, "marginTop" ),
1179 collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
1180 collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
1181 position = $.extend( {}, basePosition ),
1182 myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
1183
1184 if ( options.my[ 0 ] === "right" ) {
1185 position.left -= elemWidth;
1186 } else if ( options.my[ 0 ] === "center" ) {
1187 position.left -= elemWidth / 2;
1188 }
1189
1190 if ( options.my[ 1 ] === "bottom" ) {
1191 position.top -= elemHeight;
1192 } else if ( options.my[ 1 ] === "center" ) {
1193 position.top -= elemHeight / 2;
1194 }
1195
1196 position.left += myOffset[ 0 ];
1197 position.top += myOffset[ 1 ];
1198
1199 // if the browser doesn't support fractions, then round for consistent results
1200 if ( !$.support.offsetFractions ) {
1201 position.left = round( position.left );
1202 position.top = round( position.top );
1203 }
1204
1205 collisionPosition = {
1206 marginLeft: marginLeft,
1207 marginTop: marginTop
1208 };
1209
1210 $.each( [ "left", "top" ], function( i, dir ) {
1211 if ( $.ui.position[ collision[ i ] ] ) {
1212 $.ui.position[ collision[ i ] ][ dir ]( position, {
1213 targetWidth: targetWidth,
1214 targetHeight: targetHeight,
1215 elemWidth: elemWidth,
1216 elemHeight: elemHeight,
1217 collisionPosition: collisionPosition,
1218 collisionWidth: collisionWidth,
1219 collisionHeight: collisionHeight,
1220 offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
1221 my: options.my,
1222 at: options.at,
1223 within: within,
1224 elem : elem
1225 });
1226 }
1227 });
1228
1229 if ( options.using ) {
1230 // adds feedback as second argument to using callback, if present
1231 using = function( props ) {
1232 var left = targetOffset.left - position.left,
1233 right = left + targetWidth - elemWidth,
1234 top = targetOffset.top - position.top,
1235 bottom = top + targetHeight - elemHeight,
1236 feedback = {
1237 target: {
1238 element: target,
1239 left: targetOffset.left,
1240 top: targetOffset.top,
1241 width: targetWidth,
1242 height: targetHeight
1243 },
1244 element: {
1245 element: elem,
1246 left: position.left,
1247 top: position.top,
1248 width: elemWidth,
1249 height: elemHeight
1250 },
1251 horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
1252 vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
1253 };
1254 if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
1255 feedback.horizontal = "center";
1256 }
1257 if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
1258 feedback.vertical = "middle";
1259 }
1260 if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
1261 feedback.important = "horizontal";
1262 } else {
1263 feedback.important = "vertical";
1264 }
1265 options.using.call( this, props, feedback );
1266 };
1267 }
1268
1269 elem.offset( $.extend( position, { using: using } ) );
1270 });
1271 };
1272
1273 $.ui.position = {
1274 fit: {
1275 left: function( position, data ) {
1276 var within = data.within,
1277 withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
1278 outerWidth = within.width,
1279 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1280 overLeft = withinOffset - collisionPosLeft,
1281 overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
1282 newOverRight;
1283
1284 // element is wider than within
1285 if ( data.collisionWidth > outerWidth ) {
1286 // element is initially over the left side of within
1287 if ( overLeft > 0 && overRight <= 0 ) {
1288 newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
1289 position.left += overLeft - newOverRight;
1290 // element is initially over right side of within
1291 } else if ( overRight > 0 && overLeft <= 0 ) {
1292 position.left = withinOffset;
1293 // element is initially over both left and right sides of within
1294 } else {
1295 if ( overLeft > overRight ) {
1296 position.left = withinOffset + outerWidth - data.collisionWidth;
1297 } else {
1298 position.left = withinOffset;
1299 }
1300 }
1301 // too far left -> align with left edge
1302 } else if ( overLeft > 0 ) {
1303 position.left += overLeft;
1304 // too far right -> align with right edge
1305 } else if ( overRight > 0 ) {
1306 position.left -= overRight;
1307 // adjust based on position and margin
1308 } else {
1309 position.left = max( position.left - collisionPosLeft, position.left );
1310 }
1311 },
1312 top: function( position, data ) {
1313 var within = data.within,
1314 withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
1315 outerHeight = data.within.height,
1316 collisionPosTop = position.top - data.collisionPosition.marginTop,
1317 overTop = withinOffset - collisionPosTop,
1318 overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
1319 newOverBottom;
1320
1321 // element is taller than within
1322 if ( data.collisionHeight > outerHeight ) {
1323 // element is initially over the top of within
1324 if ( overTop > 0 && overBottom <= 0 ) {
1325 newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
1326 position.top += overTop - newOverBottom;
1327 // element is initially over bottom of within
1328 } else if ( overBottom > 0 && overTop <= 0 ) {
1329 position.top = withinOffset;
1330 // element is initially over both top and bottom of within
1331 } else {
1332 if ( overTop > overBottom ) {
1333 position.top = withinOffset + outerHeight - data.collisionHeight;
1334 } else {
1335 position.top = withinOffset;
1336 }
1337 }
1338 // too far up -> align with top
1339 } else if ( overTop > 0 ) {
1340 position.top += overTop;
1341 // too far down -> align with bottom edge
1342 } else if ( overBottom > 0 ) {
1343 position.top -= overBottom;
1344 // adjust based on position and margin
1345 } else {
1346 position.top = max( position.top - collisionPosTop, position.top );
1347 }
1348 }
1349 },
1350 flip: {
1351 left: function( position, data ) {
1352 var within = data.within,
1353 withinOffset = within.offset.left + within.scrollLeft,
1354 outerWidth = within.width,
1355 offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
1356 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1357 overLeft = collisionPosLeft - offsetLeft,
1358 overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
1359 myOffset = data.my[ 0 ] === "left" ?
1360 -data.elemWidth :
1361 data.my[ 0 ] === "right" ?
1362 data.elemWidth :
1363 0,
1364 atOffset = data.at[ 0 ] === "left" ?
1365 data.targetWidth :
1366 data.at[ 0 ] === "right" ?
1367 -data.targetWidth :
1368 0,
1369 offset = -2 * data.offset[ 0 ],
1370 newOverRight,
1371 newOverLeft;
1372
1373 if ( overLeft < 0 ) {
1374 newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
1375 if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
1376 position.left += myOffset + atOffset + offset;
1377 }
1378 }
1379 else if ( overRight > 0 ) {
1380 newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
1381 if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
1382 position.left += myOffset + atOffset + offset;
1383 }
1384 }
1385 },
1386 top: function( position, data ) {
1387 var within = data.within,
1388 withinOffset = within.offset.top + within.scrollTop,
1389 outerHeight = within.height,
1390 offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
1391 collisionPosTop = position.top - data.collisionPosition.marginTop,
1392 overTop = collisionPosTop - offsetTop,
1393 overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
1394 top = data.my[ 1 ] === "top",
1395 myOffset = top ?
1396 -data.elemHeight :
1397 data.my[ 1 ] === "bottom" ?
1398 data.elemHeight :
1399 0,
1400 atOffset = data.at[ 1 ] === "top" ?
1401 data.targetHeight :
1402 data.at[ 1 ] === "bottom" ?
1403 -data.targetHeight :
1404 0,
1405 offset = -2 * data.offset[ 1 ],
1406 newOverTop,
1407 newOverBottom;
1408 if ( overTop < 0 ) {
1409 newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
1410 if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) {
1411 position.top += myOffset + atOffset + offset;
1412 }
1413 }
1414 else if ( overBottom > 0 ) {
1415 newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
1416 if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) {
1417 position.top += myOffset + atOffset + offset;
1418 }
1419 }
1420 }
1421 },
1422 flipfit: {
1423 left: function() {
1424 $.ui.position.flip.left.apply( this, arguments );
1425 $.ui.position.fit.left.apply( this, arguments );
1426 },
1427 top: function() {
1428 $.ui.position.flip.top.apply( this, arguments );
1429 $.ui.position.fit.top.apply( this, arguments );
1430 }
1431 }
1432 };
1433
1434 // fraction support test
1435 (function () {
1436 var testElement, testElementParent, testElementStyle, offsetLeft, i,
1437 body = document.getElementsByTagName( "body" )[ 0 ],
1438 div = document.createElement( "div" );
1439
1440 //Create a "fake body" for testing based on method used in jQuery.support
1441 testElement = document.createElement( body ? "div" : "body" );
1442 testElementStyle = {
1443 visibility: "hidden",
1444 width: 0,
1445 height: 0,
1446 border: 0,
1447 margin: 0,
1448 background: "none"
1449 };
1450 if ( body ) {
1451 $.extend( testElementStyle, {
1452 position: "absolute",
1453 left: "-1000px",
1454 top: "-1000px"
1455 });
1456 }
1457 for ( i in testElementStyle ) {
1458 testElement.style[ i ] = testElementStyle[ i ];
1459 }
1460 testElement.appendChild( div );
1461 testElementParent = body || document.documentElement;
1462 testElementParent.insertBefore( testElement, testElementParent.firstChild );
1463
1464 div.style.cssText = "position: absolute; left: 10.7432222px;";
1465
1466 offsetLeft = $( div ).offset().left;
1467 $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11;
1468
1469 testElement.innerHTML = "";
1470 testElementParent.removeChild( testElement );
1471 })();
1472
1473 }( jQuery ) );
1474 (function( $, undefined ) {
1475
1476 var uid = 0,
1477 hideProps = {},
1478 showProps = {};
1479
1480 hideProps.height = hideProps.paddingTop = hideProps.paddingBottom =
1481 hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide";
1482 showProps.height = showProps.paddingTop = showProps.paddingBottom =
1483 showProps.borderTopWidth = showProps.borderBottomWidth = "show";
1484
1485 $.widget( "ui.accordion", {
1486 version: "1.10.4",
1487 options: {
1488 active: 0,
1489 animate: {},
1490 collapsible: false,
1491 event: "click",
1492 header: "> li > :first-child,> :not(li):even",
1493 heightStyle: "auto",
1494 icons: {
1495 activeHeader: "ui-icon-triangle-1-s",
1496 header: "ui-icon-triangle-1-e"
1497 },
1498
1499 // callbacks
1500 activate: null,
1501 beforeActivate: null
1502 },
1503
1504 _create: function() {
1505 var options = this.options;
1506 this.prevShow = this.prevHide = $();
1507 this.element.addClass( "ui-accordion ui-widget ui-helper-reset" )
1508 // ARIA
1509 .attr( "role", "tablist" );
1510
1511 // don't allow collapsible: false and active: false / null
1512 if ( !options.collapsible && (options.active === false || options.active == null) ) {
1513 options.active = 0;
1514 }
1515
1516 this._processPanels();
1517 // handle negative values
1518 if ( options.active < 0 ) {
1519 options.active += this.headers.length;
1520 }
1521 this._refresh();
1522 },
1523
1524 _getCreateEventData: function() {
1525 return {
1526 header: this.active,
1527 panel: !this.active.length ? $() : this.active.next(),
1528 content: !this.active.length ? $() : this.active.next()
1529 };
1530 },
1531
1532 _createIcons: function() {
1533 var icons = this.options.icons;
1534 if ( icons ) {
1535 $( "<span>" )
1536 .addClass( "ui-accordion-header-icon ui-icon " + icons.header )
1537 .prependTo( this.headers );
1538 this.active.children( ".ui-accordion-header-icon" )
1539 .removeClass( icons.header )
1540 .addClass( icons.activeHeader );
1541 this.headers.addClass( "ui-accordion-icons" );
1542 }
1543 },
1544
1545 _destroyIcons: function() {
1546 this.headers
1547 .removeClass( "ui-accordion-icons" )
1548 .children( ".ui-accordion-header-icon" )
1549 .remove();
1550 },
1551
1552 _destroy: function() {
1553 var contents;
1554
1555 // clean up main element
1556 this.element
1557 .removeClass( "ui-accordion ui-widget ui-helper-reset" )
1558 .removeAttr( "role" );
1559
1560 // clean up headers
1561 this.headers
1562 .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" )
1563 .removeAttr( "role" )
1564 .removeAttr( "aria-expanded" )
1565 .removeAttr( "aria-selected" )
1566 .removeAttr( "aria-controls" )
1567 .removeAttr( "tabIndex" )
1568 .each(function() {
1569 if ( /^ui-accordion/.test( this.id ) ) {
1570 this.removeAttribute( "id" );
1571 }
1572 });
1573 this._destroyIcons();
1574
1575 // clean up content panels
1576 contents = this.headers.next()
1577 .css( "display", "" )
1578 .removeAttr( "role" )
1579 .removeAttr( "aria-hidden" )
1580 .removeAttr( "aria-labelledby" )
1581 .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" )
1582 .each(function() {
1583 if ( /^ui-accordion/.test( this.id ) ) {
1584 this.removeAttribute( "id" );
1585 }
1586 });
1587 if ( this.options.heightStyle !== "content" ) {
1588 contents.css( "height", "" );
1589 }
1590 },
1591
1592 _setOption: function( key, value ) {
1593 if ( key === "active" ) {
1594 // _activate() will handle invalid values and update this.options
1595 this._activate( value );
1596 return;
1597 }
1598
1599 if ( key === "event" ) {
1600 if ( this.options.event ) {
1601 this._off( this.headers, this.options.event );
1602 }
1603 this._setupEvents( value );
1604 }
1605
1606 this._super( key, value );
1607
1608 // setting collapsible: false while collapsed; open first panel
1609 if ( key === "collapsible" && !value && this.options.active === false ) {
1610 this._activate( 0 );
1611 }
1612
1613 if ( key === "icons" ) {
1614 this._destroyIcons();
1615 if ( value ) {
1616 this._createIcons();
1617 }
1618 }
1619
1620 // #5332 - opacity doesn't cascade to positioned elements in IE
1621 // so we need to add the disabled class to the headers and panels
1622 if ( key === "disabled" ) {
1623 this.headers.add( this.headers.next() )
1624 .toggleClass( "ui-state-disabled", !!value );
1625 }
1626 },
1627
1628 _keydown: function( event ) {
1629 if ( event.altKey || event.ctrlKey ) {
1630 return;
1631 }
1632
1633 var keyCode = $.ui.keyCode,
1634 length = this.headers.length,
1635 currentIndex = this.headers.index( event.target ),
1636 toFocus = false;
1637
1638 switch ( event.keyCode ) {
1639 case keyCode.RIGHT:
1640 case keyCode.DOWN:
1641 toFocus = this.headers[ ( currentIndex + 1 ) % length ];
1642 break;
1643 case keyCode.LEFT:
1644 case keyCode.UP:
1645 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
1646 break;
1647 case keyCode.SPACE:
1648 case keyCode.ENTER:
1649 this._eventHandler( event );
1650 break;
1651 case keyCode.HOME:
1652 toFocus = this.headers[ 0 ];
1653 break;
1654 case keyCode.END:
1655 toFocus = this.headers[ length - 1 ];
1656 break;
1657 }
1658
1659 if ( toFocus ) {
1660 $( event.target ).attr( "tabIndex", -1 );
1661 $( toFocus ).attr( "tabIndex", 0 );
1662 toFocus.focus();
1663 event.preventDefault();
1664 }
1665 },
1666
1667 _panelKeyDown : function( event ) {
1668 if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
1669 $( event.currentTarget ).prev().focus();
1670 }
1671 },
1672
1673 refresh: function() {
1674 var options = this.options;
1675 this._processPanels();
1676
1677 // was collapsed or no panel
1678 if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) {
1679 options.active = false;
1680 this.active = $();
1681 // active false only when collapsible is true
1682 } else if ( options.active === false ) {
1683 this._activate( 0 );
1684 // was active, but active panel is gone
1685 } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
1686 // all remaining panel are disabled
1687 if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) {
1688 options.active = false;
1689 this.active = $();
1690 // activate previous panel
1691 } else {
1692 this._activate( Math.max( 0, options.active - 1 ) );
1693 }
1694 // was active, active panel still exists
1695 } else {
1696 // make sure active index is correct
1697 options.active = this.headers.index( this.active );
1698 }
1699
1700 this._destroyIcons();
1701
1702 this._refresh();
1703 },
1704
1705 _processPanels: function() {
1706 this.headers = this.element.find( this.options.header )
1707 .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" );
1708
1709 this.headers.next()
1710 .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
1711 .filter(":not(.ui-accordion-content-active)")
1712 .hide();
1713 },
1714
1715 _refresh: function() {
1716 var maxHeight,
1717 options = this.options,
1718 heightStyle = options.heightStyle,
1719 parent = this.element.parent(),
1720 accordionId = this.accordionId = "ui-accordion-" +
1721 (this.element.attr( "id" ) || ++uid);
1722
1723 this.active = this._findActive( options.active )
1724 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" )
1725 .removeClass( "ui-corner-all" );
1726 this.active.next()
1727 .addClass( "ui-accordion-content-active" )
1728 .show();
1729
1730 this.headers
1731 .attr( "role", "tab" )
1732 .each(function( i ) {
1733 var header = $( this ),
1734 headerId = header.attr( "id" ),
1735 panel = header.next(),
1736 panelId = panel.attr( "id" );
1737 if ( !headerId ) {
1738 headerId = accordionId + "-header-" + i;
1739 header.attr( "id", headerId );
1740 }
1741 if ( !panelId ) {
1742 panelId = accordionId + "-panel-" + i;
1743 panel.attr( "id", panelId );
1744 }
1745 header.attr( "aria-controls", panelId );
1746 panel.attr( "aria-labelledby", headerId );
1747 })
1748 .next()
1749 .attr( "role", "tabpanel" );
1750
1751 this.headers
1752 .not( this.active )
1753 .attr({
1754 "aria-selected": "false",
1755 "aria-expanded": "false",
1756 tabIndex: -1
1757 })
1758 .next()
1759 .attr({
1760 "aria-hidden": "true"
1761 })
1762 .hide();
1763
1764 // make sure at least one header is in the tab order
1765 if ( !this.active.length ) {
1766 this.headers.eq( 0 ).attr( "tabIndex", 0 );
1767 } else {
1768 this.active.attr({
1769 "aria-selected": "true",
1770 "aria-expanded": "true",
1771 tabIndex: 0
1772 })
1773 .next()
1774 .attr({
1775 "aria-hidden": "false"
1776 });
1777 }
1778
1779 this._createIcons();
1780
1781 this._setupEvents( options.event );
1782
1783 if ( heightStyle === "fill" ) {
1784 maxHeight = parent.height();
1785 this.element.siblings( ":visible" ).each(function() {
1786 var elem = $( this ),
1787 position = elem.css( "position" );
1788
1789 if ( position === "absolute" || position === "fixed" ) {
1790 return;
1791 }
1792 maxHeight -= elem.outerHeight( true );
1793 });
1794
1795 this.headers.each(function() {
1796 maxHeight -= $( this ).outerHeight( true );
1797 });
1798
1799 this.headers.next()
1800 .each(function() {
1801 $( this ).height( Math.max( 0, maxHeight -
1802 $( this ).innerHeight() + $( this ).height() ) );
1803 })
1804 .css( "overflow", "auto" );
1805 } else if ( heightStyle === "auto" ) {
1806 maxHeight = 0;
1807 this.headers.next()
1808 .each(function() {
1809 maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
1810 })
1811 .height( maxHeight );
1812 }
1813 },
1814
1815 _activate: function( index ) {
1816 var active = this._findActive( index )[ 0 ];
1817
1818 // trying to activate the already active panel
1819 if ( active === this.active[ 0 ] ) {
1820 return;
1821 }
1822
1823 // trying to collapse, simulate a click on the currently active header
1824 active = active || this.active[ 0 ];
1825
1826 this._eventHandler({
1827 target: active,
1828 currentTarget: active,
1829 preventDefault: $.noop
1830 });
1831 },
1832
1833 _findActive: function( selector ) {
1834 return typeof selector === "number" ? this.headers.eq( selector ) : $();
1835 },
1836
1837 _setupEvents: function( event ) {
1838 var events = {
1839 keydown: "_keydown"
1840 };
1841 if ( event ) {
1842 $.each( event.split(" "), function( index, eventName ) {
1843 events[ eventName ] = "_eventHandler";
1844 });
1845 }
1846
1847 this._off( this.headers.add( this.headers.next() ) );
1848 this._on( this.headers, events );
1849 this._on( this.headers.next(), { keydown: "_panelKeyDown" });
1850 this._hoverable( this.headers );
1851 this._focusable( this.headers );
1852 },
1853
1854 _eventHandler: function( event ) {
1855 var options = this.options,
1856 active = this.active,
1857 clicked = $( event.currentTarget ),
1858 clickedIsActive = clicked[ 0 ] === active[ 0 ],
1859 collapsing = clickedIsActive && options.collapsible,
1860 toShow = collapsing ? $() : clicked.next(),
1861 toHide = active.next(),
1862 eventData = {
1863 oldHeader: active,
1864 oldPanel: toHide,
1865 newHeader: collapsing ? $() : clicked,
1866 newPanel: toShow
1867 };
1868
1869 event.preventDefault();
1870
1871 if (
1872 // click on active header, but not collapsible
1873 ( clickedIsActive && !options.collapsible ) ||
1874 // allow canceling activation
1875 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
1876 return;
1877 }
1878
1879 options.active = collapsing ? false : this.headers.index( clicked );
1880
1881 // when the call to ._toggle() comes after the class changes
1882 // it causes a very odd bug in IE 8 (see #6720)
1883 this.active = clickedIsActive ? $() : clicked;
1884 this._toggle( eventData );
1885
1886 // switch classes
1887 // corner classes on the previously active header stay after the animation
1888 active.removeClass( "ui-accordion-header-active ui-state-active" );
1889 if ( options.icons ) {
1890 active.children( ".ui-accordion-header-icon" )
1891 .removeClass( options.icons.activeHeader )
1892 .addClass( options.icons.header );
1893 }
1894
1895 if ( !clickedIsActive ) {
1896 clicked
1897 .removeClass( "ui-corner-all" )
1898 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" );
1899 if ( options.icons ) {
1900 clicked.children( ".ui-accordion-header-icon" )
1901 .removeClass( options.icons.header )
1902 .addClass( options.icons.activeHeader );
1903 }
1904
1905 clicked
1906 .next()
1907 .addClass( "ui-accordion-content-active" );
1908 }
1909 },
1910
1911 _toggle: function( data ) {
1912 var toShow = data.newPanel,
1913 toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
1914
1915 // handle activating a panel during the animation for another activation
1916 this.prevShow.add( this.prevHide ).stop( true, true );
1917 this.prevShow = toShow;
1918 this.prevHide = toHide;
1919
1920 if ( this.options.animate ) {
1921 this._animate( toShow, toHide, data );
1922 } else {
1923 toHide.hide();
1924 toShow.show();
1925 this._toggleComplete( data );
1926 }
1927
1928 toHide.attr({
1929 "aria-hidden": "true"
1930 });
1931 toHide.prev().attr( "aria-selected", "false" );
1932 // if we're switching panels, remove the old header from the tab order
1933 // if we're opening from collapsed state, remove the previous header from the tab order
1934 // if we're collapsing, then keep the collapsing header in the tab order
1935 if ( toShow.length && toHide.length ) {
1936 toHide.prev().attr({
1937 "tabIndex": -1,
1938 "aria-expanded": "false"
1939 });
1940 } else if ( toShow.length ) {
1941 this.headers.filter(function() {
1942 return $( this ).attr( "tabIndex" ) === 0;
1943 })
1944 .attr( "tabIndex", -1 );
1945 }
1946
1947 toShow
1948 .attr( "aria-hidden", "false" )
1949 .prev()
1950 .attr({
1951 "aria-selected": "true",
1952 tabIndex: 0,
1953 "aria-expanded": "true"
1954 });
1955 },
1956
1957 _animate: function( toShow, toHide, data ) {
1958 var total, easing, duration,
1959 that = this,
1960 adjust = 0,
1961 down = toShow.length &&
1962 ( !toHide.length || ( toShow.index() < toHide.index() ) ),
1963 animate = this.options.animate || {},
1964 options = down && animate.down || animate,
1965 complete = function() {
1966 that._toggleComplete( data );
1967 };
1968
1969 if ( typeof options === "number" ) {
1970 duration = options;
1971 }
1972 if ( typeof options === "string" ) {
1973 easing = options;
1974 }
1975 // fall back from options to animation in case of partial down settings
1976 easing = easing || options.easing || animate.easing;
1977 duration = duration || options.duration || animate.duration;
1978
1979 if ( !toHide.length ) {
1980 return toShow.animate( showProps, duration, easing, complete );
1981 }
1982 if ( !toShow.length ) {
1983 return toHide.animate( hideProps, duration, easing, complete );
1984 }
1985
1986 total = toShow.show().outerHeight();
1987 toHide.animate( hideProps, {
1988 duration: duration,
1989 easing: easing,
1990 step: function( now, fx ) {
1991 fx.now = Math.round( now );
1992 }
1993 });
1994 toShow
1995 .hide()
1996 .animate( showProps, {
1997 duration: duration,
1998 easing: easing,
1999 complete: complete,
2000 step: function( now, fx ) {
2001 fx.now = Math.round( now );
2002 if ( fx.prop !== "height" ) {
2003 adjust += fx.now;
2004 } else if ( that.options.heightStyle !== "content" ) {
2005 fx.now = Math.round( total - toHide.outerHeight() - adjust );
2006 adjust = 0;
2007 }
2008 }
2009 });
2010 },
2011
2012 _toggleComplete: function( data ) {
2013 var toHide = data.oldPanel;
2014
2015 toHide
2016 .removeClass( "ui-accordion-content-active" )
2017 .prev()
2018 .removeClass( "ui-corner-top" )
2019 .addClass( "ui-corner-all" );
2020
2021 // Work around for rendering bug in IE (#5421)
2022 if ( toHide.length ) {
2023 toHide.parent()[0].className = toHide.parent()[0].className;
2024 }
2025 this._trigger( "activate", null, data );
2026 }
2027 });
2028
2029 })( jQuery );
2030 (function( $, undefined ) {
2031
2032 $.widget( "ui.autocomplete", {
2033 version: "1.10.4",
2034 defaultElement: "<input>",
2035 options: {
2036 appendTo: null,
2037 autoFocus: false,
2038 delay: 300,
2039 minLength: 1,
2040 position: {
2041 my: "left top",
2042 at: "left bottom",
2043 collision: "none"
2044 },
2045 source: null,
2046
2047 // callbacks
2048 change: null,
2049 close: null,
2050 focus: null,
2051 open: null,
2052 response: null,
2053 search: null,
2054 select: null
2055 },
2056
2057 requestIndex: 0,
2058 pending: 0,
2059
2060 _create: function() {
2061 // Some browsers only repeat keydown events, not keypress events,
2062 // so we use the suppressKeyPress flag to determine if we've already
2063 // handled the keydown event. #7269
2064 // Unfortunately the code for & in keypress is the same as the up arrow,
2065 // so we use the suppressKeyPressRepeat flag to avoid handling keypress
2066 // events when we know the keydown event was used to modify the
2067 // search term. #7799
2068 var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
2069 nodeName = this.element[0].nodeName.toLowerCase(),
2070 isTextarea = nodeName === "textarea",
2071 isInput = nodeName === "input";
2072
2073 this.isMultiLine =
2074 // Textareas are always multi-line
2075 isTextarea ? true :
2076 // Inputs are always single-line, even if inside a contentEditable element
2077 // IE also treats inputs as contentEditable
2078 isInput ? false :
2079 // All other element types are determined by whether or not they're contentEditable
2080 this.element.prop( "isContentEditable" );
2081
2082 this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
2083 this.isNewMenu = true;
2084
2085 this.element
2086 .addClass( "ui-autocomplete-input" )
2087 .attr( "autocomplete", "off" );
2088
2089 this._on( this.element, {
2090 keydown: function( event ) {
2091 if ( this.element.prop( "readOnly" ) ) {
2092 suppressKeyPress = true;
2093 suppressInput = true;
2094 suppressKeyPressRepeat = true;
2095 return;
2096 }
2097
2098 suppressKeyPress = false;
2099 suppressInput = false;
2100 suppressKeyPressRepeat = false;
2101 var keyCode = $.ui.keyCode;
2102 switch( event.keyCode ) {
2103 case keyCode.PAGE_UP:
2104 suppressKeyPress = true;
2105 this._move( "previousPage", event );
2106 break;
2107 case keyCode.PAGE_DOWN:
2108 suppressKeyPress = true;
2109 this._move( "nextPage", event );
2110 break;
2111 case keyCode.UP:
2112 suppressKeyPress = true;
2113 this._keyEvent( "previous", event );
2114 break;
2115 case keyCode.DOWN:
2116 suppressKeyPress = true;
2117 this._keyEvent( "next", event );
2118 break;
2119 case keyCode.ENTER:
2120 case keyCode.NUMPAD_ENTER:
2121 // when menu is open and has focus
2122 if ( this.menu.active ) {
2123 // #6055 - Opera still allows the keypress to occur
2124 // which causes forms to submit
2125 suppressKeyPress = true;
2126 event.preventDefault();
2127 this.menu.select( event );
2128 }
2129 break;
2130 case keyCode.TAB:
2131 if ( this.menu.active ) {
2132 this.menu.select( event );
2133 }
2134 break;
2135 case keyCode.ESCAPE:
2136 if ( this.menu.element.is( ":visible" ) ) {
2137 this._value( this.term );
2138 this.close( event );
2139 // Different browsers have different default behavior for escape
2140 // Single press can mean undo or clear
2141 // Double press in IE means clear the whole form
2142 event.preventDefault();
2143 }
2144 break;
2145 default:
2146 suppressKeyPressRepeat = true;
2147 // search timeout should be triggered before the input value is changed
2148 this._searchTimeout( event );
2149 break;
2150 }
2151 },
2152 keypress: function( event ) {
2153 if ( suppressKeyPress ) {
2154 suppressKeyPress = false;
2155 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
2156 event.preventDefault();
2157 }
2158 return;
2159 }
2160 if ( suppressKeyPressRepeat ) {
2161 return;
2162 }
2163
2164 // replicate some key handlers to allow them to repeat in Firefox and Opera
2165 var keyCode = $.ui.keyCode;
2166 switch( event.keyCode ) {
2167 case keyCode.PAGE_UP:
2168 this._move( "previousPage", event );
2169 break;
2170 case keyCode.PAGE_DOWN:
2171 this._move( "nextPage", event );
2172 break;
2173 case keyCode.UP:
2174 this._keyEvent( "previous", event );
2175 break;
2176 case keyCode.DOWN:
2177 this._keyEvent( "next", event );
2178 break;
2179 }
2180 },
2181 input: function( event ) {
2182 if ( suppressInput ) {
2183 suppressInput = false;
2184 event.preventDefault();
2185 return;
2186 }
2187 this._searchTimeout( event );
2188 },
2189 focus: function() {
2190 this.selectedItem = null;
2191 this.previous = this._value();
2192 },
2193 blur: function( event ) {
2194 if ( this.cancelBlur ) {
2195 delete this.cancelBlur;
2196 return;
2197 }
2198
2199 clearTimeout( this.searching );
2200 this.close( event );
2201 this._change( event );
2202 }
2203 });
2204
2205 this._initSource();
2206 this.menu = $( "<ul>" )
2207 .addClass( "ui-autocomplete ui-front" )
2208 .appendTo( this._appendTo() )
2209 .menu({
2210 // disable ARIA support, the live region takes care of that
2211 role: null
2212 })
2213 .hide()
2214 .data( "ui-menu" );
2215
2216 this._on( this.menu.element, {
2217 mousedown: function( event ) {
2218 // prevent moving focus out of the text field
2219 event.preventDefault();
2220
2221 // IE doesn't prevent moving focus even with event.preventDefault()
2222 // so we set a flag to know when we should ignore the blur event
2223 this.cancelBlur = true;
2224 this._delay(function() {
2225 delete this.cancelBlur;
2226 });
2227
2228 // clicking on the scrollbar causes focus to shift to the body
2229 // but we can't detect a mouseup or a click immediately afterward
2230 // so we have to track the next mousedown and close the menu if
2231 // the user clicks somewhere outside of the autocomplete
2232 var menuElement = this.menu.element[ 0 ];
2233 if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
2234 this._delay(function() {
2235 var that = this;
2236 this.document.one( "mousedown", function( event ) {
2237 if ( event.target !== that.element[ 0 ] &&
2238 event.target !== menuElement &&
2239 !$.contains( menuElement, event.target ) ) {
2240 that.close();
2241 }
2242 });
2243 });
2244 }
2245 },
2246 menufocus: function( event, ui ) {
2247 // support: Firefox
2248 // Prevent accidental activation of menu items in Firefox (#7024 #9118)
2249 if ( this.isNewMenu ) {
2250 this.isNewMenu = false;
2251 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
2252 this.menu.blur();
2253
2254 this.document.one( "mousemove", function() {
2255 $( event.target ).trigger( event.originalEvent );
2256 });
2257
2258 return;
2259 }
2260 }
2261
2262 var item = ui.item.data( "ui-autocomplete-item" );
2263 if ( false !== this._trigger( "focus", event, { item: item } ) ) {
2264 // use value to match what will end up in the input, if it was a key event
2265 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
2266 this._value( item.value );
2267 }
2268 } else {
2269 // Normally the input is populated with the item's value as the
2270 // menu is navigated, causing screen readers to notice a change and
2271 // announce the item. Since the focus event was canceled, this doesn't
2272 // happen, so we update the live region so that screen readers can
2273 // still notice the change and announce it.
2274 this.liveRegion.text( item.value );
2275 }
2276 },
2277 menuselect: function( event, ui ) {
2278 var item = ui.item.data( "ui-autocomplete-item" ),
2279 previous = this.previous;
2280
2281 // only trigger when focus was lost (click on menu)
2282 if ( this.element[0] !== this.document[0].activeElement ) {
2283 this.element.focus();
2284 this.previous = previous;
2285 // #6109 - IE triggers two focus events and the second
2286 // is asynchronous, so we need to reset the previous
2287 // term synchronously and asynchronously :-(
2288 this._delay(function() {
2289 this.previous = previous;
2290 this.selectedItem = item;
2291 });
2292 }
2293
2294 if ( false !== this._trigger( "select", event, { item: item } ) ) {
2295 this._value( item.value );
2296 }
2297 // reset the term after the select event
2298 // this allows custom select handling to work properly
2299 this.term = this._value();
2300
2301 this.close( event );
2302 this.selectedItem = item;
2303 }
2304 });
2305
2306 this.liveRegion = $( "<span>", {
2307 role: "status",
2308 "aria-live": "polite"
2309 })
2310 .addClass( "ui-helper-hidden-accessible" )
2311 .insertBefore( this.element );
2312
2313 // turning off autocomplete prevents the browser from remembering the
2314 // value when navigating through history, so we re-enable autocomplete
2315 // if the page is unloaded before the widget is destroyed. #7790
2316 this._on( this.window, {
2317 beforeunload: function() {
2318 this.element.removeAttr( "autocomplete" );
2319 }
2320 });
2321 },
2322
2323 _destroy: function() {
2324 clearTimeout( this.searching );
2325 this.element
2326 .removeClass( "ui-autocomplete-input" )
2327 .removeAttr( "autocomplete" );
2328 this.menu.element.remove();
2329 this.liveRegion.remove();
2330 },
2331
2332 _setOption: function( key, value ) {
2333 this._super( key, value );
2334 if ( key === "source" ) {
2335 this._initSource();
2336 }
2337 if ( key === "appendTo" ) {
2338 this.menu.element.appendTo( this._appendTo() );
2339 }
2340 if ( key === "disabled" && value && this.xhr ) {
2341 this.xhr.abort();
2342 }
2343 },
2344
2345 _appendTo: function() {
2346 var element = this.options.appendTo;
2347
2348 if ( element ) {
2349 element = element.jquery || element.nodeType ?
2350 $( element ) :
2351 this.document.find( element ).eq( 0 );
2352 }
2353
2354 if ( !element ) {
2355 element = this.element.closest( ".ui-front" );
2356 }
2357
2358 if ( !element.length ) {
2359 element = this.document[0].body;
2360 }
2361
2362 return element;
2363 },
2364
2365 _initSource: function() {
2366 var array, url,
2367 that = this;
2368 if ( $.isArray(this.options.source) ) {
2369 array = this.options.source;
2370 this.source = function( request, response ) {
2371 response( $.ui.autocomplete.filter( array, request.term ) );
2372 };
2373 } else if ( typeof this.options.source === "string" ) {
2374 url = this.options.source;
2375 this.source = function( request, response ) {
2376 if ( that.xhr ) {
2377 that.xhr.abort();
2378 }
2379 that.xhr = $.ajax({
2380 url: url,
2381 data: request,
2382 dataType: "json",
2383 success: function( data ) {
2384 response( data );
2385 },
2386 error: function() {
2387 response( [] );
2388 }
2389 });
2390 };
2391 } else {
2392 this.source = this.options.source;
2393 }
2394 },
2395
2396 _searchTimeout: function( event ) {
2397 clearTimeout( this.searching );
2398 this.searching = this._delay(function() {
2399 // only search if the value has changed
2400 if ( this.term !== this._value() ) {
2401 this.selectedItem = null;
2402 this.search( null, event );
2403 }
2404 }, this.options.delay );
2405 },
2406
2407 search: function( value, event ) {
2408 value = value != null ? value : this._value();
2409
2410 // always save the actual value, not the one passed as an argument
2411 this.term = this._value();
2412
2413 if ( value.length < this.options.minLength ) {
2414 return this.close( event );
2415 }
2416
2417 if ( this._trigger( "search", event ) === false ) {
2418 return;
2419 }
2420
2421 return this._search( value );
2422 },
2423
2424 _search: function( value ) {
2425 this.pending++;
2426 this.element.addClass( "ui-autocomplete-loading" );
2427 this.cancelSearch = false;
2428
2429 this.source( { term: value }, this._response() );
2430 },
2431
2432 _response: function() {
2433 var index = ++this.requestIndex;
2434
2435 return $.proxy(function( content ) {
2436 if ( index === this.requestIndex ) {
2437 this.__response( content );
2438 }
2439
2440 this.pending--;
2441 if ( !this.pending ) {
2442 this.element.removeClass( "ui-autocomplete-loading" );
2443 }
2444 }, this );
2445 },
2446
2447 __response: function( content ) {
2448 if ( content ) {
2449 content = this._normalize( content );
2450 }
2451 this._trigger( "response", null, { content: content } );
2452 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
2453 this._suggest( content );
2454 this._trigger( "open" );
2455 } else {
2456 // use ._close() instead of .close() so we don't cancel future searches
2457 this._close();
2458 }
2459 },
2460
2461 close: function( event ) {
2462 this.cancelSearch = true;
2463 this._close( event );
2464 },
2465
2466 _close: function( event ) {
2467 if ( this.menu.element.is( ":visible" ) ) {
2468 this.menu.element.hide();
2469 this.menu.blur();
2470 this.isNewMenu = true;
2471 this._trigger( "close", event );
2472 }
2473 },
2474
2475 _change: function( event ) {
2476 if ( this.previous !== this._value() ) {
2477 this._trigger( "change", event, { item: this.selectedItem } );
2478 }
2479 },
2480
2481 _normalize: function( items ) {
2482 // assume all items have the right format when the first item is complete
2483 if ( items.length && items[0].label && items[0].value ) {
2484 return items;
2485 }
2486 return $.map( items, function( item ) {
2487 if ( typeof item === "string" ) {
2488 return {
2489 label: item,
2490 value: item
2491 };
2492 }
2493 return $.extend({
2494 label: item.label || item.value,
2495 value: item.value || item.label
2496 }, item );
2497 });
2498 },
2499
2500 _suggest: function( items ) {
2501 var ul = this.menu.element.empty();
2502 this._renderMenu( ul, items );
2503 this.isNewMenu = true;
2504 this.menu.refresh();
2505
2506 // size and position menu
2507 ul.show();
2508 this._resizeMenu();
2509 ul.position( $.extend({
2510 of: this.element
2511 }, this.options.position ));
2512
2513 if ( this.options.autoFocus ) {
2514 this.menu.next();
2515 }
2516 },
2517
2518 _resizeMenu: function() {
2519 var ul = this.menu.element;
2520 ul.outerWidth( Math.max(
2521 // Firefox wraps long text (possibly a rounding bug)
2522 // so we add 1px to avoid the wrapping (#7513)
2523 ul.width( "" ).outerWidth() + 1,
2524 this.element.outerWidth()
2525 ) );
2526 },
2527
2528 _renderMenu: function( ul, items ) {
2529 var that = this;
2530 $.each( items, function( index, item ) {
2531 that._renderItemData( ul, item );
2532 });
2533 },
2534
2535 _renderItemData: function( ul, item ) {
2536 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
2537 },
2538
2539 _renderItem: function( ul, item ) {
2540 return $( "<li>" )
2541 .append( $( "<a>" ).text( item.label ) )
2542 .appendTo( ul );
2543 },
2544
2545 _move: function( direction, event ) {
2546 if ( !this.menu.element.is( ":visible" ) ) {
2547 this.search( null, event );
2548 return;
2549 }
2550 if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
2551 this.menu.isLastItem() && /^next/.test( direction ) ) {
2552 this._value( this.term );
2553 this.menu.blur();
2554 return;
2555 }
2556 this.menu[ direction ]( event );
2557 },
2558
2559 widget: function() {
2560 return this.menu.element;
2561 },
2562
2563 _value: function() {
2564 return this.valueMethod.apply( this.element, arguments );
2565 },
2566
2567 _keyEvent: function( keyEvent, event ) {
2568 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
2569 this._move( keyEvent, event );
2570
2571 // prevents moving cursor to beginning/end of the text field in some browsers
2572 event.preventDefault();
2573 }
2574 }
2575 });
2576
2577 $.extend( $.ui.autocomplete, {
2578 escapeRegex: function( value ) {
2579 return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
2580 },
2581 filter: function(array, term) {
2582 var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
2583 return $.grep( array, function(value) {
2584 return matcher.test( value.label || value.value || value );
2585 });
2586 }
2587 });
2588
2589
2590 // live region extension, adding a `messages` option
2591 // NOTE: This is an experimental API. We are still investigating
2592 // a full solution for string manipulation and internationalization.
2593 $.widget( "ui.autocomplete", $.ui.autocomplete, {
2594 options: {
2595 messages: {
2596 noResults: "No search results.",
2597 results: function( amount ) {
2598 return amount + ( amount > 1 ? " results are" : " result is" ) +
2599 " available, use up and down arrow keys to navigate.";
2600 }
2601 }
2602 },
2603
2604 __response: function( content ) {
2605 var message;
2606 this._superApply( arguments );
2607 if ( this.options.disabled || this.cancelSearch ) {
2608 return;
2609 }
2610 if ( content && content.length ) {
2611 message = this.options.messages.results( content.length );
2612 } else {
2613 message = this.options.messages.noResults;
2614 }
2615 this.liveRegion.text( message );
2616 }
2617 });
2618
2619 }( jQuery ));
2620 (function( $, undefined ) {
2621
2622 var lastActive,
2623 baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
2624 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",
2625 formResetHandler = function() {
2626 var form = $( this );
2627 setTimeout(function() {
2628 form.find( ":ui-button" ).button( "refresh" );
2629 }, 1 );
2630 },
2631 radioGroup = function( radio ) {
2632 var name = radio.name,
2633 form = radio.form,
2634 radios = $( [] );
2635 if ( name ) {
2636 name = name.replace( /'/g, "\\'" );
2637 if ( form ) {
2638 radios = $( form ).find( "[name='" + name + "']" );
2639 } else {
2640 radios = $( "[name='" + name + "']", radio.ownerDocument )
2641 .filter(function() {
2642 return !this.form;
2643 });
2644 }
2645 }
2646 return radios;
2647 };
2648
2649 $.widget( "ui.button", {
2650 version: "1.10.4",
2651 defaultElement: "<button>",
2652 options: {
2653 disabled: null,
2654 text: true,
2655 label: null,
2656 icons: {
2657 primary: null,
2658 secondary: null
2659 }
2660 },
2661 _create: function() {
2662 this.element.closest( "form" )
2663 .unbind( "reset" + this.eventNamespace )
2664 .bind( "reset" + this.eventNamespace, formResetHandler );
2665
2666 if ( typeof this.options.disabled !== "boolean" ) {
2667 this.options.disabled = !!this.element.prop( "disabled" );
2668 } else {
2669 this.element.prop( "disabled", this.options.disabled );
2670 }
2671
2672 this._determineButtonType();
2673 this.hasTitle = !!this.buttonElement.attr( "title" );
2674
2675 var that = this,
2676 options = this.options,
2677 toggleButton = this.type === "checkbox" || this.type === "radio",
2678 activeClass = !toggleButton ? "ui-state-active" : "";
2679
2680 if ( options.label === null ) {
2681 options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html());
2682 }
2683
2684 this._hoverable( this.buttonElement );
2685
2686 this.buttonElement
2687 .addClass( baseClasses )
2688 .attr( "role", "button" )
2689 .bind( "mouseenter" + this.eventNamespace, function() {
2690 if ( options.disabled ) {
2691 return;
2692 }
2693 if ( this === lastActive ) {
2694 $( this ).addClass( "ui-state-active" );
2695 }
2696 })
2697 .bind( "mouseleave" + this.eventNamespace, function() {
2698 if ( options.disabled ) {
2699 return;
2700 }
2701 $( this ).removeClass( activeClass );
2702 })
2703 .bind( "click" + this.eventNamespace, function( event ) {
2704 if ( options.disabled ) {
2705 event.preventDefault();
2706 event.stopImmediatePropagation();
2707 }
2708 });
2709
2710 // Can't use _focusable() because the element that receives focus
2711 // and the element that gets the ui-state-focus class are different
2712 this._on({
2713 focus: function() {
2714 this.buttonElement.addClass( "ui-state-focus" );
2715 },
2716 blur: function() {
2717 this.buttonElement.removeClass( "ui-state-focus" );
2718 }
2719 });
2720
2721 if ( toggleButton ) {
2722 this.element.bind( "change" + this.eventNamespace, function() {
2723 that.refresh();
2724 });
2725 }
2726
2727 if ( this.type === "checkbox" ) {
2728 this.buttonElement.bind( "click" + this.eventNamespace, function() {
2729 if ( options.disabled ) {
2730 return false;
2731 }
2732 });
2733 } else if ( this.type === "radio" ) {
2734 this.buttonElement.bind( "click" + this.eventNamespace, function() {
2735 if ( options.disabled ) {
2736 return false;
2737 }
2738 $( this ).addClass( "ui-state-active" );
2739 that.buttonElement.attr( "aria-pressed", "true" );
2740
2741 var radio = that.element[ 0 ];
2742 radioGroup( radio )
2743 .not( radio )
2744 .map(function() {
2745 return $( this ).button( "widget" )[ 0 ];
2746 })
2747 .removeClass( "ui-state-active" )
2748 .attr( "aria-pressed", "false" );
2749 });
2750 } else {
2751 this.buttonElement
2752 .bind( "mousedown" + this.eventNamespace, function() {
2753 if ( options.disabled ) {
2754 return false;
2755 }
2756 $( this ).addClass( "ui-state-active" );
2757 lastActive = this;
2758 that.document.one( "mouseup", function() {
2759 lastActive = null;
2760 });
2761 })
2762 .bind( "mouseup" + this.eventNamespace, function() {
2763 if ( options.disabled ) {
2764 return false;
2765 }
2766 $( this ).removeClass( "ui-state-active" );
2767 })
2768 .bind( "keydown" + this.eventNamespace, function(event) {
2769 if ( options.disabled ) {
2770 return false;
2771 }
2772 if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) {
2773 $( this ).addClass( "ui-state-active" );
2774 }
2775 })
2776 // see #8559, we bind to blur here in case the button element loses
2777 // focus between keydown and keyup, it would be left in an "active" state
2778 .bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() {
2779 $( this ).removeClass( "ui-state-active" );
2780 });
2781
2782 if ( this.buttonElement.is("a") ) {
2783 this.buttonElement.keyup(function(event) {
2784 if ( event.keyCode === $.ui.keyCode.SPACE ) {
2785 // TODO pass through original event correctly (just as 2nd argument doesn't work)
2786 $( this ).click();
2787 }
2788 });
2789 }
2790 }
2791
2792 // TODO: pull out $.Widget's handling for the disabled option into
2793 // $.Widget.prototype._setOptionDisabled so it's easy to proxy and can
2794 // be overridden by individual plugins
2795 this._setOption( "disabled", options.disabled );
2796 this._resetButton();
2797 },
2798
2799 _determineButtonType: function() {
2800 var ancestor, labelSelector, checked;
2801
2802 if ( this.element.is("[type=checkbox]") ) {
2803 this.type = "checkbox";
2804 } else if ( this.element.is("[type=radio]") ) {
2805 this.type = "radio";
2806 } else if ( this.element.is("input") ) {
2807 this.type = "input";
2808 } else {
2809 this.type = "button";
2810 }
2811
2812 if ( this.type === "checkbox" || this.type === "radio" ) {
2813 // we don't search against the document in case the element
2814 // is disconnected from the DOM
2815 ancestor = this.element.parents().last();
2816 labelSelector = "label[for='" + this.element.attr("id") + "']";
2817 this.buttonElement = ancestor.find( labelSelector );
2818 if ( !this.buttonElement.length ) {
2819 ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
2820 this.buttonElement = ancestor.filter( labelSelector );
2821 if ( !this.buttonElement.length ) {
2822 this.buttonElement = ancestor.find( labelSelector );
2823 }
2824 }
2825 this.element.addClass( "ui-helper-hidden-accessible" );
2826
2827 checked = this.element.is( ":checked" );
2828 if ( checked ) {
2829 this.buttonElement.addClass( "ui-state-active" );
2830 }
2831 this.buttonElement.prop( "aria-pressed", checked );
2832 } else {
2833 this.buttonElement = this.element;
2834 }
2835 },
2836
2837 widget: function() {
2838 return this.buttonElement;
2839 },
2840
2841 _destroy: function() {
2842 this.element
2843 .removeClass( "ui-helper-hidden-accessible" );
2844 this.buttonElement
2845 .removeClass( baseClasses + " ui-state-active " + typeClasses )
2846 .removeAttr( "role" )
2847 .removeAttr( "aria-pressed" )
2848 .html( this.buttonElement.find(".ui-button-text").html() );
2849
2850 if ( !this.hasTitle ) {
2851 this.buttonElement.removeAttr( "title" );
2852 }
2853 },
2854
2855 _setOption: function( key, value ) {
2856 this._super( key, value );
2857 if ( key === "disabled" ) {
2858 this.element.prop( "disabled", !!value );
2859 if ( value ) {
2860 this.buttonElement.removeClass( "ui-state-focus" );
2861 }
2862 return;
2863 }
2864 this._resetButton();
2865 },
2866
2867 refresh: function() {
2868 //See #8237 & #8828
2869 var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" );
2870
2871 if ( isDisabled !== this.options.disabled ) {
2872 this._setOption( "disabled", isDisabled );
2873 }
2874 if ( this.type === "radio" ) {
2875 radioGroup( this.element[0] ).each(function() {
2876 if ( $( this ).is( ":checked" ) ) {
2877 $( this ).button( "widget" )
2878 .addClass( "ui-state-active" )
2879 .attr( "aria-pressed", "true" );
2880 } else {
2881 $( this ).button( "widget" )
2882 .removeClass( "ui-state-active" )
2883 .attr( "aria-pressed", "false" );
2884 }
2885 });
2886 } else if ( this.type === "checkbox" ) {
2887 if ( this.element.is( ":checked" ) ) {
2888 this.buttonElement
2889 .addClass( "ui-state-active" )
2890 .attr( "aria-pressed", "true" );
2891 } else {
2892 this.buttonElement
2893 .removeClass( "ui-state-active" )
2894 .attr( "aria-pressed", "false" );
2895 }
2896 }
2897 },
2898
2899 _resetButton: function() {
2900 if ( this.type === "input" ) {
2901 if ( this.options.label ) {
2902 this.element.val( this.options.label );
2903 }
2904 return;
2905 }
2906 var buttonElement = this.buttonElement.removeClass( typeClasses ),
2907 buttonText = $( "<span></span>", this.document[0] )
2908 .addClass( "ui-button-text" )
2909 .html( this.options.label )
2910 .appendTo( buttonElement.empty() )
2911 .text(),
2912 icons = this.options.icons,
2913 multipleIcons = icons.primary && icons.secondary,
2914 buttonClasses = [];
2915
2916 if ( icons.primary || icons.secondary ) {
2917 if ( this.options.text ) {
2918 buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
2919 }
2920
2921 if ( icons.primary ) {
2922 buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
2923 }
2924
2925 if ( icons.secondary ) {
2926 buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
2927 }
2928
2929 if ( !this.options.text ) {
2930 buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );
2931
2932 if ( !this.hasTitle ) {
2933 buttonElement.attr( "title", $.trim( buttonText ) );
2934 }
2935 }
2936 } else {
2937 buttonClasses.push( "ui-button-text-only" );
2938 }
2939 buttonElement.addClass( buttonClasses.join( " " ) );
2940 }
2941 });
2942
2943 $.widget( "ui.buttonset", {
2944 version: "1.10.4",
2945 options: {
2946 items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"
2947 },
2948
2949 _create: function() {
2950 this.element.addClass( "ui-buttonset" );
2951 },
2952
2953 _init: function() {
2954 this.refresh();
2955 },
2956
2957 _setOption: function( key, value ) {
2958 if ( key === "disabled" ) {
2959 this.buttons.button( "option", key, value );
2960 }
2961
2962 this._super( key, value );
2963 },
2964
2965 refresh: function() {
2966 var rtl = this.element.css( "direction" ) === "rtl";
2967
2968 this.buttons = this.element.find( this.options.items )
2969 .filter( ":ui-button" )
2970 .button( "refresh" )
2971 .end()
2972 .not( ":ui-button" )
2973 .button()
2974 .end()
2975 .map(function() {
2976 return $( this ).button( "widget" )[ 0 ];
2977 })
2978 .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
2979 .filter( ":first" )
2980 .addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
2981 .end()
2982 .filter( ":last" )
2983 .addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
2984 .end()
2985 .end();
2986 },
2987
2988 _destroy: function() {
2989 this.element.removeClass( "ui-buttonset" );
2990 this.buttons
2991 .map(function() {
2992 return $( this ).button( "widget" )[ 0 ];
2993 })
2994 .removeClass( "ui-corner-left ui-corner-right" )
2995 .end()
2996 .button( "destroy" );
2997 }
2998 });
2999
3000 }( jQuery ) );
3001 (function( $, undefined ) {
3002
3003 $.extend($.ui, { datepicker: { version: "1.10.4" } });
3004
3005 var PROP_NAME = "datepicker",
3006 instActive;
3007
3008 /* Date picker manager.
3009 Use the singleton instance of this class, $.datepicker, to interact with the date picker.
3010 Settings for (groups of) date pickers are maintained in an instance object,
3011 allowing multiple different settings on the same page. */
3012
3013 function Datepicker() {
3014 this._curInst = null; // The current instance in use
3015 this._keyEvent = false; // If the last event was a key event
3016 this._disabledInputs = []; // List of date picker inputs that have been disabled
3017 this._datepickerShowing = false; // True if the popup picker is showing , false if not
3018 this._inDialog = false; // True if showing within a "dialog", false if not
3019 this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
3020 this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
3021 this._appendClass = "ui-datepicker-append"; // The name of the append marker class
3022 this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
3023 this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
3024 this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
3025 this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
3026 this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
3027 this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
3028 this.regional = []; // Available regional settings, indexed by language code
3029 this.regional[""] = { // Default regional settings
3030 closeText: "Done", // Display text for close link
3031 prevText: "Prev", // Display text for previous month link
3032 nextText: "Next", // Display text for next month link
3033 currentText: "Today", // Display text for current month link
3034 monthNames: ["January","February","March","April","May","June",
3035 "July","August","September","October","November","December"], // Names of months for drop-down and formatting
3036 monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
3037 dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
3038 dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
3039 dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
3040 weekHeader: "Wk", // Column header for week of the year
3041 dateFormat: "mm/dd/yy", // See format options on parseDate
3042 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
3043 isRTL: false, // True if right-to-left language, false if left-to-right
3044 showMonthAfterYear: false, // True if the year select precedes month, false for month then year
3045 yearSuffix: "" // Additional text to append to the year in the month headers
3046 };
3047 this._defaults = { // Global defaults for all the date picker instances
3048 showOn: "focus", // "focus" for popup on focus,
3049 // "button" for trigger button, or "both" for either
3050 showAnim: "fadeIn", // Name of jQuery animation for popup
3051 showOptions: {}, // Options for enhanced animations
3052 defaultDate: null, // Used when field is blank: actual date,
3053 // +/-number for offset from today, null for today
3054 appendText: "", // Display text following the input box, e.g. showing the format
3055 buttonText: "...", // Text for trigger button
3056 buttonImage: "", // URL for trigger button image
3057 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
3058 hideIfNoPrevNext: false, // True to hide next/previous month links
3059 // if not applicable, false to just disable them
3060 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
3061 gotoCurrent: false, // True if today link goes back to current selection instead
3062 changeMonth: false, // True if month can be selected directly, false if only prev/next
3063 changeYear: false, // True if year can be selected directly, false if only prev/next
3064 yearRange: "c-10:c+10", // Range of years to display in drop-down,
3065 // either relative to today's year (-nn:+nn), relative to currently displayed year
3066 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
3067 showOtherMonths: false, // True to show dates in other months, false to leave blank
3068 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
3069 showWeek: false, // True to show week of the year, false to not show it
3070 calculateWeek: this.iso8601Week, // How to calculate the week of the year,
3071 // takes a Date and returns the number of the week for it
3072 shortYearCutoff: "+10", // Short year values < this are in the current century,
3073 // > this are in the previous century,
3074 // string value starting with "+" for current year + value
3075 minDate: null, // The earliest selectable date, or null for no limit
3076 maxDate: null, // The latest selectable date, or null for no limit
3077 duration: "fast", // Duration of display/closure
3078 beforeShowDay: null, // Function that takes a date and returns an array with
3079 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
3080 // [2] = cell title (optional), e.g. $.datepicker.noWeekends
3081 beforeShow: null, // Function that takes an input field and
3082 // returns a set of custom settings for the date picker
3083 onSelect: null, // Define a callback function when a date is selected
3084 onChangeMonthYear: null, // Define a callback function when the month or year is changed
3085 onClose: null, // Define a callback function when the datepicker is closed
3086 numberOfMonths: 1, // Number of months to show at a time
3087 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
3088 stepMonths: 1, // Number of months to step back/forward
3089 stepBigMonths: 12, // Number of months to step back/forward for the big links
3090 altField: "", // Selector for an alternate field to store selected dates into
3091 altFormat: "", // The date format to use for the alternate field
3092 constrainInput: true, // The input is constrained by the current date format
3093 showButtonPanel: false, // True to show button panel, false to not show it
3094 autoSize: false, // True to size the input for the date format, false to leave as is
3095 disabled: false // The initial disabled state
3096 };
3097 $.extend(this._defaults, this.regional[""]);
3098 this.dpDiv = bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
3099 }
3100
3101 $.extend(Datepicker.prototype, {
3102 /* Class name added to elements to indicate already configured with a date picker. */
3103 markerClassName: "hasDatepicker",
3104
3105 //Keep track of the maximum number of rows displayed (see #7043)
3106 maxRows: 4,
3107
3108 // TODO rename to "widget" when switching to widget factory
3109 _widgetDatepicker: function() {
3110 return this.dpDiv;
3111 },
3112
3113 /* Override the default settings for all instances of the date picker.
3114 * @param settings object - the new settings to use as defaults (anonymous object)
3115 * @return the manager object
3116 */
3117 setDefaults: function(settings) {
3118 extendRemove(this._defaults, settings || {});
3119 return this;
3120 },
3121
3122 /* Attach the date picker to a jQuery selection.
3123 * @param target element - the target input field or division or span
3124 * @param settings object - the new settings to use for this date picker instance (anonymous)
3125 */
3126 _attachDatepicker: function(target, settings) {
3127 var nodeName, inline, inst;
3128 nodeName = target.nodeName.toLowerCase();
3129 inline = (nodeName === "div" || nodeName === "span");
3130 if (!target.id) {
3131 this.uuid += 1;
3132 target.id = "dp" + this.uuid;
3133 }
3134 inst = this._newInst($(target), inline);
3135 inst.settings = $.extend({}, settings || {});
3136 if (nodeName === "input") {
3137 this._connectDatepicker(target, inst);
3138 } else if (inline) {
3139 this._inlineDatepicker(target, inst);
3140 }
3141 },
3142
3143 /* Create a new instance object. */
3144 _newInst: function(target, inline) {
3145 var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
3146 return {id: id, input: target, // associated target
3147 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
3148 drawMonth: 0, drawYear: 0, // month being drawn
3149 inline: inline, // is datepicker inline or not
3150 dpDiv: (!inline ? this.dpDiv : // presentation div
3151 bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
3152 },
3153
3154 /* Attach the date picker to an input field. */
3155 _connectDatepicker: function(target, inst) {
3156 var input = $(target);
3157 inst.append = $([]);
3158 inst.trigger = $([]);
3159 if (input.hasClass(this.markerClassName)) {
3160 return;
3161 }
3162 this._attachments(input, inst);
3163 input.addClass(this.markerClassName).keydown(this._doKeyDown).
3164 keypress(this._doKeyPress).keyup(this._doKeyUp);
3165 this._autoSize(inst);
3166 $.data(target, PROP_NAME, inst);
3167 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
3168 if( inst.settings.disabled ) {
3169 this._disableDatepicker( target );
3170 }
3171 },
3172
3173 /* Make attachments based on settings. */
3174 _attachments: function(input, inst) {
3175 var showOn, buttonText, buttonImage,
3176 appendText = this._get(inst, "appendText"),
3177 isRTL = this._get(inst, "isRTL");
3178
3179 if (inst.append) {
3180 inst.append.remove();
3181 }
3182 if (appendText) {
3183 inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
3184 input[isRTL ? "before" : "after"](inst.append);
3185 }
3186
3187 input.unbind("focus", this._showDatepicker);
3188
3189 if (inst.trigger) {
3190 inst.trigger.remove();
3191 }
3192
3193 showOn = this._get(inst, "showOn");
3194 if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
3195 input.focus(this._showDatepicker);
3196 }
3197 if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
3198 buttonText = this._get(inst, "buttonText");
3199 buttonImage = this._get(inst, "buttonImage");
3200 inst.trigger = $(this._get(inst, "buttonImageOnly") ?
3201 $("<img/>").addClass(this._triggerClass).
3202 attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
3203 $("<button type='button'></button>").addClass(this._triggerClass).
3204 html(!buttonImage ? buttonText : $("<img/>").attr(
3205 { src:buttonImage, alt:buttonText, title:buttonText })));
3206 input[isRTL ? "before" : "after"](inst.trigger);
3207 inst.trigger.click(function() {
3208 if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
3209 $.datepicker._hideDatepicker();
3210 } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
3211 $.datepicker._hideDatepicker();
3212 $.datepicker._showDatepicker(input[0]);
3213 } else {
3214 $.datepicker._showDatepicker(input[0]);
3215 }
3216 return false;
3217 });
3218 }
3219 },
3220
3221 /* Apply the maximum length for the date format. */
3222 _autoSize: function(inst) {
3223 if (this._get(inst, "autoSize") && !inst.inline) {
3224 var findMax, max, maxI, i,
3225 date = new Date(2009, 12 - 1, 20), // Ensure double digits
3226 dateFormat = this._get(inst, "dateFormat");
3227
3228 if (dateFormat.match(/[DM]/)) {
3229 findMax = function(names) {
3230 max = 0;
3231 maxI = 0;
3232 for (i = 0; i < names.length; i++) {
3233 if (names[i].length > max) {
3234 max = names[i].length;
3235 maxI = i;
3236 }
3237 }
3238 return maxI;
3239 };
3240 date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
3241 "monthNames" : "monthNamesShort"))));
3242 date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
3243 "dayNames" : "dayNamesShort"))) + 20 - date.getDay());
3244 }
3245 inst.input.attr("size", this._formatDate(inst, date).length);
3246 }
3247 },
3248
3249 /* Attach an inline date picker to a div. */
3250 _inlineDatepicker: function(target, inst) {
3251 var divSpan = $(target);
3252 if (divSpan.hasClass(this.markerClassName)) {
3253 return;
3254 }
3255 divSpan.addClass(this.markerClassName).append(inst.dpDiv);
3256 $.data(target, PROP_NAME, inst);
3257 this._setDate(inst, this._getDefaultDate(inst), true);
3258 this._updateDatepicker(inst);
3259 this._updateAlternate(inst);
3260 //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
3261 if( inst.settings.disabled ) {
3262 this._disableDatepicker( target );
3263 }
3264 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
3265 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
3266 inst.dpDiv.css( "display", "block" );
3267 },
3268
3269 /* Pop-up the date picker in a "dialog" box.
3270 * @param input element - ignored
3271 * @param date string or Date - the initial date to display
3272 * @param onSelect function - the function to call when a date is selected
3273 * @param settings object - update the dialog date picker instance's settings (anonymous object)
3274 * @param pos int[2] - coordinates for the dialog's position within the screen or
3275 * event - with x/y coordinates or
3276 * leave empty for default (screen centre)
3277 * @return the manager object
3278 */
3279 _dialogDatepicker: function(input, date, onSelect, settings, pos) {
3280 var id, browserWidth, browserHeight, scrollX, scrollY,
3281 inst = this._dialogInst; // internal instance
3282
3283 if (!inst) {
3284 this.uuid += 1;
3285 id = "dp" + this.uuid;
3286 this._dialogInput = $("<input type='text' id='" + id +
3287 "' style='position: absolute; top: -100px; width: 0px;'/>");
3288 this._dialogInput.keydown(this._doKeyDown);
3289 $("body").append(this._dialogInput);
3290 inst = this._dialogInst = this._newInst(this._dialogInput, false);
3291 inst.settings = {};
3292 $.data(this._dialogInput[0], PROP_NAME, inst);
3293 }
3294 extendRemove(inst.settings, settings || {});
3295 date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
3296 this._dialogInput.val(date);
3297
3298 this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
3299 if (!this._pos) {
3300 browserWidth = document.documentElement.clientWidth;
3301 browserHeight = document.documentElement.clientHeight;
3302 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
3303 scrollY = document.documentElement.scrollTop || document.body.scrollTop;
3304 this._pos = // should use actual width/height below
3305 [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
3306 }
3307
3308 // move input on screen for focus, but hidden behind dialog
3309 this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
3310 inst.settings.onSelect = onSelect;
3311 this._inDialog = true;
3312 this.dpDiv.addClass(this._dialogClass);
3313 this._showDatepicker(this._dialogInput[0]);
3314 if ($.blockUI) {
3315 $.blockUI(this.dpDiv);
3316 }
3317 $.data(this._dialogInput[0], PROP_NAME, inst);
3318 return this;
3319 },
3320
3321 /* Detach a datepicker from its control.
3322 * @param target element - the target input field or division or span
3323 */
3324 _destroyDatepicker: function(target) {
3325 var nodeName,
3326 $target = $(target),
3327 inst = $.data(target, PROP_NAME);
3328
3329 if (!$target.hasClass(this.markerClassName)) {
3330 return;
3331 }
3332
3333 nodeName = target.nodeName.toLowerCase();
3334 $.removeData(target, PROP_NAME);
3335 if (nodeName === "input") {
3336 inst.append.remove();
3337 inst.trigger.remove();
3338 $target.removeClass(this.markerClassName).
3339 unbind("focus", this._showDatepicker).
3340 unbind("keydown", this._doKeyDown).
3341 unbind("keypress", this._doKeyPress).
3342 unbind("keyup", this._doKeyUp);
3343 } else if (nodeName === "div" || nodeName === "span") {
3344 $target.removeClass(this.markerClassName).empty();
3345 }
3346 },
3347
3348 /* Enable the date picker to a jQuery selection.
3349 * @param target element - the target input field or division or span
3350 */
3351 _enableDatepicker: function(target) {
3352 var nodeName, inline,
3353 $target = $(target),
3354 inst = $.data(target, PROP_NAME);
3355
3356 if (!$target.hasClass(this.markerClassName)) {
3357 return;
3358 }
3359
3360 nodeName = target.nodeName.toLowerCase();
3361 if (nodeName === "input") {
3362 target.disabled = false;
3363 inst.trigger.filter("button").
3364 each(function() { this.disabled = false; }).end().
3365 filter("img").css({opacity: "1.0", cursor: ""});
3366 } else if (nodeName === "div" || nodeName === "span") {
3367 inline = $target.children("." + this._inlineClass);
3368 inline.children().removeClass("ui-state-disabled");
3369 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
3370 prop("disabled", false);
3371 }
3372 this._disabledInputs = $.map(this._disabledInputs,
3373 function(value) { return (value === target ? null : value); }); // delete entry
3374 },
3375
3376 /* Disable the date picker to a jQuery selection.
3377 * @param target element - the target input field or division or span
3378 */
3379 _disableDatepicker: function(target) {
3380 var nodeName, inline,
3381 $target = $(target),
3382 inst = $.data(target, PROP_NAME);
3383
3384 if (!$target.hasClass(this.markerClassName)) {
3385 return;
3386 }
3387
3388 nodeName = target.nodeName.toLowerCase();
3389 if (nodeName === "input") {
3390 target.disabled = true;
3391 inst.trigger.filter("button").
3392 each(function() { this.disabled = true; }).end().
3393 filter("img").css({opacity: "0.5", cursor: "default"});
3394 } else if (nodeName === "div" || nodeName === "span") {
3395 inline = $target.children("." + this._inlineClass);
3396 inline.children().addClass("ui-state-disabled");
3397 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
3398 prop("disabled", true);
3399 }
3400 this._disabledInputs = $.map(this._disabledInputs,
3401 function(value) { return (value === target ? null : value); }); // delete entry
3402 this._disabledInputs[this._disabledInputs.length] = target;
3403 },
3404
3405 /* Is the first field in a jQuery collection disabled as a datepicker?
3406 * @param target element - the target input field or division or span
3407 * @return boolean - true if disabled, false if enabled
3408 */
3409 _isDisabledDatepicker: function(target) {
3410 if (!target) {
3411 return false;
3412 }
3413 for (var i = 0; i < this._disabledInputs.length; i++) {
3414 if (this._disabledInputs[i] === target) {
3415 return true;
3416 }
3417 }
3418 return false;
3419 },
3420
3421 /* Retrieve the instance data for the target control.
3422 * @param target element - the target input field or division or span
3423 * @return object - the associated instance data
3424 * @throws error if a jQuery problem getting data
3425 */
3426 _getInst: function(target) {
3427 try {
3428 return $.data(target, PROP_NAME);
3429 }
3430 catch (err) {
3431 throw "Missing instance data for this datepicker";
3432 }
3433 },
3434
3435 /* Update or retrieve the settings for a date picker attached to an input field or division.
3436 * @param target element - the target input field or division or span
3437 * @param name object - the new settings to update or
3438 * string - the name of the setting to change or retrieve,
3439 * when retrieving also "all" for all instance settings or
3440 * "defaults" for all global defaults
3441 * @param value any - the new value for the setting
3442 * (omit if above is an object or to retrieve a value)
3443 */
3444 _optionDatepicker: function(target, name, value) {
3445 var settings, date, minDate, maxDate,
3446 inst = this._getInst(target);
3447
3448 if (arguments.length === 2 && typeof name === "string") {
3449 return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
3450 (inst ? (name === "all" ? $.extend({}, inst.settings) :
3451 this._get(inst, name)) : null));
3452 }
3453
3454 settings = name || {};
3455 if (typeof name === "string") {
3456 settings = {};
3457 settings[name] = value;
3458 }
3459
3460 if (inst) {
3461 if (this._curInst === inst) {
3462 this._hideDatepicker();
3463 }
3464
3465 date = this._getDateDatepicker(target, true);
3466 minDate = this._getMinMaxDate(inst, "min");
3467 maxDate = this._getMinMaxDate(inst, "max");
3468 extendRemove(inst.settings, settings);
3469 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
3470 if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
3471 inst.settings.minDate = this._formatDate(inst, minDate);
3472 }
3473 if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
3474 inst.settings.maxDate = this._formatDate(inst, maxDate);
3475 }
3476 if ( "disabled" in settings ) {
3477 if ( settings.disabled ) {
3478 this._disableDatepicker(target);
3479 } else {
3480 this._enableDatepicker(target);
3481 }
3482 }
3483 this._attachments($(target), inst);
3484 this._autoSize(inst);
3485 this._setDate(inst, date);
3486 this._updateAlternate(inst);
3487 this._updateDatepicker(inst);
3488 }
3489 },
3490
3491 // change method deprecated
3492 _changeDatepicker: function(target, name, value) {
3493 this._optionDatepicker(target, name, value);
3494 },
3495
3496 /* Redraw the date picker attached to an input field or division.
3497 * @param target element - the target input field or division or span
3498 */
3499 _refreshDatepicker: function(target) {
3500 var inst = this._getInst(target);
3501 if (inst) {
3502 this._updateDatepicker(inst);
3503 }
3504 },
3505
3506 /* Set the dates for a jQuery selection.
3507 * @param target element - the target input field or division or span
3508 * @param date Date - the new date
3509 */
3510 _setDateDatepicker: function(target, date) {
3511 var inst = this._getInst(target);
3512 if (inst) {
3513 this._setDate(inst, date);
3514 this._updateDatepicker(inst);
3515 this._updateAlternate(inst);
3516 }
3517 },
3518
3519 /* Get the date(s) for the first entry in a jQuery selection.
3520 * @param target element - the target input field or division or span
3521 * @param noDefault boolean - true if no default date is to be used
3522 * @return Date - the current date
3523 */
3524 _getDateDatepicker: function(target, noDefault) {
3525 var inst = this._getInst(target);
3526 if (inst && !inst.inline) {
3527 this._setDateFromField(inst, noDefault);
3528 }
3529 return (inst ? this._getDate(inst) : null);
3530 },
3531
3532 /* Handle keystrokes. */
3533 _doKeyDown: function(event) {
3534 var onSelect, dateStr, sel,
3535 inst = $.datepicker._getInst(event.target),
3536 handled = true,
3537 isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
3538
3539 inst._keyEvent = true;
3540 if ($.datepicker._datepickerShowing) {
3541 switch (event.keyCode) {
3542 case 9: $.datepicker._hideDatepicker();
3543 handled = false;
3544 break; // hide on tab out
3545 case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
3546 $.datepicker._currentClass + ")", inst.dpDiv);
3547 if (sel[0]) {
3548 $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
3549 }
3550
3551 onSelect = $.datepicker._get(inst, "onSelect");
3552 if (onSelect) {
3553 dateStr = $.datepicker._formatDate(inst);
3554
3555 // trigger custom callback
3556 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
3557 } else {
3558 $.datepicker._hideDatepicker();
3559 }
3560
3561 return false; // don't submit the form
3562 case 27: $.datepicker._hideDatepicker();
3563 break; // hide on escape
3564 case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
3565 -$.datepicker._get(inst, "stepBigMonths") :
3566 -$.datepicker._get(inst, "stepMonths")), "M");
3567 break; // previous month/year on page up/+ ctrl
3568 case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
3569 +$.datepicker._get(inst, "stepBigMonths") :
3570 +$.datepicker._get(inst, "stepMonths")), "M");
3571 break; // next month/year on page down/+ ctrl
3572 case 35: if (event.ctrlKey || event.metaKey) {
3573 $.datepicker._clearDate(event.target);
3574 }
3575 handled = event.ctrlKey || event.metaKey;
3576 break; // clear on ctrl or command +end
3577 case 36: if (event.ctrlKey || event.metaKey) {
3578 $.datepicker._gotoToday(event.target);
3579 }
3580 handled = event.ctrlKey || event.metaKey;
3581 break; // current on ctrl or command +home
3582 case 37: if (event.ctrlKey || event.metaKey) {
3583 $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
3584 }
3585 handled = event.ctrlKey || event.metaKey;
3586 // -1 day on ctrl or command +left
3587 if (event.originalEvent.altKey) {
3588 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
3589 -$.datepicker._get(inst, "stepBigMonths") :
3590 -$.datepicker._get(inst, "stepMonths")), "M");
3591 }
3592 // next month/year on alt +left on Mac
3593 break;
3594 case 38: if (event.ctrlKey || event.metaKey) {
3595 $.datepicker._adjustDate(event.target, -7, "D");
3596 }
3597 handled = event.ctrlKey || event.metaKey;
3598 break; // -1 week on ctrl or command +up
3599 case 39: if (event.ctrlKey || event.metaKey) {
3600 $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
3601 }
3602 handled = event.ctrlKey || event.metaKey;
3603 // +1 day on ctrl or command +right
3604 if (event.originalEvent.altKey) {
3605 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
3606 +$.datepicker._get(inst, "stepBigMonths") :
3607 +$.datepicker._get(inst, "stepMonths")), "M");
3608 }
3609 // next month/year on alt +right
3610 break;
3611 case 40: if (event.ctrlKey || event.metaKey) {
3612 $.datepicker._adjustDate(event.target, +7, "D");
3613 }
3614 handled = event.ctrlKey || event.metaKey;
3615 break; // +1 week on ctrl or command +down
3616 default: handled = false;
3617 }
3618 } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
3619 $.datepicker._showDatepicker(this);
3620 } else {
3621 handled = false;
3622 }
3623
3624 if (handled) {
3625 event.preventDefault();
3626 event.stopPropagation();
3627 }
3628 },
3629
3630 /* Filter entered characters - based on date format. */
3631 _doKeyPress: function(event) {
3632 var chars, chr,
3633 inst = $.datepicker._getInst(event.target);
3634
3635 if ($.datepicker._get(inst, "constrainInput")) {
3636 chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
3637 chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
3638 return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
3639 }
3640 },
3641
3642 /* Synchronise manual entry and field/alternate field. */
3643 _doKeyUp: function(event) {
3644 var date,
3645 inst = $.datepicker._getInst(event.target);
3646
3647 if (inst.input.val() !== inst.lastVal) {
3648 try {
3649 date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
3650 (inst.input ? inst.input.val() : null),
3651 $.datepicker._getFormatConfig(inst));
3652
3653 if (date) { // only if valid
3654 $.datepicker._setDateFromField(inst);
3655 $.datepicker._updateAlternate(inst);
3656 $.datepicker._updateDatepicker(inst);
3657 }
3658 }
3659 catch (err) {
3660 }
3661 }
3662 return true;
3663 },
3664
3665 /* Pop-up the date picker for a given input field.
3666 * If false returned from beforeShow event handler do not show.
3667 * @param input element - the input field attached to the date picker or
3668 * event - if triggered by focus
3669 */
3670 _showDatepicker: function(input) {
3671 input = input.target || input;
3672 if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
3673 input = $("input", input.parentNode)[0];
3674 }
3675
3676 if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
3677 return;
3678 }
3679
3680 var inst, beforeShow, beforeShowSettings, isFixed,
3681 offset, showAnim, duration;
3682
3683 inst = $.datepicker._getInst(input);
3684 if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
3685 $.datepicker._curInst.dpDiv.stop(true, true);
3686 if ( inst && $.datepicker._datepickerShowing ) {
3687 $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
3688 }
3689 }
3690
3691 beforeShow = $.datepicker._get(inst, "beforeShow");
3692 beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
3693 if(beforeShowSettings === false){
3694 return;
3695 }
3696 extendRemove(inst.settings, beforeShowSettings);
3697
3698 inst.lastVal = null;
3699 $.datepicker._lastInput = input;
3700 $.datepicker._setDateFromField(inst);
3701
3702 if ($.datepicker._inDialog) { // hide cursor
3703 input.value = "";
3704 }
3705 if (!$.datepicker._pos) { // position below input
3706 $.datepicker._pos = $.datepicker._findPos(input);
3707 $.datepicker._pos[1] += input.offsetHeight; // add the height
3708 }
3709
3710 isFixed = false;
3711 $(input).parents().each(function() {
3712 isFixed |= $(this).css("position") === "fixed";
3713 return !isFixed;
3714 });
3715
3716 offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
3717 $.datepicker._pos = null;
3718 //to avoid flashes on Firefox
3719 inst.dpDiv.empty();
3720 // determine sizing offscreen
3721 inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
3722 $.datepicker._updateDatepicker(inst);
3723 // fix width for dynamic number of date pickers
3724 // and adjust position before showing
3725 offset = $.datepicker._checkOffset(inst, offset, isFixed);
3726 inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
3727 "static" : (isFixed ? "fixed" : "absolute")), display: "none",
3728 left: offset.left + "px", top: offset.top + "px"});
3729
3730 if (!inst.inline) {
3731 showAnim = $.datepicker._get(inst, "showAnim");
3732 duration = $.datepicker._get(inst, "duration");
3733 inst.dpDiv.zIndex($(input).zIndex()+1);
3734 $.datepicker._datepickerShowing = true;
3735
3736 if ( $.effects && $.effects.effect[ showAnim ] ) {
3737 inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
3738 } else {
3739 inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
3740 }
3741
3742 if ( $.datepicker._shouldFocusInput( inst ) ) {
3743 inst.input.focus();
3744 }
3745
3746 $.datepicker._curInst = inst;
3747 }
3748 },
3749
3750 /* Generate the date picker content. */
3751 _updateDatepicker: function(inst) {
3752 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
3753 instActive = inst; // for delegate hover events
3754 inst.dpDiv.empty().append(this._generateHTML(inst));
3755 this._attachHandlers(inst);
3756 inst.dpDiv.find("." + this._dayOverClass + " a").mouseover();
3757
3758 var origyearshtml,
3759 numMonths = this._getNumberOfMonths(inst),
3760 cols = numMonths[1],
3761 width = 17;
3762
3763 inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
3764 if (cols > 1) {
3765 inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
3766 }
3767 inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
3768 "Class"]("ui-datepicker-multi");
3769 inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
3770 "Class"]("ui-datepicker-rtl");
3771
3772 if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
3773 inst.input.focus();
3774 }
3775
3776 // deffered render of the years select (to avoid flashes on Firefox)
3777 if( inst.yearshtml ){
3778 origyearshtml = inst.yearshtml;
3779 setTimeout(function(){
3780 //assure that inst.yearshtml didn't change.
3781 if( origyearshtml === inst.yearshtml && inst.yearshtml ){
3782 inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
3783 }
3784 origyearshtml = inst.yearshtml = null;
3785 }, 0);
3786 }
3787 },
3788
3789 // #6694 - don't focus the input if it's already focused
3790 // this breaks the change event in IE
3791 // Support: IE and jQuery <1.9
3792 _shouldFocusInput: function( inst ) {
3793 return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
3794 },
3795
3796 /* Check positioning to remain on screen. */
3797 _checkOffset: function(inst, offset, isFixed) {
3798 var dpWidth = inst.dpDiv.outerWidth(),
3799 dpHeight = inst.dpDiv.outerHeight(),
3800 inputWidth = inst.input ? inst.input.outerWidth() : 0,
3801 inputHeight = inst.input ? inst.input.outerHeight() : 0,
3802 viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
3803 viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
3804
3805 offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
3806 offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
3807 offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
3808
3809 // now check if datepicker is showing outside window viewport - move to a better place if so.
3810 offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
3811 Math.abs(offset.left + dpWidth - viewWidth) : 0);
3812 offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
3813 Math.abs(dpHeight + inputHeight) : 0);
3814
3815 return offset;
3816 },
3817
3818 /* Find an object's position on the screen. */
3819 _findPos: function(obj) {
3820 var position,
3821 inst = this._getInst(obj),
3822 isRTL = this._get(inst, "isRTL");
3823
3824 while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
3825 obj = obj[isRTL ? "previousSibling" : "nextSibling"];
3826 }
3827
3828 position = $(obj).offset();
3829 return [position.left, position.top];
3830 },
3831
3832 /* Hide the date picker from view.
3833 * @param input element - the input field attached to the date picker
3834 */
3835 _hideDatepicker: function(input) {
3836 var showAnim, duration, postProcess, onClose,
3837 inst = this._curInst;
3838
3839 if (!inst || (input && inst !== $.data(input, PROP_NAME))) {
3840 return;
3841 }
3842
3843 if (this._datepickerShowing) {
3844 showAnim = this._get(inst, "showAnim");
3845 duration = this._get(inst, "duration");
3846 postProcess = function() {
3847 $.datepicker._tidyDialog(inst);
3848 };
3849
3850 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
3851 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
3852 inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
3853 } else {
3854 inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
3855 (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
3856 }
3857
3858 if (!showAnim) {
3859 postProcess();
3860 }
3861 this._datepickerShowing = false;
3862
3863 onClose = this._get(inst, "onClose");
3864 if (onClose) {
3865 onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
3866 }
3867
3868 this._lastInput = null;
3869 if (this._inDialog) {
3870 this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
3871 if ($.blockUI) {
3872 $.unblockUI();
3873 $("body").append(this.dpDiv);
3874 }
3875 }
3876 this._inDialog = false;
3877 }
3878 },
3879
3880 /* Tidy up after a dialog display. */
3881 _tidyDialog: function(inst) {
3882 inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");
3883 },
3884
3885 /* Close date picker if clicked elsewhere. */
3886 _checkExternalClick: function(event) {
3887 if (!$.datepicker._curInst) {
3888 return;
3889 }
3890
3891 var $target = $(event.target),
3892 inst = $.datepicker._getInst($target[0]);
3893
3894 if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
3895 $target.parents("#" + $.datepicker._mainDivId).length === 0 &&
3896 !$target.hasClass($.datepicker.markerClassName) &&
3897 !$target.closest("." + $.datepicker._triggerClass).length &&
3898 $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
3899 ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
3900 $.datepicker._hideDatepicker();
3901 }
3902 },
3903
3904 /* Adjust one of the date sub-fields. */
3905 _adjustDate: function(id, offset, period) {
3906 var target = $(id),
3907 inst = this._getInst(target[0]);
3908
3909 if (this._isDisabledDatepicker(target[0])) {
3910 return;
3911 }
3912 this._adjustInstDate(inst, offset +
3913 (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
3914 period);
3915 this._updateDatepicker(inst);
3916 },
3917
3918 /* Action for current link. */
3919 _gotoToday: function(id) {
3920 var date,
3921 target = $(id),
3922 inst = this._getInst(target[0]);
3923
3924 if (this._get(inst, "gotoCurrent") && inst.currentDay) {
3925 inst.selectedDay = inst.currentDay;
3926 inst.drawMonth = inst.selectedMonth = inst.currentMonth;
3927 inst.drawYear = inst.selectedYear = inst.currentYear;
3928 } else {
3929 date = new Date();
3930 inst.selectedDay = date.getDate();
3931 inst.drawMonth = inst.selectedMonth = date.getMonth();
3932 inst.drawYear = inst.selectedYear = date.getFullYear();
3933 }
3934 this._notifyChange(inst);
3935 this._adjustDate(target);
3936 },
3937
3938 /* Action for selecting a new month/year. */
3939 _selectMonthYear: function(id, select, period) {
3940 var target = $(id),
3941 inst = this._getInst(target[0]);
3942
3943 inst["selected" + (period === "M" ? "Month" : "Year")] =
3944 inst["draw" + (period === "M" ? "Month" : "Year")] =
3945 parseInt(select.options[select.selectedIndex].value,10);
3946
3947 this._notifyChange(inst);
3948 this._adjustDate(target);
3949 },
3950
3951 /* Action for selecting a day. */
3952 _selectDay: function(id, month, year, td) {
3953 var inst,
3954 target = $(id);
3955
3956 if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
3957 return;
3958 }
3959
3960 inst = this._getInst(target[0]);
3961 inst.selectedDay = inst.currentDay = $("a", td).html();
3962 inst.selectedMonth = inst.currentMonth = month;
3963 inst.selectedYear = inst.currentYear = year;
3964 this._selectDate(id, this._formatDate(inst,
3965 inst.currentDay, inst.currentMonth, inst.currentYear));
3966 },
3967
3968 /* Erase the input field and hide the date picker. */
3969 _clearDate: function(id) {
3970 var target = $(id);
3971 this._selectDate(target, "");
3972 },
3973
3974 /* Update the input field with the selected date. */
3975 _selectDate: function(id, dateStr) {
3976 var onSelect,
3977 target = $(id),
3978 inst = this._getInst(target[0]);
3979
3980 dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
3981 if (inst.input) {
3982 inst.input.val(dateStr);
3983 }
3984 this._updateAlternate(inst);
3985
3986 onSelect = this._get(inst, "onSelect");
3987 if (onSelect) {
3988 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
3989 } else if (inst.input) {
3990 inst.input.trigger("change"); // fire the change event
3991 }
3992
3993 if (inst.inline){
3994 this._updateDatepicker(inst);
3995 } else {
3996 this._hideDatepicker();
3997 this._lastInput = inst.input[0];
3998 if (typeof(inst.input[0]) !== "object") {
3999 inst.input.focus(); // restore focus
4000 }
4001 this._lastInput = null;
4002 }
4003 },
4004
4005 /* Update any alternate field to synchronise with the main field. */
4006 _updateAlternate: function(inst) {
4007 var altFormat, date, dateStr,
4008 altField = this._get(inst, "altField");
4009
4010 if (altField) { // update alternate field too
4011 altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
4012 date = this._getDate(inst);
4013 dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
4014 $(altField).each(function() { $(this).val(dateStr); });
4015 }
4016 },
4017
4018 /* Set as beforeShowDay function to prevent selection of weekends.
4019 * @param date Date - the date to customise
4020 * @return [boolean, string] - is this date selectable?, what is its CSS class?
4021 */
4022 noWeekends: function(date) {
4023 var day = date.getDay();
4024 return [(day > 0 && day < 6), ""];
4025 },
4026
4027 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
4028 * @param date Date - the date to get the week for
4029 * @return number - the number of the week within the year that contains this date
4030 */
4031 iso8601Week: function(date) {
4032 var time,
4033 checkDate = new Date(date.getTime());
4034
4035 // Find Thursday of this week starting on Monday
4036 checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
4037
4038 time = checkDate.getTime();
4039 checkDate.setMonth(0); // Compare with Jan 1
4040 checkDate.setDate(1);
4041 return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
4042 },
4043
4044 /* Parse a string value into a date object.
4045 * See formatDate below for the possible formats.
4046 *
4047 * @param format string - the expected format of the date
4048 * @param value string - the date in the above format
4049 * @param settings Object - attributes include:
4050 * shortYearCutoff number - the cutoff year for determining the century (optional)
4051 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
4052 * dayNames string[7] - names of the days from Sunday (optional)
4053 * monthNamesShort string[12] - abbreviated names of the months (optional)
4054 * monthNames string[12] - names of the months (optional)
4055 * @return Date - the extracted date value or null if value is blank
4056 */
4057 parseDate: function (format, value, settings) {
4058 if (format == null || value == null) {
4059 throw "Invalid arguments";
4060 }
4061
4062 value = (typeof value === "object" ? value.toString() : value + "");
4063 if (value === "") {
4064 return null;
4065 }
4066
4067 var iFormat, dim, extra,
4068 iValue = 0,
4069 shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
4070 shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
4071 new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
4072 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
4073 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
4074 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
4075 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
4076 year = -1,
4077 month = -1,
4078 day = -1,
4079 doy = -1,
4080 literal = false,
4081 date,
4082 // Check whether a format character is doubled
4083 lookAhead = function(match) {
4084 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
4085 if (matches) {
4086 iFormat++;
4087 }
4088 return matches;
4089 },
4090 // Extract a number from the string value
4091 getNumber = function(match) {
4092 var isDoubled = lookAhead(match),
4093 size = (match === "@" ? 14 : (match === "!" ? 20 :
4094 (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
4095 digits = new RegExp("^\\d{1," + size + "}"),
4096 num = value.substring(iValue).match(digits);
4097 if (!num) {
4098 throw "Missing number at position " + iValue;
4099 }
4100 iValue += num[0].length;
4101 return parseInt(num[0], 10);
4102 },
4103 // Extract a name from the string value and convert to an index
4104 getName = function(match, shortNames, longNames) {
4105 var index = -1,
4106 names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
4107 return [ [k, v] ];
4108 }).sort(function (a, b) {
4109 return -(a[1].length - b[1].length);
4110 });
4111
4112 $.each(names, function (i, pair) {
4113 var name = pair[1];
4114 if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
4115 index = pair[0];
4116 iValue += name.length;
4117 return false;
4118 }
4119 });
4120 if (index !== -1) {
4121 return index + 1;
4122 } else {
4123 throw "Unknown name at position " + iValue;
4124 }
4125 },
4126 // Confirm that a literal character matches the string value
4127 checkLiteral = function() {
4128 if (value.charAt(iValue) !== format.charAt(iFormat)) {
4129 throw "Unexpected literal at position " + iValue;
4130 }
4131 iValue++;
4132 };
4133
4134 for (iFormat = 0; iFormat < format.length; iFormat++) {
4135 if (literal) {
4136 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
4137 literal = false;
4138 } else {
4139 checkLiteral();
4140 }
4141 } else {
4142 switch (format.charAt(iFormat)) {
4143 case "d":
4144 day = getNumber("d");
4145 break;
4146 case "D":
4147 getName("D", dayNamesShort, dayNames);
4148 break;
4149 case "o":
4150 doy = getNumber("o");
4151 break;
4152 case "m":
4153 month = getNumber("m");
4154 break;
4155 case "M":
4156 month = getName("M", monthNamesShort, monthNames);
4157 break;
4158 case "y":
4159 year = getNumber("y");
4160 break;
4161 case "@":
4162 date = new Date(getNumber("@"));
4163 year = date.getFullYear();
4164 month = date.getMonth() + 1;
4165 day = date.getDate();
4166 break;
4167 case "!":
4168 date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
4169 year = date.getFullYear();
4170 month = date.getMonth() + 1;
4171 day = date.getDate();
4172 break;
4173 case "'":
4174 if (lookAhead("'")){
4175 checkLiteral();
4176 } else {
4177 literal = true;
4178 }
4179 break;
4180 default:
4181 checkLiteral();
4182 }
4183 }
4184 }
4185
4186 if (iValue < value.length){
4187 extra = value.substr(iValue);
4188 if (!/^\s+/.test(extra)) {
4189 throw "Extra/unparsed characters found in date: " + extra;
4190 }
4191 }
4192
4193 if (year === -1) {
4194 year = new Date().getFullYear();
4195 } else if (year < 100) {
4196 year += new Date().getFullYear() - new Date().getFullYear() % 100 +
4197 (year <= shortYearCutoff ? 0 : -100);
4198 }
4199
4200 if (doy > -1) {
4201 month = 1;
4202 day = doy;
4203 do {
4204 dim = this._getDaysInMonth(year, month - 1);
4205 if (day <= dim) {
4206 break;
4207 }
4208 month++;
4209 day -= dim;
4210 } while (true);
4211 }
4212
4213 date = this._daylightSavingAdjust(new Date(year, month - 1, day));
4214 if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
4215 throw "Invalid date"; // E.g. 31/02/00
4216 }
4217 return date;
4218 },
4219
4220 /* Standard date formats. */
4221 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
4222 COOKIE: "D, dd M yy",
4223 ISO_8601: "yy-mm-dd",
4224 RFC_822: "D, d M y",
4225 RFC_850: "DD, dd-M-y",
4226 RFC_1036: "D, d M y",
4227 RFC_1123: "D, d M yy",
4228 RFC_2822: "D, d M yy",
4229 RSS: "D, d M y", // RFC 822
4230 TICKS: "!",
4231 TIMESTAMP: "@",
4232 W3C: "yy-mm-dd", // ISO 8601
4233
4234 _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
4235 Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
4236
4237 /* Format a date object into a string value.
4238 * The format can be combinations of the following:
4239 * d - day of month (no leading zero)
4240 * dd - day of month (two digit)
4241 * o - day of year (no leading zeros)
4242 * oo - day of year (three digit)
4243 * D - day name short
4244 * DD - day name long
4245 * m - month of year (no leading zero)
4246 * mm - month of year (two digit)
4247 * M - month name short
4248 * MM - month name long
4249 * y - year (two digit)
4250 * yy - year (four digit)
4251 * @ - Unix timestamp (ms since 01/01/1970)
4252 * ! - Windows ticks (100ns since 01/01/0001)
4253 * "..." - literal text
4254 * '' - single quote
4255 *
4256 * @param format string - the desired format of the date
4257 * @param date Date - the date value to format
4258 * @param settings Object - attributes include:
4259 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
4260 * dayNames string[7] - names of the days from Sunday (optional)
4261 * monthNamesShort string[12] - abbreviated names of the months (optional)
4262 * monthNames string[12] - names of the months (optional)
4263 * @return string - the date in the above format
4264 */
4265 formatDate: function (format, date, settings) {
4266 if (!date) {
4267 return "";
4268 }
4269
4270 var iFormat,
4271 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
4272 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
4273 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
4274 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
4275 // Check whether a format character is doubled
4276 lookAhead = function(match) {
4277 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
4278 if (matches) {
4279 iFormat++;
4280 }
4281 return matches;
4282 },
4283 // Format a number, with leading zero if necessary
4284 formatNumber = function(match, value, len) {
4285 var num = "" + value;
4286 if (lookAhead(match)) {
4287 while (num.length < len) {
4288 num = "0" + num;
4289 }
4290 }
4291 return num;
4292 },
4293 // Format a name, short or long as requested
4294 formatName = function(match, value, shortNames, longNames) {
4295 return (lookAhead(match) ? longNames[value] : shortNames[value]);
4296 },
4297 output = "",
4298 literal = false;
4299
4300 if (date) {
4301 for (iFormat = 0; iFormat < format.length; iFormat++) {
4302 if (literal) {
4303 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
4304 literal = false;
4305 } else {
4306 output += format.charAt(iFormat);
4307 }
4308 } else {
4309 switch (format.charAt(iFormat)) {
4310 case "d":
4311 output += formatNumber("d", date.getDate(), 2);
4312 break;
4313 case "D":
4314 output += formatName("D", date.getDay(), dayNamesShort, dayNames);
4315 break;
4316 case "o":
4317 output += formatNumber("o",
4318 Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
4319 break;
4320 case "m":
4321 output += formatNumber("m", date.getMonth() + 1, 2);
4322 break;
4323 case "M":
4324 output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
4325 break;
4326 case "y":
4327 output += (lookAhead("y") ? date.getFullYear() :
4328 (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
4329 break;
4330 case "@":
4331 output += date.getTime();
4332 break;
4333 case "!":
4334 output += date.getTime() * 10000 + this._ticksTo1970;
4335 break;
4336 case "'":
4337 if (lookAhead("'")) {
4338 output += "'";
4339 } else {
4340 literal = true;
4341 }
4342 break;
4343 default:
4344 output += format.charAt(iFormat);
4345 }
4346 }
4347 }
4348 }
4349 return output;
4350 },
4351
4352 /* Extract all possible characters from the date format. */
4353 _possibleChars: function (format) {
4354 var iFormat,
4355 chars = "",
4356 literal = false,
4357 // Check whether a format character is doubled
4358 lookAhead = function(match) {
4359 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
4360 if (matches) {
4361 iFormat++;
4362 }
4363 return matches;
4364 };
4365
4366 for (iFormat = 0; iFormat < format.length; iFormat++) {
4367 if (literal) {
4368 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
4369 literal = false;
4370 } else {
4371 chars += format.charAt(iFormat);
4372 }
4373 } else {
4374 switch (format.charAt(iFormat)) {
4375 case "d": case "m": case "y": case "@":
4376 chars += "0123456789";
4377 break;
4378 case "D": case "M":
4379 return null; // Accept anything
4380 case "'":
4381 if (lookAhead("'")) {
4382 chars += "'";
4383 } else {
4384 literal = true;
4385 }
4386 break;
4387 default:
4388 chars += format.charAt(iFormat);
4389 }
4390 }
4391 }
4392 return chars;
4393 },
4394
4395 /* Get a setting value, defaulting if necessary. */
4396 _get: function(inst, name) {
4397 return inst.settings[name] !== undefined ?
4398 inst.settings[name] : this._defaults[name];
4399 },
4400
4401 /* Parse existing date and initialise date picker. */
4402 _setDateFromField: function(inst, noDefault) {
4403 if (inst.input.val() === inst.lastVal) {
4404 return;
4405 }
4406
4407 var dateFormat = this._get(inst, "dateFormat"),
4408 dates = inst.lastVal = inst.input ? inst.input.val() : null,
4409 defaultDate = this._getDefaultDate(inst),
4410 date = defaultDate,
4411 settings = this._getFormatConfig(inst);
4412
4413 try {
4414 date = this.parseDate(dateFormat, dates, settings) || defaultDate;
4415 } catch (event) {
4416 dates = (noDefault ? "" : dates);
4417 }
4418 inst.selectedDay = date.getDate();
4419 inst.drawMonth = inst.selectedMonth = date.getMonth();
4420 inst.drawYear = inst.selectedYear = date.getFullYear();
4421 inst.currentDay = (dates ? date.getDate() : 0);
4422 inst.currentMonth = (dates ? date.getMonth() : 0);
4423 inst.currentYear = (dates ? date.getFullYear() : 0);
4424 this._adjustInstDate(inst);
4425 },
4426
4427 /* Retrieve the default date shown on opening. */
4428 _getDefaultDate: function(inst) {
4429 return this._restrictMinMax(inst,
4430 this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
4431 },
4432
4433 /* A date may be specified as an exact value or a relative one. */
4434 _determineDate: function(inst, date, defaultDate) {
4435 var offsetNumeric = function(offset) {
4436 var date = new Date();
4437 date.setDate(date.getDate() + offset);
4438 return date;
4439 },
4440 offsetString = function(offset) {
4441 try {
4442 return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
4443 offset, $.datepicker._getFormatConfig(inst));
4444 }
4445 catch (e) {
4446 // Ignore
4447 }
4448
4449 var date = (offset.toLowerCase().match(/^c/) ?
4450 $.datepicker._getDate(inst) : null) || new Date(),
4451 year = date.getFullYear(),
4452 month = date.getMonth(),
4453 day = date.getDate(),
4454 pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
4455 matches = pattern.exec(offset);
4456
4457 while (matches) {
4458 switch (matches[2] || "d") {
4459 case "d" : case "D" :
4460 day += parseInt(matches[1],10); break;
4461 case "w" : case "W" :
4462 day += parseInt(matches[1],10) * 7; break;
4463 case "m" : case "M" :
4464 month += parseInt(matches[1],10);
4465 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
4466 break;
4467 case "y": case "Y" :
4468 year += parseInt(matches[1],10);
4469 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
4470 break;
4471 }
4472 matches = pattern.exec(offset);
4473 }
4474 return new Date(year, month, day);
4475 },
4476 newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
4477 (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
4478
4479 newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
4480 if (newDate) {
4481 newDate.setHours(0);
4482 newDate.setMinutes(0);
4483 newDate.setSeconds(0);
4484 newDate.setMilliseconds(0);
4485 }
4486 return this._daylightSavingAdjust(newDate);
4487 },
4488
4489 /* Handle switch to/from daylight saving.
4490 * Hours may be non-zero on daylight saving cut-over:
4491 * > 12 when midnight changeover, but then cannot generate
4492 * midnight datetime, so jump to 1AM, otherwise reset.
4493 * @param date (Date) the date to check
4494 * @return (Date) the corrected date
4495 */
4496 _daylightSavingAdjust: function(date) {
4497 if (!date) {
4498 return null;
4499 }
4500 date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
4501 return date;
4502 },
4503
4504 /* Set the date(s) directly. */
4505 _setDate: function(inst, date, noChange) {
4506 var clear = !date,
4507 origMonth = inst.selectedMonth,
4508 origYear = inst.selectedYear,
4509 newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
4510
4511 inst.selectedDay = inst.currentDay = newDate.getDate();
4512 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
4513 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
4514 if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
4515 this._notifyChange(inst);
4516 }
4517 this._adjustInstDate(inst);
4518 if (inst.input) {
4519 inst.input.val(clear ? "" : this._formatDate(inst));
4520 }
4521 },
4522
4523 /* Retrieve the date(s) directly. */
4524 _getDate: function(inst) {
4525 var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
4526 this._daylightSavingAdjust(new Date(
4527 inst.currentYear, inst.currentMonth, inst.currentDay)));
4528 return startDate;
4529 },
4530
4531 /* Attach the onxxx handlers. These are declared statically so
4532 * they work with static code transformers like Caja.
4533 */
4534 _attachHandlers: function(inst) {
4535 var stepMonths = this._get(inst, "stepMonths"),
4536 id = "#" + inst.id.replace( /\\\\/g, "\\" );
4537 inst.dpDiv.find("[data-handler]").map(function () {
4538 var handler = {
4539 prev: function () {
4540 $.datepicker._adjustDate(id, -stepMonths, "M");
4541 },
4542 next: function () {
4543 $.datepicker._adjustDate(id, +stepMonths, "M");
4544 },
4545 hide: function () {
4546 $.datepicker._hideDatepicker();
4547 },
4548 today: function () {
4549 $.datepicker._gotoToday(id);
4550 },
4551 selectDay: function () {
4552 $.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
4553 return false;
4554 },
4555 selectMonth: function () {
4556 $.datepicker._selectMonthYear(id, this, "M");
4557 return false;
4558 },
4559 selectYear: function () {
4560 $.datepicker._selectMonthYear(id, this, "Y");
4561 return false;
4562 }
4563 };
4564 $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
4565 });
4566 },
4567
4568 /* Generate the HTML for the current state of the date picker. */
4569 _generateHTML: function(inst) {
4570 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
4571 controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
4572 monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
4573 selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
4574 cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
4575 printDate, dRow, tbody, daySettings, otherMonth, unselectable,
4576 tempDate = new Date(),
4577 today = this._daylightSavingAdjust(
4578 new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
4579 isRTL = this._get(inst, "isRTL"),
4580 showButtonPanel = this._get(inst, "showButtonPanel"),
4581 hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
4582 navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
4583 numMonths = this._getNumberOfMonths(inst),
4584 showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
4585 stepMonths = this._get(inst, "stepMonths"),
4586 isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
4587 currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
4588 new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
4589 minDate = this._getMinMaxDate(inst, "min"),
4590 maxDate = this._getMinMaxDate(inst, "max"),
4591 drawMonth = inst.drawMonth - showCurrentAtPos,
4592 drawYear = inst.drawYear;
4593
4594 if (drawMonth < 0) {
4595 drawMonth += 12;
4596 drawYear--;
4597 }
4598 if (maxDate) {
4599 maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
4600 maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
4601 maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
4602 while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
4603 drawMonth--;
4604 if (drawMonth < 0) {
4605 drawMonth = 11;
4606 drawYear--;
4607 }
4608 }
4609 }
4610 inst.drawMonth = drawMonth;
4611 inst.drawYear = drawYear;
4612
4613 prevText = this._get(inst, "prevText");
4614 prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
4615 this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
4616 this._getFormatConfig(inst)));
4617
4618 prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
4619 "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
4620 " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
4621 (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>"));
4622
4623 nextText = this._get(inst, "nextText");
4624 nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
4625 this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
4626 this._getFormatConfig(inst)));
4627
4628 next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
4629 "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
4630 " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
4631 (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>"));
4632
4633 currentText = this._get(inst, "currentText");
4634 gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
4635 currentText = (!navigationAsDateFormat ? currentText :
4636 this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
4637
4638 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'>" +
4639 this._get(inst, "closeText") + "</button>" : "");
4640
4641 buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
4642 (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'" +
4643 ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";
4644
4645 firstDay = parseInt(this._get(inst, "firstDay"),10);
4646 firstDay = (isNaN(firstDay) ? 0 : firstDay);
4647
4648 showWeek = this._get(inst, "showWeek");
4649 dayNames = this._get(inst, "dayNames");
4650 dayNamesMin = this._get(inst, "dayNamesMin");
4651 monthNames = this._get(inst, "monthNames");
4652 monthNamesShort = this._get(inst, "monthNamesShort");
4653 beforeShowDay = this._get(inst, "beforeShowDay");
4654 showOtherMonths = this._get(inst, "showOtherMonths");
4655 selectOtherMonths = this._get(inst, "selectOtherMonths");
4656 defaultDate = this._getDefaultDate(inst);
4657 html = "";
4658 dow;
4659 for (row = 0; row < numMonths[0]; row++) {
4660 group = "";
4661 this.maxRows = 4;
4662 for (col = 0; col < numMonths[1]; col++) {
4663 selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
4664 cornerClass = " ui-corner-all";
4665 calender = "";
4666 if (isMultiMonth) {
4667 calender += "<div class='ui-datepicker-group";
4668 if (numMonths[1] > 1) {
4669 switch (col) {
4670 case 0: calender += " ui-datepicker-group-first";
4671 cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
4672 case numMonths[1]-1: calender += " ui-datepicker-group-last";
4673 cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
4674 default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
4675 }
4676 }
4677 calender += "'>";
4678 }
4679 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
4680 (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
4681 (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
4682 this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
4683 row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
4684 "</div><table class='ui-datepicker-calendar'><thead>" +
4685 "<tr>";
4686 thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
4687 for (dow = 0; dow < 7; dow++) { // days of the week
4688 day = (dow + firstDay) % 7;
4689 thead += "<th" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
4690 "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
4691 }
4692 calender += thead + "</tr></thead><tbody>";
4693 daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
4694 if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
4695 inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
4696 }
4697 leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
4698 curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
4699 numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
4700 this.maxRows = numRows;
4701 printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
4702 for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
4703 calender += "<tr>";
4704 tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
4705 this._get(inst, "calculateWeek")(printDate) + "</td>");
4706 for (dow = 0; dow < 7; dow++) { // create date picker days
4707 daySettings = (beforeShowDay ?
4708 beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
4709 otherMonth = (printDate.getMonth() !== drawMonth);
4710 unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
4711 (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
4712 tbody += "<td class='" +
4713 ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
4714 (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
4715 ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
4716 (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
4717 // or defaultDate is current printedDate and defaultDate is selectedDate
4718 " " + this._dayOverClass : "") + // highlight selected day
4719 (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days
4720 (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
4721 (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
4722 (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
4723 ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "&#39;") + "'" : "") + // cell title
4724 (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
4725 (otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
4726 (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
4727 (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
4728 (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
4729 (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
4730 "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
4731 printDate.setDate(printDate.getDate() + 1);
4732 printDate = this._daylightSavingAdjust(printDate);
4733 }
4734 calender += tbody + "</tr>";
4735 }
4736 drawMonth++;
4737 if (drawMonth > 11) {
4738 drawMonth = 0;
4739 drawYear++;
4740 }
4741 calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
4742 ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
4743 group += calender;
4744 }
4745 html += group;
4746 }
4747 html += buttonPanel;
4748 inst._keyEvent = false;
4749 return html;
4750 },
4751
4752 /* Generate the month and year header. */
4753 _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
4754 secondary, monthNames, monthNamesShort) {
4755
4756 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
4757 changeMonth = this._get(inst, "changeMonth"),
4758 changeYear = this._get(inst, "changeYear"),
4759 showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
4760 html = "<div class='ui-datepicker-title'>",
4761 monthHtml = "";
4762
4763 // month selection
4764 if (secondary || !changeMonth) {
4765 monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
4766 } else {
4767 inMinYear = (minDate && minDate.getFullYear() === drawYear);
4768 inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
4769 monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
4770 for ( month = 0; month < 12; month++) {
4771 if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
4772 monthHtml += "<option value='" + month + "'" +
4773 (month === drawMonth ? " selected='selected'" : "") +
4774 ">" + monthNamesShort[month] + "</option>";
4775 }
4776 }
4777 monthHtml += "</select>";
4778 }
4779
4780 if (!showMonthAfterYear) {
4781 html += monthHtml + (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "");
4782 }
4783
4784 // year selection
4785 if ( !inst.yearshtml ) {
4786 inst.yearshtml = "";
4787 if (secondary || !changeYear) {
4788 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
4789 } else {
4790 // determine range of years to display
4791 years = this._get(inst, "yearRange").split(":");
4792 thisYear = new Date().getFullYear();
4793 determineYear = function(value) {
4794 var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
4795 (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
4796 parseInt(value, 10)));
4797 return (isNaN(year) ? thisYear : year);
4798 };
4799 year = determineYear(years[0]);
4800 endYear = Math.max(year, determineYear(years[1] || ""));
4801 year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
4802 endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
4803 inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
4804 for (; year <= endYear; year++) {
4805 inst.yearshtml += "<option value='" + year + "'" +
4806 (year === drawYear ? " selected='selected'" : "") +
4807 ">" + year + "</option>";
4808 }
4809 inst.yearshtml += "</select>";
4810
4811 html += inst.yearshtml;
4812 inst.yearshtml = null;
4813 }
4814 }
4815
4816 html += this._get(inst, "yearSuffix");
4817 if (showMonthAfterYear) {
4818 html += (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "") + monthHtml;
4819 }
4820 html += "</div>"; // Close datepicker_header
4821 return html;
4822 },
4823
4824 /* Adjust one of the date sub-fields. */
4825 _adjustInstDate: function(inst, offset, period) {
4826 var year = inst.drawYear + (period === "Y" ? offset : 0),
4827 month = inst.drawMonth + (period === "M" ? offset : 0),
4828 day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
4829 date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));
4830
4831 inst.selectedDay = date.getDate();
4832 inst.drawMonth = inst.selectedMonth = date.getMonth();
4833 inst.drawYear = inst.selectedYear = date.getFullYear();
4834 if (period === "M" || period === "Y") {
4835 this._notifyChange(inst);
4836 }
4837 },
4838
4839 /* Ensure a date is within any min/max bounds. */
4840 _restrictMinMax: function(inst, date) {
4841 var minDate = this._getMinMaxDate(inst, "min"),
4842 maxDate = this._getMinMaxDate(inst, "max"),
4843 newDate = (minDate && date < minDate ? minDate : date);
4844 return (maxDate && newDate > maxDate ? maxDate : newDate);
4845 },
4846
4847 /* Notify change of month/year. */
4848 _notifyChange: function(inst) {
4849 var onChange = this._get(inst, "onChangeMonthYear");
4850 if (onChange) {
4851 onChange.apply((inst.input ? inst.input[0] : null),
4852 [inst.selectedYear, inst.selectedMonth + 1, inst]);
4853 }
4854 },
4855
4856 /* Determine the number of months to show. */
4857 _getNumberOfMonths: function(inst) {
4858 var numMonths = this._get(inst, "numberOfMonths");
4859 return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
4860 },
4861
4862 /* Determine the current maximum date - ensure no time components are set. */
4863 _getMinMaxDate: function(inst, minMax) {
4864 return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
4865 },
4866
4867 /* Find the number of days in a given month. */
4868 _getDaysInMonth: function(year, month) {
4869 return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
4870 },
4871
4872 /* Find the day of the week of the first of a month. */
4873 _getFirstDayOfMonth: function(year, month) {
4874 return new Date(year, month, 1).getDay();
4875 },
4876
4877 /* Determines if we should allow a "next/prev" month display change. */
4878 _canAdjustMonth: function(inst, offset, curYear, curMonth) {
4879 var numMonths = this._getNumberOfMonths(inst),
4880 date = this._daylightSavingAdjust(new Date(curYear,
4881 curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
4882
4883 if (offset < 0) {
4884 date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
4885 }
4886 return this._isInRange(inst, date);
4887 },
4888
4889 /* Is the given date in the accepted range? */
4890 _isInRange: function(inst, date) {
4891 var yearSplit, currentYear,
4892 minDate = this._getMinMaxDate(inst, "min"),
4893 maxDate = this._getMinMaxDate(inst, "max"),
4894 minYear = null,
4895 maxYear = null,
4896 years = this._get(inst, "yearRange");
4897 if (years){
4898 yearSplit = years.split(":");
4899 currentYear = new Date().getFullYear();
4900 minYear = parseInt(yearSplit[0], 10);
4901 maxYear = parseInt(yearSplit[1], 10);
4902 if ( yearSplit[0].match(/[+\-].*/) ) {
4903 minYear += currentYear;
4904 }
4905 if ( yearSplit[1].match(/[+\-].*/) ) {
4906 maxYear += currentYear;
4907 }
4908 }
4909
4910 return ((!minDate || date.getTime() >= minDate.getTime()) &&
4911 (!maxDate || date.getTime() <= maxDate.getTime()) &&
4912 (!minYear || date.getFullYear() >= minYear) &&
4913 (!maxYear || date.getFullYear() <= maxYear));
4914 },
4915
4916 /* Provide the configuration settings for formatting/parsing. */
4917 _getFormatConfig: function(inst) {
4918 var shortYearCutoff = this._get(inst, "shortYearCutoff");
4919 shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
4920 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
4921 return {shortYearCutoff: shortYearCutoff,
4922 dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
4923 monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
4924 },
4925
4926 /* Format the given date for display. */
4927 _formatDate: function(inst, day, month, year) {
4928 if (!day) {
4929 inst.currentDay = inst.selectedDay;
4930 inst.currentMonth = inst.selectedMonth;
4931 inst.currentYear = inst.selectedYear;
4932 }
4933 var date = (day ? (typeof day === "object" ? day :
4934 this._daylightSavingAdjust(new Date(year, month, day))) :
4935 this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
4936 return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
4937 }
4938 });
4939
4940 /*
4941 * Bind hover events for datepicker elements.
4942 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
4943 * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
4944 */
4945 function bindHover(dpDiv) {
4946 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
4947 return dpDiv.delegate(selector, "mouseout", function() {
4948 $(this).removeClass("ui-state-hover");
4949 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
4950 $(this).removeClass("ui-datepicker-prev-hover");
4951 }
4952 if (this.className.indexOf("ui-datepicker-next") !== -1) {
4953 $(this).removeClass("ui-datepicker-next-hover");
4954 }
4955 })
4956 .delegate(selector, "mouseover", function(){
4957 if (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) {
4958 $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
4959 $(this).addClass("ui-state-hover");
4960 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
4961 $(this).addClass("ui-datepicker-prev-hover");
4962 }
4963 if (this.className.indexOf("ui-datepicker-next") !== -1) {
4964 $(this).addClass("ui-datepicker-next-hover");
4965 }
4966 }
4967 });
4968 }
4969
4970 /* jQuery extend now ignores nulls! */
4971 function extendRemove(target, props) {
4972 $.extend(target, props);
4973 for (var name in props) {
4974 if (props[name] == null) {
4975 target[name] = props[name];
4976 }
4977 }
4978 return target;
4979 }
4980
4981 /* Invoke the datepicker functionality.
4982 @param options string - a command, optionally followed by additional parameters or
4983 Object - settings for attaching new datepicker functionality
4984 @return jQuery object */
4985 $.fn.datepicker = function(options){
4986
4987 /* Verify an empty collection wasn't passed - Fixes #6976 */
4988 if ( !this.length ) {
4989 return this;
4990 }
4991
4992 /* Initialise the date picker. */
4993 if (!$.datepicker.initialized) {
4994 $(document).mousedown($.datepicker._checkExternalClick);
4995 $.datepicker.initialized = true;
4996 }
4997
4998 /* Append datepicker main container to body if not exist. */
4999 if ($("#"+$.datepicker._mainDivId).length === 0) {
5000 $("body").append($.datepicker.dpDiv);
5001 }
5002
5003 var otherArgs = Array.prototype.slice.call(arguments, 1);
5004 if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
5005 return $.datepicker["_" + options + "Datepicker"].
5006 apply($.datepicker, [this[0]].concat(otherArgs));
5007 }
5008 if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
5009 return $.datepicker["_" + options + "Datepicker"].
5010 apply($.datepicker, [this[0]].concat(otherArgs));
5011 }
5012 return this.each(function() {
5013 typeof options === "string" ?
5014 $.datepicker["_" + options + "Datepicker"].
5015 apply($.datepicker, [this].concat(otherArgs)) :
5016 $.datepicker._attachDatepicker(this, options);
5017 });
5018 };
5019
5020 $.datepicker = new Datepicker(); // singleton instance
5021 $.datepicker.initialized = false;
5022 $.datepicker.uuid = new Date().getTime();
5023 $.datepicker.version = "1.10.4";
5024
5025 })(jQuery);
5026 (function( $, undefined ) {
5027
5028 var sizeRelatedOptions = {
5029 buttons: true,
5030 height: true,
5031 maxHeight: true,
5032 maxWidth: true,
5033 minHeight: true,
5034 minWidth: true,
5035 width: true
5036 },
5037 resizableRelatedOptions = {
5038 maxHeight: true,
5039 maxWidth: true,
5040 minHeight: true,
5041 minWidth: true
5042 };
5043
5044 $.widget( "ui.dialog", {
5045 version: "1.10.4",
5046 options: {
5047 appendTo: "body",
5048 autoOpen: true,
5049 buttons: [],
5050 closeOnEscape: true,
5051 closeText: "close",
5052 dialogClass: "",
5053 draggable: true,
5054 hide: null,
5055 height: "auto",
5056 maxHeight: null,
5057 maxWidth: null,
5058 minHeight: 150,
5059 minWidth: 150,
5060 modal: false,
5061 position: {
5062 my: "center",
5063 at: "center",
5064 of: window,
5065 collision: "fit",
5066 // Ensure the titlebar is always visible
5067 using: function( pos ) {
5068 var topOffset = $( this ).css( pos ).offset().top;
5069 if ( topOffset < 0 ) {
5070 $( this ).css( "top", pos.top - topOffset );
5071 }
5072 }
5073 },
5074 resizable: true,
5075 show: null,
5076 title: null,
5077 width: 300,
5078
5079 // callbacks
5080 beforeClose: null,
5081 close: null,
5082 drag: null,
5083 dragStart: null,
5084 dragStop: null,
5085 focus: null,
5086 open: null,
5087 resize: null,
5088 resizeStart: null,
5089 resizeStop: null
5090 },
5091
5092 _create: function() {
5093 this.originalCss = {
5094 display: this.element[0].style.display,
5095 width: this.element[0].style.width,
5096 minHeight: this.element[0].style.minHeight,
5097 maxHeight: this.element[0].style.maxHeight,
5098 height: this.element[0].style.height
5099 };
5100 this.originalPosition = {
5101 parent: this.element.parent(),
5102 index: this.element.parent().children().index( this.element )
5103 };
5104 this.originalTitle = this.element.attr("title");
5105 this.options.title = this.options.title || this.originalTitle;
5106
5107 this._createWrapper();
5108
5109 this.element
5110 .show()
5111 .removeAttr("title")
5112 .addClass("ui-dialog-content ui-widget-content")
5113 .appendTo( this.uiDialog );
5114
5115 this._createTitlebar();
5116 this._createButtonPane();
5117
5118 if ( this.options.draggable && $.fn.draggable ) {
5119 this._makeDraggable();
5120 }
5121 if ( this.options.resizable && $.fn.resizable ) {
5122 this._makeResizable();
5123 }
5124
5125 this._isOpen = false;
5126 },
5127
5128 _init: function() {
5129 if ( this.options.autoOpen ) {
5130 this.open();
5131 }
5132 },
5133
5134 _appendTo: function() {
5135 var element = this.options.appendTo;
5136 if ( element && (element.jquery || element.nodeType) ) {
5137 return $( element );
5138 }
5139 return this.document.find( element || "body" ).eq( 0 );
5140 },
5141
5142 _destroy: function() {
5143 var next,
5144 originalPosition = this.originalPosition;
5145
5146 this._destroyOverlay();
5147
5148 this.element
5149 .removeUniqueId()
5150 .removeClass("ui-dialog-content ui-widget-content")
5151 .css( this.originalCss )
5152 // Without detaching first, the following becomes really slow
5153 .detach();
5154
5155 this.uiDialog.stop( true, true ).remove();
5156
5157 if ( this.originalTitle ) {
5158 this.element.attr( "title", this.originalTitle );
5159 }
5160
5161 next = originalPosition.parent.children().eq( originalPosition.index );
5162 // Don't try to place the dialog next to itself (#8613)
5163 if ( next.length && next[0] !== this.element[0] ) {
5164 next.before( this.element );
5165 } else {
5166 originalPosition.parent.append( this.element );
5167 }
5168 },
5169
5170 widget: function() {
5171 return this.uiDialog;
5172 },
5173
5174 disable: $.noop,
5175 enable: $.noop,
5176
5177 close: function( event ) {
5178 var activeElement,
5179 that = this;
5180
5181 if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
5182 return;
5183 }
5184
5185 this._isOpen = false;
5186 this._destroyOverlay();
5187
5188 if ( !this.opener.filter(":focusable").focus().length ) {
5189
5190 // support: IE9
5191 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
5192 try {
5193 activeElement = this.document[ 0 ].activeElement;
5194
5195 // Support: IE9, IE10
5196 // If the <body> is blurred, IE will switch windows, see #4520
5197 if ( activeElement && activeElement.nodeName.toLowerCase() !== "body" ) {
5198
5199 // Hiding a focused element doesn't trigger blur in WebKit
5200 // so in case we have nothing to focus on, explicitly blur the active element
5201 // https://bugs.webkit.org/show_bug.cgi?id=47182
5202 $( activeElement ).blur();
5203 }
5204 } catch ( error ) {}
5205 }
5206
5207 this._hide( this.uiDialog, this.options.hide, function() {
5208 that._trigger( "close", event );
5209 });
5210 },
5211
5212 isOpen: function() {
5213 return this._isOpen;
5214 },
5215
5216 moveToTop: function() {
5217 this._moveToTop();
5218 },
5219
5220 _moveToTop: function( event, silent ) {
5221 var moved = !!this.uiDialog.nextAll(":visible").insertBefore( this.uiDialog ).length;
5222 if ( moved && !silent ) {
5223 this._trigger( "focus", event );
5224 }
5225 return moved;
5226 },
5227
5228 open: function() {
5229 var that = this;
5230 if ( this._isOpen ) {
5231 if ( this._moveToTop() ) {
5232 this._focusTabbable();
5233 }
5234 return;
5235 }
5236
5237 this._isOpen = true;
5238 this.opener = $( this.document[0].activeElement );
5239
5240 this._size();
5241 this._position();
5242 this._createOverlay();
5243 this._moveToTop( null, true );
5244 this._show( this.uiDialog, this.options.show, function() {
5245 that._focusTabbable();
5246 that._trigger("focus");
5247 });
5248
5249 this._trigger("open");
5250 },
5251
5252 _focusTabbable: function() {
5253 // Set focus to the first match:
5254 // 1. First element inside the dialog matching [autofocus]
5255 // 2. Tabbable element inside the content element
5256 // 3. Tabbable element inside the buttonpane
5257 // 4. The close button
5258 // 5. The dialog itself
5259 var hasFocus = this.element.find("[autofocus]");
5260 if ( !hasFocus.length ) {
5261 hasFocus = this.element.find(":tabbable");
5262 }
5263 if ( !hasFocus.length ) {
5264 hasFocus = this.uiDialogButtonPane.find(":tabbable");
5265 }
5266 if ( !hasFocus.length ) {
5267 hasFocus = this.uiDialogTitlebarClose.filter(":tabbable");
5268 }
5269 if ( !hasFocus.length ) {
5270 hasFocus = this.uiDialog;
5271 }
5272 hasFocus.eq( 0 ).focus();
5273 },
5274
5275 _keepFocus: function( event ) {
5276 function checkFocus() {
5277 var activeElement = this.document[0].activeElement,
5278 isActive = this.uiDialog[0] === activeElement ||
5279 $.contains( this.uiDialog[0], activeElement );
5280 if ( !isActive ) {
5281 this._focusTabbable();
5282 }
5283 }
5284 event.preventDefault();
5285 checkFocus.call( this );
5286 // support: IE
5287 // IE <= 8 doesn't prevent moving focus even with event.preventDefault()
5288 // so we check again later
5289 this._delay( checkFocus );
5290 },
5291
5292 _createWrapper: function() {
5293 this.uiDialog = $("<div>")
5294 .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " +
5295 this.options.dialogClass )
5296 .hide()
5297 .attr({
5298 // Setting tabIndex makes the div focusable
5299 tabIndex: -1,
5300 role: "dialog"
5301 })
5302 .appendTo( this._appendTo() );
5303
5304 this._on( this.uiDialog, {
5305 keydown: function( event ) {
5306 if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
5307 event.keyCode === $.ui.keyCode.ESCAPE ) {
5308 event.preventDefault();
5309 this.close( event );
5310 return;
5311 }
5312
5313 // prevent tabbing out of dialogs
5314 if ( event.keyCode !== $.ui.keyCode.TAB ) {
5315 return;
5316 }
5317 var tabbables = this.uiDialog.find(":tabbable"),
5318 first = tabbables.filter(":first"),
5319 last = tabbables.filter(":last");
5320
5321 if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) {
5322 first.focus( 1 );
5323 event.preventDefault();
5324 } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) {
5325 last.focus( 1 );
5326 event.preventDefault();
5327 }
5328 },
5329 mousedown: function( event ) {
5330 if ( this._moveToTop( event ) ) {
5331 this._focusTabbable();
5332 }
5333 }
5334 });
5335
5336 // We assume that any existing aria-describedby attribute means
5337 // that the dialog content is marked up properly
5338 // otherwise we brute force the content as the description
5339 if ( !this.element.find("[aria-describedby]").length ) {
5340 this.uiDialog.attr({
5341 "aria-describedby": this.element.uniqueId().attr("id")
5342 });
5343 }
5344 },
5345
5346 _createTitlebar: function() {
5347 var uiDialogTitle;
5348
5349 this.uiDialogTitlebar = $("<div>")
5350 .addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix")
5351 .prependTo( this.uiDialog );
5352 this._on( this.uiDialogTitlebar, {
5353 mousedown: function( event ) {
5354 // Don't prevent click on close button (#8838)
5355 // Focusing a dialog that is partially scrolled out of view
5356 // causes the browser to scroll it into view, preventing the click event
5357 if ( !$( event.target ).closest(".ui-dialog-titlebar-close") ) {
5358 // Dialog isn't getting focus when dragging (#8063)
5359 this.uiDialog.focus();
5360 }
5361 }
5362 });
5363
5364 // support: IE
5365 // Use type="button" to prevent enter keypresses in textboxes from closing the
5366 // dialog in IE (#9312)
5367 this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
5368 .button({
5369 label: this.options.closeText,
5370 icons: {
5371 primary: "ui-icon-closethick"
5372 },
5373 text: false
5374 })
5375 .addClass("ui-dialog-titlebar-close")
5376 .appendTo( this.uiDialogTitlebar );
5377 this._on( this.uiDialogTitlebarClose, {
5378 click: function( event ) {
5379 event.preventDefault();
5380 this.close( event );
5381 }
5382 });
5383
5384 uiDialogTitle = $("<span>")
5385 .uniqueId()
5386 .addClass("ui-dialog-title")
5387 .prependTo( this.uiDialogTitlebar );
5388 this._title( uiDialogTitle );
5389
5390 this.uiDialog.attr({
5391 "aria-labelledby": uiDialogTitle.attr("id")
5392 });
5393 },
5394
5395 _title: function( title ) {
5396 if ( !this.options.title ) {
5397 title.html("&#160;");
5398 }
5399 title.text( this.options.title );
5400 },
5401
5402 _createButtonPane: function() {
5403 this.uiDialogButtonPane = $("<div>")
5404 .addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix");
5405
5406 this.uiButtonSet = $("<div>")
5407 .addClass("ui-dialog-buttonset")
5408 .appendTo( this.uiDialogButtonPane );
5409
5410 this._createButtons();
5411 },
5412
5413 _createButtons: function() {
5414 var that = this,
5415 buttons = this.options.buttons;
5416
5417 // if we already have a button pane, remove it
5418 this.uiDialogButtonPane.remove();
5419 this.uiButtonSet.empty();
5420
5421 if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) {
5422 this.uiDialog.removeClass("ui-dialog-buttons");
5423 return;
5424 }
5425
5426 $.each( buttons, function( name, props ) {
5427 var click, buttonOptions;
5428 props = $.isFunction( props ) ?
5429 { click: props, text: name } :
5430 props;
5431 // Default to a non-submitting button
5432 props = $.extend( { type: "button" }, props );
5433 // Change the context for the click callback to be the main element
5434 click = props.click;
5435 props.click = function() {
5436 click.apply( that.element[0], arguments );
5437 };
5438 buttonOptions = {
5439 icons: props.icons,
5440 text: props.showText
5441 };
5442 delete props.icons;
5443 delete props.showText;
5444 $( "<button></button>", props )
5445 .button( buttonOptions )
5446 .appendTo( that.uiButtonSet );
5447 });
5448 this.uiDialog.addClass("ui-dialog-buttons");
5449 this.uiDialogButtonPane.appendTo( this.uiDialog );
5450 },
5451
5452 _makeDraggable: function() {
5453 var that = this,
5454 options = this.options;
5455
5456 function filteredUi( ui ) {
5457 return {
5458 position: ui.position,
5459 offset: ui.offset
5460 };
5461 }
5462
5463 this.uiDialog.draggable({
5464 cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
5465 handle: ".ui-dialog-titlebar",
5466 containment: "document",
5467 start: function( event, ui ) {
5468 $( this ).addClass("ui-dialog-dragging");
5469 that._blockFrames();
5470 that._trigger( "dragStart", event, filteredUi( ui ) );
5471 },
5472 drag: function( event, ui ) {
5473 that._trigger( "drag", event, filteredUi( ui ) );
5474 },
5475 stop: function( event, ui ) {
5476 options.position = [
5477 ui.position.left - that.document.scrollLeft(),
5478 ui.position.top - that.document.scrollTop()
5479 ];
5480 $( this ).removeClass("ui-dialog-dragging");
5481 that._unblockFrames();
5482 that._trigger( "dragStop", event, filteredUi( ui ) );
5483 }
5484 });
5485 },
5486
5487 _makeResizable: function() {
5488 var that = this,
5489 options = this.options,
5490 handles = options.resizable,
5491 // .ui-resizable has position: relative defined in the stylesheet
5492 // but dialogs have to use absolute or fixed positioning
5493 position = this.uiDialog.css("position"),
5494 resizeHandles = typeof handles === "string" ?
5495 handles :
5496 "n,e,s,w,se,sw,ne,nw";
5497
5498 function filteredUi( ui ) {
5499 return {
5500 originalPosition: ui.originalPosition,
5501 originalSize: ui.originalSize,
5502 position: ui.position,
5503 size: ui.size
5504 };
5505 }
5506
5507 this.uiDialog.resizable({
5508 cancel: ".ui-dialog-content",
5509 containment: "document",
5510 alsoResize: this.element,
5511 maxWidth: options.maxWidth,
5512 maxHeight: options.maxHeight,
5513 minWidth: options.minWidth,
5514 minHeight: this._minHeight(),
5515 handles: resizeHandles,
5516 start: function( event, ui ) {
5517 $( this ).addClass("ui-dialog-resizing");
5518 that._blockFrames();
5519 that._trigger( "resizeStart", event, filteredUi( ui ) );
5520 },
5521 resize: function( event, ui ) {
5522 that._trigger( "resize", event, filteredUi( ui ) );
5523 },
5524 stop: function( event, ui ) {
5525 options.height = $( this ).height();
5526 options.width = $( this ).width();
5527 $( this ).removeClass("ui-dialog-resizing");
5528 that._unblockFrames();
5529 that._trigger( "resizeStop", event, filteredUi( ui ) );
5530 }
5531 })
5532 .css( "position", position );
5533 },
5534
5535 _minHeight: function() {
5536 var options = this.options;
5537
5538 return options.height === "auto" ?
5539 options.minHeight :
5540 Math.min( options.minHeight, options.height );
5541 },
5542
5543 _position: function() {
5544 // Need to show the dialog to get the actual offset in the position plugin
5545 var isVisible = this.uiDialog.is(":visible");
5546 if ( !isVisible ) {
5547 this.uiDialog.show();
5548 }
5549 this.uiDialog.position( this.options.position );
5550 if ( !isVisible ) {
5551 this.uiDialog.hide();
5552 }
5553 },
5554
5555 _setOptions: function( options ) {
5556 var that = this,
5557 resize = false,
5558 resizableOptions = {};
5559
5560 $.each( options, function( key, value ) {
5561 that._setOption( key, value );
5562
5563 if ( key in sizeRelatedOptions ) {
5564 resize = true;
5565 }
5566 if ( key in resizableRelatedOptions ) {
5567 resizableOptions[ key ] = value;
5568 }
5569 });
5570
5571 if ( resize ) {
5572 this._size();
5573 this._position();
5574 }
5575 if ( this.uiDialog.is(":data(ui-resizable)") ) {
5576 this.uiDialog.resizable( "option", resizableOptions );
5577 }
5578 },
5579
5580 _setOption: function( key, value ) {
5581 var isDraggable, isResizable,
5582 uiDialog = this.uiDialog;
5583
5584 if ( key === "dialogClass" ) {
5585 uiDialog
5586 .removeClass( this.options.dialogClass )
5587 .addClass( value );
5588 }
5589
5590 if ( key === "disabled" ) {
5591 return;
5592 }
5593
5594 this._super( key, value );
5595
5596 if ( key === "appendTo" ) {
5597 this.uiDialog.appendTo( this._appendTo() );
5598 }
5599
5600 if ( key === "buttons" ) {
5601 this._createButtons();
5602 }
5603
5604 if ( key === "closeText" ) {
5605 this.uiDialogTitlebarClose.button({
5606 // Ensure that we always pass a string
5607 label: "" + value
5608 });
5609 }
5610
5611 if ( key === "draggable" ) {
5612 isDraggable = uiDialog.is(":data(ui-draggable)");
5613 if ( isDraggable && !value ) {
5614 uiDialog.draggable("destroy");
5615 }
5616
5617 if ( !isDraggable && value ) {
5618 this._makeDraggable();
5619 }
5620 }
5621
5622 if ( key === "position" ) {
5623 this._position();
5624 }
5625
5626 if ( key === "resizable" ) {
5627 // currently resizable, becoming non-resizable
5628 isResizable = uiDialog.is(":data(ui-resizable)");
5629 if ( isResizable && !value ) {
5630 uiDialog.resizable("destroy");
5631 }
5632
5633 // currently resizable, changing handles
5634 if ( isResizable && typeof value === "string" ) {
5635 uiDialog.resizable( "option", "handles", value );
5636 }
5637
5638 // currently non-resizable, becoming resizable
5639 if ( !isResizable && value !== false ) {
5640 this._makeResizable();
5641 }
5642 }
5643
5644 if ( key === "title" ) {
5645 this._title( this.uiDialogTitlebar.find(".ui-dialog-title") );
5646 }
5647 },
5648
5649 _size: function() {
5650 // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
5651 // divs will both have width and height set, so we need to reset them
5652 var nonContentHeight, minContentHeight, maxContentHeight,
5653 options = this.options;
5654
5655 // Reset content sizing
5656 this.element.show().css({
5657 width: "auto",
5658 minHeight: 0,
5659 maxHeight: "none",
5660 height: 0
5661 });
5662
5663 if ( options.minWidth > options.width ) {
5664 options.width = options.minWidth;
5665 }
5666
5667 // reset wrapper sizing
5668 // determine the height of all the non-content elements
5669 nonContentHeight = this.uiDialog.css({
5670 height: "auto",
5671 width: options.width
5672 })
5673 .outerHeight();
5674 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
5675 maxContentHeight = typeof options.maxHeight === "number" ?
5676 Math.max( 0, options.maxHeight - nonContentHeight ) :
5677 "none";
5678
5679 if ( options.height === "auto" ) {
5680 this.element.css({
5681 minHeight: minContentHeight,
5682 maxHeight: maxContentHeight,
5683 height: "auto"
5684 });
5685 } else {
5686 this.element.height( Math.max( 0, options.height - nonContentHeight ) );
5687 }
5688
5689 if (this.uiDialog.is(":data(ui-resizable)") ) {
5690 this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
5691 }
5692 },
5693
5694 _blockFrames: function() {
5695 this.iframeBlocks = this.document.find( "iframe" ).map(function() {
5696 var iframe = $( this );
5697
5698 return $( "<div>" )
5699 .css({
5700 position: "absolute",
5701 width: iframe.outerWidth(),
5702 height: iframe.outerHeight()
5703 })
5704 .appendTo( iframe.parent() )
5705 .offset( iframe.offset() )[0];
5706 });
5707 },
5708
5709 _unblockFrames: function() {
5710 if ( this.iframeBlocks ) {
5711 this.iframeBlocks.remove();
5712 delete this.iframeBlocks;
5713 }
5714 },
5715
5716 _allowInteraction: function( event ) {
5717 if ( $( event.target ).closest(".ui-dialog").length ) {
5718 return true;
5719 }
5720
5721 // TODO: Remove hack when datepicker implements
5722 // the .ui-front logic (#8989)
5723 return !!$( event.target ).closest(".ui-datepicker").length;
5724 },
5725
5726 _createOverlay: function() {
5727 if ( !this.options.modal ) {
5728 return;
5729 }
5730
5731 var that = this,
5732 widgetFullName = this.widgetFullName;
5733 if ( !$.ui.dialog.overlayInstances ) {
5734 // Prevent use of anchors and inputs.
5735 // We use a delay in case the overlay is created from an
5736 // event that we're going to be cancelling. (#2804)
5737 this._delay(function() {
5738 // Handle .dialog().dialog("close") (#4065)
5739 if ( $.ui.dialog.overlayInstances ) {
5740 this.document.bind( "focusin.dialog", function( event ) {
5741 if ( !that._allowInteraction( event ) ) {
5742 event.preventDefault();
5743 $(".ui-dialog:visible:last .ui-dialog-content")
5744 .data( widgetFullName )._focusTabbable();
5745 }
5746 });
5747 }
5748 });
5749 }
5750
5751 this.overlay = $("<div>")
5752 .addClass("ui-widget-overlay ui-front")
5753 .appendTo( this._appendTo() );
5754 this._on( this.overlay, {
5755 mousedown: "_keepFocus"
5756 });
5757 $.ui.dialog.overlayInstances++;
5758 },
5759
5760 _destroyOverlay: function() {
5761 if ( !this.options.modal ) {
5762 return;
5763 }
5764
5765 if ( this.overlay ) {
5766 $.ui.dialog.overlayInstances--;
5767
5768 if ( !$.ui.dialog.overlayInstances ) {
5769 this.document.unbind( "focusin.dialog" );
5770 }
5771 this.overlay.remove();
5772 this.overlay = null;
5773 }
5774 }
5775 });
5776
5777 $.ui.dialog.overlayInstances = 0;
5778
5779 // DEPRECATED
5780 if ( $.uiBackCompat !== false ) {
5781 // position option with array notation
5782 // just override with old implementation
5783 $.widget( "ui.dialog", $.ui.dialog, {
5784 _position: function() {
5785 var position = this.options.position,
5786 myAt = [],
5787 offset = [ 0, 0 ],
5788 isVisible;
5789
5790 if ( position ) {
5791 if ( typeof position === "string" || (typeof position === "object" && "0" in position ) ) {
5792 myAt = position.split ? position.split(" ") : [ position[0], position[1] ];
5793 if ( myAt.length === 1 ) {
5794 myAt[1] = myAt[0];
5795 }
5796
5797 $.each( [ "left", "top" ], function( i, offsetPosition ) {
5798 if ( +myAt[ i ] === myAt[ i ] ) {
5799 offset[ i ] = myAt[ i ];
5800 myAt[ i ] = offsetPosition;
5801 }
5802 });
5803
5804 position = {
5805 my: myAt[0] + (offset[0] < 0 ? offset[0] : "+" + offset[0]) + " " +
5806 myAt[1] + (offset[1] < 0 ? offset[1] : "+" + offset[1]),
5807 at: myAt.join(" ")
5808 };
5809 }
5810
5811 position = $.extend( {}, $.ui.dialog.prototype.options.position, position );
5812 } else {
5813 position = $.ui.dialog.prototype.options.position;
5814 }
5815
5816 // need to show the dialog to get the actual offset in the position plugin
5817 isVisible = this.uiDialog.is(":visible");
5818 if ( !isVisible ) {
5819 this.uiDialog.show();
5820 }
5821 this.uiDialog.position( position );
5822 if ( !isVisible ) {
5823 this.uiDialog.hide();
5824 }
5825 }
5826 });
5827 }
5828
5829 }( jQuery ) );
5830 (function( $, undefined ) {
5831
5832 $.widget("ui.draggable", $.ui.mouse, {
5833 version: "1.10.4",
5834 widgetEventPrefix: "drag",
5835 options: {
5836 addClasses: true,
5837 appendTo: "parent",
5838 axis: false,
5839 connectToSortable: false,
5840 containment: false,
5841 cursor: "auto",
5842 cursorAt: false,
5843 grid: false,
5844 handle: false,
5845 helper: "original",
5846 iframeFix: false,
5847 opacity: false,
5848 refreshPositions: false,
5849 revert: false,
5850 revertDuration: 500,
5851 scope: "default",
5852 scroll: true,
5853 scrollSensitivity: 20,
5854 scrollSpeed: 20,
5855 snap: false,
5856 snapMode: "both",
5857 snapTolerance: 20,
5858 stack: false,
5859 zIndex: false,
5860
5861 // callbacks
5862 drag: null,
5863 start: null,
5864 stop: null
5865 },
5866 _create: function() {
5867
5868 if (this.options.helper === "original" && !(/^(?:r|a|f)/).test(this.element.css("position"))) {
5869 this.element[0].style.position = "relative";
5870 }
5871 if (this.options.addClasses){
5872 this.element.addClass("ui-draggable");
5873 }
5874 if (this.options.disabled){
5875 this.element.addClass("ui-draggable-disabled");
5876 }
5877
5878 this._mouseInit();
5879
5880 },
5881
5882 _destroy: function() {
5883 this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
5884 this._mouseDestroy();
5885 },
5886
5887 _mouseCapture: function(event) {
5888
5889 var o = this.options;
5890
5891 // among others, prevent a drag on a resizable-handle
5892 if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) {
5893 return false;
5894 }
5895
5896 //Quit if we're not on a valid handle
5897 this.handle = this._getHandle(event);
5898 if (!this.handle) {
5899 return false;
5900 }
5901
5902 $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
5903 $("<div class='ui-draggable-iframeFix' style='background: #fff;'></div>")
5904 .css({
5905 width: this.offsetWidth+"px", height: this.offsetHeight+"px",
5906 position: "absolute", opacity: "0.001", zIndex: 1000
5907 })
5908 .css($(this).offset())
5909 .appendTo("body");
5910 });
5911
5912 return true;
5913
5914 },
5915
5916 _mouseStart: function(event) {
5917
5918 var o = this.options;
5919
5920 //Create and append the visible helper
5921 this.helper = this._createHelper(event);
5922
5923 this.helper.addClass("ui-draggable-dragging");
5924
5925 //Cache the helper size
5926 this._cacheHelperProportions();
5927
5928 //If ddmanager is used for droppables, set the global draggable
5929 if($.ui.ddmanager) {
5930 $.ui.ddmanager.current = this;
5931 }
5932
5933 /*
5934 * - Position generation -
5935 * This block generates everything position related - it's the core of draggables.
5936 */
5937
5938 //Cache the margins of the original element
5939 this._cacheMargins();
5940
5941 //Store the helper's css position
5942 this.cssPosition = this.helper.css( "position" );
5943 this.scrollParent = this.helper.scrollParent();
5944 this.offsetParent = this.helper.offsetParent();
5945 this.offsetParentCssPosition = this.offsetParent.css( "position" );
5946
5947 //The element's absolute position on the page minus margins
5948 this.offset = this.positionAbs = this.element.offset();
5949 this.offset = {
5950 top: this.offset.top - this.margins.top,
5951 left: this.offset.left - this.margins.left
5952 };
5953
5954 //Reset scroll cache
5955 this.offset.scroll = false;
5956
5957 $.extend(this.offset, {
5958 click: { //Where the click happened, relative to the element
5959 left: event.pageX - this.offset.left,
5960 top: event.pageY - this.offset.top
5961 },
5962 parent: this._getParentOffset(),
5963 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
5964 });
5965
5966 //Generate the original position
5967 this.originalPosition = this.position = this._generatePosition(event);
5968 this.originalPageX = event.pageX;
5969 this.originalPageY = event.pageY;
5970
5971 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
5972 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
5973
5974 //Set a containment if given in the options
5975 this._setContainment();
5976
5977 //Trigger event + callbacks
5978 if(this._trigger("start", event) === false) {
5979 this._clear();
5980 return false;
5981 }
5982
5983 //Recache the helper size
5984 this._cacheHelperProportions();
5985
5986 //Prepare the droppable offsets
5987 if ($.ui.ddmanager && !o.dropBehaviour) {
5988 $.ui.ddmanager.prepareOffsets(this, event);
5989 }
5990
5991
5992 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
5993
5994 //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
5995 if ( $.ui.ddmanager ) {
5996 $.ui.ddmanager.dragStart(this, event);
5997 }
5998
5999 return true;
6000 },
6001
6002 _mouseDrag: function(event, noPropagation) {
6003 // reset any necessary cached properties (see #5009)
6004 if ( this.offsetParentCssPosition === "fixed" ) {
6005 this.offset.parent = this._getParentOffset();
6006 }
6007
6008 //Compute the helpers position
6009 this.position = this._generatePosition(event);
6010 this.positionAbs = this._convertPositionTo("absolute");
6011
6012 //Call plugins and callbacks and use the resulting position if something is returned
6013 if (!noPropagation) {
6014 var ui = this._uiHash();
6015 if(this._trigger("drag", event, ui) === false) {
6016 this._mouseUp({});
6017 return false;
6018 }
6019 this.position = ui.position;
6020 }
6021
6022 if(!this.options.axis || this.options.axis !== "y") {
6023 this.helper[0].style.left = this.position.left+"px";
6024 }
6025 if(!this.options.axis || this.options.axis !== "x") {
6026 this.helper[0].style.top = this.position.top+"px";
6027 }
6028 if($.ui.ddmanager) {
6029 $.ui.ddmanager.drag(this, event);
6030 }
6031
6032 return false;
6033 },
6034
6035 _mouseStop: function(event) {
6036
6037 //If we are using droppables, inform the manager about the drop
6038 var that = this,
6039 dropped = false;
6040 if ($.ui.ddmanager && !this.options.dropBehaviour) {
6041 dropped = $.ui.ddmanager.drop(this, event);
6042 }
6043
6044 //if a drop comes from outside (a sortable)
6045 if(this.dropped) {
6046 dropped = this.dropped;
6047 this.dropped = false;
6048 }
6049
6050 //if the original element is no longer in the DOM don't bother to continue (see #8269)
6051 if ( this.options.helper === "original" && !$.contains( this.element[ 0 ].ownerDocument, this.element[ 0 ] ) ) {
6052 return false;
6053 }
6054
6055 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))) {
6056 $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
6057 if(that._trigger("stop", event) !== false) {
6058 that._clear();
6059 }
6060 });
6061 } else {
6062 if(this._trigger("stop", event) !== false) {
6063 this._clear();
6064 }
6065 }
6066
6067 return false;
6068 },
6069
6070 _mouseUp: function(event) {
6071 //Remove frame helpers
6072 $("div.ui-draggable-iframeFix").each(function() {
6073 this.parentNode.removeChild(this);
6074 });
6075
6076 //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
6077 if( $.ui.ddmanager ) {
6078 $.ui.ddmanager.dragStop(this, event);
6079 }
6080
6081 return $.ui.mouse.prototype._mouseUp.call(this, event);
6082 },
6083
6084 cancel: function() {
6085
6086 if(this.helper.is(".ui-draggable-dragging")) {
6087 this._mouseUp({});
6088 } else {
6089 this._clear();
6090 }
6091
6092 return this;
6093
6094 },
6095
6096 _getHandle: function(event) {
6097 return this.options.handle ?
6098 !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
6099 true;
6100 },
6101
6102 _createHelper: function(event) {
6103
6104 var o = this.options,
6105 helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper === "clone" ? this.element.clone().removeAttr("id") : this.element);
6106
6107 if(!helper.parents("body").length) {
6108 helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo));
6109 }
6110
6111 if(helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) {
6112 helper.css("position", "absolute");
6113 }
6114
6115 return helper;
6116
6117 },
6118
6119 _adjustOffsetFromHelper: function(obj) {
6120 if (typeof obj === "string") {
6121 obj = obj.split(" ");
6122 }
6123 if ($.isArray(obj)) {
6124 obj = {left: +obj[0], top: +obj[1] || 0};
6125 }
6126 if ("left" in obj) {
6127 this.offset.click.left = obj.left + this.margins.left;
6128 }
6129 if ("right" in obj) {
6130 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
6131 }
6132 if ("top" in obj) {
6133 this.offset.click.top = obj.top + this.margins.top;
6134 }
6135 if ("bottom" in obj) {
6136 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
6137 }
6138 },
6139
6140 _getParentOffset: function() {
6141
6142 //Get the offsetParent and cache its position
6143 var po = this.offsetParent.offset();
6144
6145 // This is a special case where we need to modify a offset calculated on start, since the following happened:
6146 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
6147 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
6148 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
6149 if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
6150 po.left += this.scrollParent.scrollLeft();
6151 po.top += this.scrollParent.scrollTop();
6152 }
6153
6154 //This needs to be actually done for all browsers, since pageX/pageY includes this information
6155 //Ugly IE fix
6156 if((this.offsetParent[0] === document.body) ||
6157 (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
6158 po = { top: 0, left: 0 };
6159 }
6160
6161 return {
6162 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
6163 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
6164 };
6165
6166 },
6167
6168 _getRelativeOffset: function() {
6169
6170 if(this.cssPosition === "relative") {
6171 var p = this.element.position();
6172 return {
6173 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
6174 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
6175 };
6176 } else {
6177 return { top: 0, left: 0 };
6178 }
6179
6180 },
6181
6182 _cacheMargins: function() {
6183 this.margins = {
6184 left: (parseInt(this.element.css("marginLeft"),10) || 0),
6185 top: (parseInt(this.element.css("marginTop"),10) || 0),
6186 right: (parseInt(this.element.css("marginRight"),10) || 0),
6187 bottom: (parseInt(this.element.css("marginBottom"),10) || 0)
6188 };
6189 },
6190
6191 _cacheHelperProportions: function() {
6192 this.helperProportions = {
6193 width: this.helper.outerWidth(),
6194 height: this.helper.outerHeight()
6195 };
6196 },
6197
6198 _setContainment: function() {
6199
6200 var over, c, ce,
6201 o = this.options;
6202
6203 if ( !o.containment ) {
6204 this.containment = null;
6205 return;
6206 }
6207
6208 if ( o.containment === "window" ) {
6209 this.containment = [
6210 $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
6211 $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
6212 $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left,
6213 $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
6214 ];
6215 return;
6216 }
6217
6218 if ( o.containment === "document") {
6219 this.containment = [
6220 0,
6221 0,
6222 $( document ).width() - this.helperProportions.width - this.margins.left,
6223 ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
6224 ];
6225 return;
6226 }
6227
6228 if ( o.containment.constructor === Array ) {
6229 this.containment = o.containment;
6230 return;
6231 }
6232
6233 if ( o.containment === "parent" ) {
6234 o.containment = this.helper[ 0 ].parentNode;
6235 }
6236
6237 c = $( o.containment );
6238 ce = c[ 0 ];
6239
6240 if( !ce ) {
6241 return;
6242 }
6243
6244 over = c.css( "overflow" ) !== "hidden";
6245
6246 this.containment = [
6247 ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
6248 ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ) ,
6249 ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) - this.helperProportions.width - this.margins.left - this.margins.right,
6250 ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) - this.helperProportions.height - this.margins.top - this.margins.bottom
6251 ];
6252 this.relative_container = c;
6253 },
6254
6255 _convertPositionTo: function(d, pos) {
6256
6257 if(!pos) {
6258 pos = this.position;
6259 }
6260
6261 var mod = d === "absolute" ? 1 : -1,
6262 scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent;
6263
6264 //Cache the scroll
6265 if (!this.offset.scroll) {
6266 this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()};
6267 }
6268
6269 return {
6270 top: (
6271 pos.top + // The absolute mouse position
6272 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
6273 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
6274 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top ) * mod )
6275 ),
6276 left: (
6277 pos.left + // The absolute mouse position
6278 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
6279 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
6280 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left ) * mod )
6281 )
6282 };
6283
6284 },
6285
6286 _generatePosition: function(event) {
6287
6288 var containment, co, top, left,
6289 o = this.options,
6290 scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent,
6291 pageX = event.pageX,
6292 pageY = event.pageY;
6293
6294 //Cache the scroll
6295 if (!this.offset.scroll) {
6296 this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()};
6297 }
6298
6299 /*
6300 * - Position constraining -
6301 * Constrain the position to a mix of grid, containment.
6302 */
6303
6304 // If we are not dragging yet, we won't check for options
6305 if ( this.originalPosition ) {
6306 if ( this.containment ) {
6307 if ( this.relative_container ){
6308 co = this.relative_container.offset();
6309 containment = [
6310 this.containment[ 0 ] + co.left,
6311 this.containment[ 1 ] + co.top,
6312 this.containment[ 2 ] + co.left,
6313 this.containment[ 3 ] + co.top
6314 ];
6315 }
6316 else {
6317 containment = this.containment;
6318 }
6319
6320 if(event.pageX - this.offset.click.left < containment[0]) {
6321 pageX = containment[0] + this.offset.click.left;
6322 }
6323 if(event.pageY - this.offset.click.top < containment[1]) {
6324 pageY = containment[1] + this.offset.click.top;
6325 }
6326 if(event.pageX - this.offset.click.left > containment[2]) {
6327 pageX = containment[2] + this.offset.click.left;
6328 }
6329 if(event.pageY - this.offset.click.top > containment[3]) {
6330 pageY = containment[3] + this.offset.click.top;
6331 }
6332 }
6333
6334 if(o.grid) {
6335 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
6336 top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
6337 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;
6338
6339 left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
6340 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;
6341 }
6342
6343 }
6344
6345 return {
6346 top: (
6347 pageY - // The absolute mouse position
6348 this.offset.click.top - // Click offset (relative to the element)
6349 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
6350 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
6351 ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top )
6352 ),
6353 left: (
6354 pageX - // The absolute mouse position
6355 this.offset.click.left - // Click offset (relative to the element)
6356 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
6357 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
6358 ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left )
6359 )
6360 };
6361
6362 },
6363
6364 _clear: function() {
6365 this.helper.removeClass("ui-draggable-dragging");
6366 if(this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) {
6367 this.helper.remove();
6368 }
6369 this.helper = null;
6370 this.cancelHelperRemoval = false;
6371 },
6372
6373 // From now on bulk stuff - mainly helpers
6374
6375 _trigger: function(type, event, ui) {
6376 ui = ui || this._uiHash();
6377 $.ui.plugin.call(this, type, [event, ui]);
6378 //The absolute position has to be recalculated after plugins
6379 if(type === "drag") {
6380 this.positionAbs = this._convertPositionTo("absolute");
6381 }
6382 return $.Widget.prototype._trigger.call(this, type, event, ui);
6383 },
6384
6385 plugins: {},
6386
6387 _uiHash: function() {
6388 return {
6389 helper: this.helper,
6390 position: this.position,
6391 originalPosition: this.originalPosition,
6392 offset: this.positionAbs
6393 };
6394 }
6395
6396 });
6397
6398 $.ui.plugin.add("draggable", "connectToSortable", {
6399 start: function(event, ui) {
6400
6401 var inst = $(this).data("ui-draggable"), o = inst.options,
6402 uiSortable = $.extend({}, ui, { item: inst.element });
6403 inst.sortables = [];
6404 $(o.connectToSortable).each(function() {
6405 var sortable = $.data(this, "ui-sortable");
6406 if (sortable && !sortable.options.disabled) {
6407 inst.sortables.push({
6408 instance: sortable,
6409 shouldRevert: sortable.options.revert
6410 });
6411 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).
6412 sortable._trigger("activate", event, uiSortable);
6413 }
6414 });
6415
6416 },
6417 stop: function(event, ui) {
6418
6419 //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
6420 var inst = $(this).data("ui-draggable"),
6421 uiSortable = $.extend({}, ui, { item: inst.element });
6422
6423 $.each(inst.sortables, function() {
6424 if(this.instance.isOver) {
6425
6426 this.instance.isOver = 0;
6427
6428 inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
6429 this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
6430
6431 //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: "valid/invalid"
6432 if(this.shouldRevert) {
6433 this.instance.options.revert = this.shouldRevert;
6434 }
6435
6436 //Trigger the stop of the sortable
6437 this.instance._mouseStop(event);
6438
6439 this.instance.options.helper = this.instance.options._helper;
6440
6441 //If the helper has been the original item, restore properties in the sortable
6442 if(inst.options.helper === "original") {
6443 this.instance.currentItem.css({ top: "auto", left: "auto" });
6444 }
6445
6446 } else {
6447 this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
6448 this.instance._trigger("deactivate", event, uiSortable);
6449 }
6450
6451 });
6452
6453 },
6454 drag: function(event, ui) {
6455
6456 var inst = $(this).data("ui-draggable"), that = this;
6457
6458 $.each(inst.sortables, function() {
6459
6460 var innermostIntersecting = false,
6461 thisSortable = this;
6462
6463 //Copy over some variables to allow calling the sortable's native _intersectsWith
6464 this.instance.positionAbs = inst.positionAbs;
6465 this.instance.helperProportions = inst.helperProportions;
6466 this.instance.offset.click = inst.offset.click;
6467
6468 if(this.instance._intersectsWith(this.instance.containerCache)) {
6469 innermostIntersecting = true;
6470 $.each(inst.sortables, function () {
6471 this.instance.positionAbs = inst.positionAbs;
6472 this.instance.helperProportions = inst.helperProportions;
6473 this.instance.offset.click = inst.offset.click;
6474 if (this !== thisSortable &&
6475 this.instance._intersectsWith(this.instance.containerCache) &&
6476 $.contains(thisSortable.instance.element[0], this.instance.element[0])
6477 ) {
6478 innermostIntersecting = false;
6479 }
6480 return innermostIntersecting;
6481 });
6482 }
6483
6484
6485 if(innermostIntersecting) {
6486 //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
6487 if(!this.instance.isOver) {
6488
6489 this.instance.isOver = 1;
6490 //Now we fake the start of dragging for the sortable instance,
6491 //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
6492 //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)
6493 this.instance.currentItem = $(that).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item", true);
6494 this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
6495 this.instance.options.helper = function() { return ui.helper[0]; };
6496
6497 event.target = this.instance.currentItem[0];
6498 this.instance._mouseCapture(event, true);
6499 this.instance._mouseStart(event, true, true);
6500
6501 //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
6502 this.instance.offset.click.top = inst.offset.click.top;
6503 this.instance.offset.click.left = inst.offset.click.left;
6504 this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
6505 this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
6506
6507 inst._trigger("toSortable", event);
6508 inst.dropped = this.instance.element; //draggable revert needs that
6509 //hack so receive/update callbacks work (mostly)
6510 inst.currentItem = inst.element;
6511 this.instance.fromOutside = inst;
6512
6513 }
6514
6515 //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
6516 if(this.instance.currentItem) {
6517 this.instance._mouseDrag(event);
6518 }
6519
6520 } else {
6521
6522 //If it doesn't intersect with the sortable, and it intersected before,
6523 //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
6524 if(this.instance.isOver) {
6525
6526 this.instance.isOver = 0;
6527 this.instance.cancelHelperRemoval = true;
6528
6529 //Prevent reverting on this forced stop
6530 this.instance.options.revert = false;
6531
6532 // The out event needs to be triggered independently
6533 this.instance._trigger("out", event, this.instance._uiHash(this.instance));
6534
6535 this.instance._mouseStop(event, true);
6536 this.instance.options.helper = this.instance.options._helper;
6537
6538 //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
6539 this.instance.currentItem.remove();
6540 if(this.instance.placeholder) {
6541 this.instance.placeholder.remove();
6542 }
6543
6544 inst._trigger("fromSortable", event);
6545 inst.dropped = false; //draggable revert needs that
6546 }
6547
6548 }
6549
6550 });
6551
6552 }
6553 });
6554
6555 $.ui.plugin.add("draggable", "cursor", {
6556 start: function() {
6557 var t = $("body"), o = $(this).data("ui-draggable").options;
6558 if (t.css("cursor")) {
6559 o._cursor = t.css("cursor");
6560 }
6561 t.css("cursor", o.cursor);
6562 },
6563 stop: function() {
6564 var o = $(this).data("ui-draggable").options;
6565 if (o._cursor) {
6566 $("body").css("cursor", o._cursor);
6567 }
6568 }
6569 });
6570
6571 $.ui.plugin.add("draggable", "opacity", {
6572 start: function(event, ui) {
6573 var t = $(ui.helper), o = $(this).data("ui-draggable").options;
6574 if(t.css("opacity")) {
6575 o._opacity = t.css("opacity");
6576 }
6577 t.css("opacity", o.opacity);
6578 },
6579 stop: function(event, ui) {
6580 var o = $(this).data("ui-draggable").options;
6581 if(o._opacity) {
6582 $(ui.helper).css("opacity", o._opacity);
6583 }
6584 }
6585 });
6586
6587 $.ui.plugin.add("draggable", "scroll", {
6588 start: function() {
6589 var i = $(this).data("ui-draggable");
6590 if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") {
6591 i.overflowOffset = i.scrollParent.offset();
6592 }
6593 },
6594 drag: function( event ) {
6595
6596 var i = $(this).data("ui-draggable"), o = i.options, scrolled = false;
6597
6598 if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") {
6599
6600 if(!o.axis || o.axis !== "x") {
6601 if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
6602 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
6603 } else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) {
6604 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
6605 }
6606 }
6607
6608 if(!o.axis || o.axis !== "y") {
6609 if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
6610 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
6611 } else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) {
6612 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
6613 }
6614 }
6615
6616 } else {
6617
6618 if(!o.axis || o.axis !== "x") {
6619 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
6620 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
6621 } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
6622 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
6623 }
6624 }
6625
6626 if(!o.axis || o.axis !== "y") {
6627 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
6628 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
6629 } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
6630 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
6631 }
6632 }
6633
6634 }
6635
6636 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
6637 $.ui.ddmanager.prepareOffsets(i, event);
6638 }
6639
6640 }
6641 });
6642
6643 $.ui.plugin.add("draggable", "snap", {
6644 start: function() {
6645
6646 var i = $(this).data("ui-draggable"),
6647 o = i.options;
6648
6649 i.snapElements = [];
6650
6651 $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() {
6652 var $t = $(this),
6653 $o = $t.offset();
6654 if(this !== i.element[0]) {
6655 i.snapElements.push({
6656 item: this,
6657 width: $t.outerWidth(), height: $t.outerHeight(),
6658 top: $o.top, left: $o.left
6659 });
6660 }
6661 });
6662
6663 },
6664 drag: function(event, ui) {
6665
6666 var ts, bs, ls, rs, l, r, t, b, i, first,
6667 inst = $(this).data("ui-draggable"),
6668 o = inst.options,
6669 d = o.snapTolerance,
6670 x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
6671 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
6672
6673 for (i = inst.snapElements.length - 1; i >= 0; i--){
6674
6675 l = inst.snapElements[i].left;
6676 r = l + inst.snapElements[i].width;
6677 t = inst.snapElements[i].top;
6678 b = t + inst.snapElements[i].height;
6679
6680 if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) {
6681 if(inst.snapElements[i].snapping) {
6682 (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
6683 }
6684 inst.snapElements[i].snapping = false;
6685 continue;
6686 }
6687
6688 if(o.snapMode !== "inner") {
6689 ts = Math.abs(t - y2) <= d;
6690 bs = Math.abs(b - y1) <= d;
6691 ls = Math.abs(l - x2) <= d;
6692 rs = Math.abs(r - x1) <= d;
6693 if(ts) {
6694 ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
6695 }
6696 if(bs) {
6697 ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
6698 }
6699 if(ls) {
6700 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
6701 }
6702 if(rs) {
6703 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
6704 }
6705 }
6706
6707 first = (ts || bs || ls || rs);
6708
6709 if(o.snapMode !== "outer") {
6710 ts = Math.abs(t - y1) <= d;
6711 bs = Math.abs(b - y2) <= d;
6712 ls = Math.abs(l - x1) <= d;
6713 rs = Math.abs(r - x2) <= d;
6714 if(ts) {
6715 ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
6716 }
6717 if(bs) {
6718 ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
6719 }
6720 if(ls) {
6721 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
6722 }
6723 if(rs) {
6724 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
6725 }
6726 }
6727
6728 if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) {
6729 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
6730 }
6731 inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
6732
6733 }
6734
6735 }
6736 });
6737
6738 $.ui.plugin.add("draggable", "stack", {
6739 start: function() {
6740 var min,
6741 o = this.data("ui-draggable").options,
6742 group = $.makeArray($(o.stack)).sort(function(a,b) {
6743 return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0);
6744 });
6745
6746 if (!group.length) { return; }
6747
6748 min = parseInt($(group[0]).css("zIndex"), 10) || 0;
6749 $(group).each(function(i) {
6750 $(this).css("zIndex", min + i);
6751 });
6752 this.css("zIndex", (min + group.length));
6753 }
6754 });
6755
6756 $.ui.plugin.add("draggable", "zIndex", {
6757 start: function(event, ui) {
6758 var t = $(ui.helper), o = $(this).data("ui-draggable").options;
6759 if(t.css("zIndex")) {
6760 o._zIndex = t.css("zIndex");
6761 }
6762 t.css("zIndex", o.zIndex);
6763 },
6764 stop: function(event, ui) {
6765 var o = $(this).data("ui-draggable").options;
6766 if(o._zIndex) {
6767 $(ui.helper).css("zIndex", o._zIndex);
6768 }
6769 }
6770 });
6771
6772 })(jQuery);
6773 (function( $, undefined ) {
6774
6775 function isOverAxis( x, reference, size ) {
6776 return ( x > reference ) && ( x < ( reference + size ) );
6777 }
6778
6779 $.widget("ui.droppable", {
6780 version: "1.10.4",
6781 widgetEventPrefix: "drop",
6782 options: {
6783 accept: "*",
6784 activeClass: false,
6785 addClasses: true,
6786 greedy: false,
6787 hoverClass: false,
6788 scope: "default",
6789 tolerance: "intersect",
6790
6791 // callbacks
6792 activate: null,
6793 deactivate: null,
6794 drop: null,
6795 out: null,
6796 over: null
6797 },
6798 _create: function() {
6799
6800 var proportions,
6801 o = this.options,
6802 accept = o.accept;
6803
6804 this.isover = false;
6805 this.isout = true;
6806
6807 this.accept = $.isFunction(accept) ? accept : function(d) {
6808 return d.is(accept);
6809 };
6810
6811 this.proportions = function( /* valueToWrite */ ) {
6812 if ( arguments.length ) {
6813 // Store the droppable's proportions
6814 proportions = arguments[ 0 ];
6815 } else {
6816 // Retrieve or derive the droppable's proportions
6817 return proportions ?
6818 proportions :
6819 proportions = {
6820 width: this.element[ 0 ].offsetWidth,
6821 height: this.element[ 0 ].offsetHeight
6822 };
6823 }
6824 };
6825
6826 // Add the reference and positions to the manager
6827 $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || [];
6828 $.ui.ddmanager.droppables[o.scope].push(this);
6829
6830 (o.addClasses && this.element.addClass("ui-droppable"));
6831
6832 },
6833
6834 _destroy: function() {
6835 var i = 0,
6836 drop = $.ui.ddmanager.droppables[this.options.scope];
6837
6838 for ( ; i < drop.length; i++ ) {
6839 if ( drop[i] === this ) {
6840 drop.splice(i, 1);
6841 }
6842 }
6843
6844 this.element.removeClass("ui-droppable ui-droppable-disabled");
6845 },
6846
6847 _setOption: function(key, value) {
6848
6849 if(key === "accept") {
6850 this.accept = $.isFunction(value) ? value : function(d) {
6851 return d.is(value);
6852 };
6853 }
6854 $.Widget.prototype._setOption.apply(this, arguments);
6855 },
6856
6857 _activate: function(event) {
6858 var draggable = $.ui.ddmanager.current;
6859 if(this.options.activeClass) {
6860 this.element.addClass(this.options.activeClass);
6861 }
6862 if(draggable){
6863 this._trigger("activate", event, this.ui(draggable));
6864 }
6865 },
6866
6867 _deactivate: function(event) {
6868 var draggable = $.ui.ddmanager.current;
6869 if(this.options.activeClass) {
6870 this.element.removeClass(this.options.activeClass);
6871 }
6872 if(draggable){
6873 this._trigger("deactivate", event, this.ui(draggable));
6874 }
6875 },
6876
6877 _over: function(event) {
6878
6879 var draggable = $.ui.ddmanager.current;
6880
6881 // Bail if draggable and droppable are same element
6882 if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
6883 return;
6884 }
6885
6886 if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
6887 if(this.options.hoverClass) {
6888 this.element.addClass(this.options.hoverClass);
6889 }
6890 this._trigger("over", event, this.ui(draggable));
6891 }
6892
6893 },
6894
6895 _out: function(event) {
6896
6897 var draggable = $.ui.ddmanager.current;
6898
6899 // Bail if draggable and droppable are same element
6900 if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
6901 return;
6902 }
6903
6904 if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
6905 if(this.options.hoverClass) {
6906 this.element.removeClass(this.options.hoverClass);
6907 }
6908 this._trigger("out", event, this.ui(draggable));
6909 }
6910
6911 },
6912
6913 _drop: function(event,custom) {
6914
6915 var draggable = custom || $.ui.ddmanager.current,
6916 childrenIntersection = false;
6917
6918 // Bail if draggable and droppable are same element
6919 if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
6920 return false;
6921 }
6922
6923 this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function() {
6924 var inst = $.data(this, "ui-droppable");
6925 if(
6926 inst.options.greedy &&
6927 !inst.options.disabled &&
6928 inst.options.scope === draggable.options.scope &&
6929 inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) &&
6930 $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)
6931 ) { childrenIntersection = true; return false; }
6932 });
6933 if(childrenIntersection) {
6934 return false;
6935 }
6936
6937 if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
6938 if(this.options.activeClass) {
6939 this.element.removeClass(this.options.activeClass);
6940 }
6941 if(this.options.hoverClass) {
6942 this.element.removeClass(this.options.hoverClass);
6943 }
6944 this._trigger("drop", event, this.ui(draggable));
6945 return this.element;
6946 }
6947
6948 return false;
6949
6950 },
6951
6952 ui: function(c) {
6953 return {
6954 draggable: (c.currentItem || c.element),
6955 helper: c.helper,
6956 position: c.position,
6957 offset: c.positionAbs
6958 };
6959 }
6960
6961 });
6962
6963 $.ui.intersect = function(draggable, droppable, toleranceMode) {
6964
6965 if (!droppable.offset) {
6966 return false;
6967 }
6968
6969 var draggableLeft, draggableTop,
6970 x1 = (draggable.positionAbs || draggable.position.absolute).left,
6971 y1 = (draggable.positionAbs || draggable.position.absolute).top,
6972 x2 = x1 + draggable.helperProportions.width,
6973 y2 = y1 + draggable.helperProportions.height,
6974 l = droppable.offset.left,
6975 t = droppable.offset.top,
6976 r = l + droppable.proportions().width,
6977 b = t + droppable.proportions().height;
6978
6979 switch (toleranceMode) {
6980 case "fit":
6981 return (l <= x1 && x2 <= r && t <= y1 && y2 <= b);
6982 case "intersect":
6983 return (l < x1 + (draggable.helperProportions.width / 2) && // Right Half
6984 x2 - (draggable.helperProportions.width / 2) < r && // Left Half
6985 t < y1 + (draggable.helperProportions.height / 2) && // Bottom Half
6986 y2 - (draggable.helperProportions.height / 2) < b ); // Top Half
6987 case "pointer":
6988 draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left);
6989 draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top);
6990 return isOverAxis( draggableTop, t, droppable.proportions().height ) && isOverAxis( draggableLeft, l, droppable.proportions().width );
6991 case "touch":
6992 return (
6993 (y1 >= t && y1 <= b) || // Top edge touching
6994 (y2 >= t && y2 <= b) || // Bottom edge touching
6995 (y1 < t && y2 > b) // Surrounded vertically
6996 ) && (
6997 (x1 >= l && x1 <= r) || // Left edge touching
6998 (x2 >= l && x2 <= r) || // Right edge touching
6999 (x1 < l && x2 > r) // Surrounded horizontally
7000 );
7001 default:
7002 return false;
7003 }
7004
7005 };
7006
7007 /*
7008 This manager tracks offsets of draggables and droppables
7009 */
7010 $.ui.ddmanager = {
7011 current: null,
7012 droppables: { "default": [] },
7013 prepareOffsets: function(t, event) {
7014
7015 var i, j,
7016 m = $.ui.ddmanager.droppables[t.options.scope] || [],
7017 type = event ? event.type : null, // workaround for #2317
7018 list = (t.currentItem || t.element).find(":data(ui-droppable)").addBack();
7019
7020 droppablesLoop: for (i = 0; i < m.length; i++) {
7021
7022 //No disabled and non-accepted
7023 if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) {
7024 continue;
7025 }
7026
7027 // Filter out elements in the current dragged item
7028 for (j=0; j < list.length; j++) {
7029 if(list[j] === m[i].element[0]) {
7030 m[i].proportions().height = 0;
7031 continue droppablesLoop;
7032 }
7033 }
7034
7035 m[i].visible = m[i].element.css("display") !== "none";
7036 if(!m[i].visible) {
7037 continue;
7038 }
7039
7040 //Activate the droppable if used directly from draggables
7041 if(type === "mousedown") {
7042 m[i]._activate.call(m[i], event);
7043 }
7044
7045 m[ i ].offset = m[ i ].element.offset();
7046 m[ i ].proportions({ width: m[ i ].element[ 0 ].offsetWidth, height: m[ i ].element[ 0 ].offsetHeight });
7047
7048 }
7049
7050 },
7051 drop: function(draggable, event) {
7052
7053 var dropped = false;
7054 // Create a copy of the droppables in case the list changes during the drop (#9116)
7055 $.each(($.ui.ddmanager.droppables[draggable.options.scope] || []).slice(), function() {
7056
7057 if(!this.options) {
7058 return;
7059 }
7060 if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) {
7061 dropped = this._drop.call(this, event) || dropped;
7062 }
7063
7064 if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
7065 this.isout = true;
7066 this.isover = false;
7067 this._deactivate.call(this, event);
7068 }
7069
7070 });
7071 return dropped;
7072
7073 },
7074 dragStart: function( draggable, event ) {
7075 //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
7076 draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
7077 if( !draggable.options.refreshPositions ) {
7078 $.ui.ddmanager.prepareOffsets( draggable, event );
7079 }
7080 });
7081 },
7082 drag: function(draggable, event) {
7083
7084 //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
7085 if(draggable.options.refreshPositions) {
7086 $.ui.ddmanager.prepareOffsets(draggable, event);
7087 }
7088
7089 //Run through all droppables and check their positions based on specific tolerance options
7090 $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
7091
7092 if(this.options.disabled || this.greedyChild || !this.visible) {
7093 return;
7094 }
7095
7096 var parentInstance, scope, parent,
7097 intersects = $.ui.intersect(draggable, this, this.options.tolerance),
7098 c = !intersects && this.isover ? "isout" : (intersects && !this.isover ? "isover" : null);
7099 if(!c) {
7100 return;
7101 }
7102
7103 if (this.options.greedy) {
7104 // find droppable parents with same scope
7105 scope = this.options.scope;
7106 parent = this.element.parents(":data(ui-droppable)").filter(function () {
7107 return $.data(this, "ui-droppable").options.scope === scope;
7108 });
7109
7110 if (parent.length) {
7111 parentInstance = $.data(parent[0], "ui-droppable");
7112 parentInstance.greedyChild = (c === "isover");
7113 }
7114 }
7115
7116 // we just moved into a greedy child
7117 if (parentInstance && c === "isover") {
7118 parentInstance.isover = false;
7119 parentInstance.isout = true;
7120 parentInstance._out.call(parentInstance, event);
7121 }
7122
7123 this[c] = true;
7124 this[c === "isout" ? "isover" : "isout"] = false;
7125 this[c === "isover" ? "_over" : "_out"].call(this, event);
7126
7127 // we just moved out of a greedy child
7128 if (parentInstance && c === "isout") {
7129 parentInstance.isout = false;
7130 parentInstance.isover = true;
7131 parentInstance._over.call(parentInstance, event);
7132 }
7133 });
7134
7135 },
7136 dragStop: function( draggable, event ) {
7137 draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
7138 //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
7139 if( !draggable.options.refreshPositions ) {
7140 $.ui.ddmanager.prepareOffsets( draggable, event );
7141 }
7142 }
7143 };
7144
7145 })(jQuery);
7146 (function($, undefined) {
7147
7148 var dataSpace = "ui-effects-";
7149
7150 $.effects = {
7151 effect: {}
7152 };
7153
7154 /*!
7155 * jQuery Color Animations v2.1.2
7156 * https://github.com/jquery/jquery-color
7157 *
7158 * Copyright 2013 jQuery Foundation and other contributors
7159 * Released under the MIT license.
7160 * http://jquery.org/license
7161 *
7162 * Date: Wed Jan 16 08:47:09 2013 -0600
7163 */
7164 (function( jQuery, undefined ) {
7165
7166 var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
7167
7168 // plusequals test for += 100 -= 100
7169 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
7170 // a set of RE's that can match strings and generate color tuples.
7171 stringParsers = [{
7172 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
7173 parse: function( execResult ) {
7174 return [
7175 execResult[ 1 ],
7176 execResult[ 2 ],
7177 execResult[ 3 ],
7178 execResult[ 4 ]
7179 ];
7180 }
7181 }, {
7182 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
7183 parse: function( execResult ) {
7184 return [
7185 execResult[ 1 ] * 2.55,
7186 execResult[ 2 ] * 2.55,
7187 execResult[ 3 ] * 2.55,
7188 execResult[ 4 ]
7189 ];
7190 }
7191 }, {
7192 // this regex ignores A-F because it's compared against an already lowercased string
7193 re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
7194 parse: function( execResult ) {
7195 return [
7196 parseInt( execResult[ 1 ], 16 ),
7197 parseInt( execResult[ 2 ], 16 ),
7198 parseInt( execResult[ 3 ], 16 )
7199 ];
7200 }
7201 }, {
7202 // this regex ignores A-F because it's compared against an already lowercased string
7203 re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
7204 parse: function( execResult ) {
7205 return [
7206 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
7207 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
7208 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
7209 ];
7210 }
7211 }, {
7212 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
7213 space: "hsla",
7214 parse: function( execResult ) {
7215 return [
7216 execResult[ 1 ],
7217 execResult[ 2 ] / 100,
7218 execResult[ 3 ] / 100,
7219 execResult[ 4 ]
7220 ];
7221 }
7222 }],
7223
7224 // jQuery.Color( )
7225 color = jQuery.Color = function( color, green, blue, alpha ) {
7226 return new jQuery.Color.fn.parse( color, green, blue, alpha );
7227 },
7228 spaces = {
7229 rgba: {
7230 props: {
7231 red: {
7232 idx: 0,
7233 type: "byte"
7234 },
7235 green: {
7236 idx: 1,
7237 type: "byte"
7238 },
7239 blue: {
7240 idx: 2,
7241 type: "byte"
7242 }
7243 }
7244 },
7245
7246 hsla: {
7247 props: {
7248 hue: {
7249 idx: 0,
7250 type: "degrees"
7251 },
7252 saturation: {
7253 idx: 1,
7254 type: "percent"
7255 },
7256 lightness: {
7257 idx: 2,
7258 type: "percent"
7259 }
7260 }
7261 }
7262 },
7263 propTypes = {
7264 "byte": {
7265 floor: true,
7266 max: 255
7267 },
7268 "percent": {
7269 max: 1
7270 },
7271 "degrees": {
7272 mod: 360,
7273 floor: true
7274 }
7275 },
7276 support = color.support = {},
7277
7278 // element for support tests
7279 supportElem = jQuery( "<p>" )[ 0 ],
7280
7281 // colors = jQuery.Color.names
7282 colors,
7283
7284 // local aliases of functions called often
7285 each = jQuery.each;
7286
7287 // determine rgba support immediately
7288 supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
7289 support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
7290
7291 // define cache name and alpha properties
7292 // for rgba and hsla spaces
7293 each( spaces, function( spaceName, space ) {
7294 space.cache = "_" + spaceName;
7295 space.props.alpha = {
7296 idx: 3,
7297 type: "percent",
7298 def: 1
7299 };
7300 });
7301
7302 function clamp( value, prop, allowEmpty ) {
7303 var type = propTypes[ prop.type ] || {};
7304
7305 if ( value == null ) {
7306 return (allowEmpty || !prop.def) ? null : prop.def;
7307 }
7308
7309 // ~~ is an short way of doing floor for positive numbers
7310 value = type.floor ? ~~value : parseFloat( value );
7311
7312 // IE will pass in empty strings as value for alpha,
7313 // which will hit this case
7314 if ( isNaN( value ) ) {
7315 return prop.def;
7316 }
7317
7318 if ( type.mod ) {
7319 // we add mod before modding to make sure that negatives values
7320 // get converted properly: -10 -> 350
7321 return (value + type.mod) % type.mod;
7322 }
7323
7324 // for now all property types without mod have min and max
7325 return 0 > value ? 0 : type.max < value ? type.max : value;
7326 }
7327
7328 function stringParse( string ) {
7329 var inst = color(),
7330 rgba = inst._rgba = [];
7331
7332 string = string.toLowerCase();
7333
7334 each( stringParsers, function( i, parser ) {
7335 var parsed,
7336 match = parser.re.exec( string ),
7337 values = match && parser.parse( match ),
7338 spaceName = parser.space || "rgba";
7339
7340 if ( values ) {
7341 parsed = inst[ spaceName ]( values );
7342
7343 // if this was an rgba parse the assignment might happen twice
7344 // oh well....
7345 inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
7346 rgba = inst._rgba = parsed._rgba;
7347
7348 // exit each( stringParsers ) here because we matched
7349 return false;
7350 }
7351 });
7352
7353 // Found a stringParser that handled it
7354 if ( rgba.length ) {
7355
7356 // if this came from a parsed string, force "transparent" when alpha is 0
7357 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
7358 if ( rgba.join() === "0,0,0,0" ) {
7359 jQuery.extend( rgba, colors.transparent );
7360 }
7361 return inst;
7362 }
7363
7364 // named colors
7365 return colors[ string ];
7366 }
7367
7368 color.fn = jQuery.extend( color.prototype, {
7369 parse: function( red, green, blue, alpha ) {
7370 if ( red === undefined ) {
7371 this._rgba = [ null, null, null, null ];
7372 return this;
7373 }
7374 if ( red.jquery || red.nodeType ) {
7375 red = jQuery( red ).css( green );
7376 green = undefined;
7377 }
7378
7379 var inst = this,
7380 type = jQuery.type( red ),
7381 rgba = this._rgba = [];
7382
7383 // more than 1 argument specified - assume ( red, green, blue, alpha )
7384 if ( green !== undefined ) {
7385 red = [ red, green, blue, alpha ];
7386 type = "array";
7387 }
7388
7389 if ( type === "string" ) {
7390 return this.parse( stringParse( red ) || colors._default );
7391 }
7392
7393 if ( type === "array" ) {
7394 each( spaces.rgba.props, function( key, prop ) {
7395 rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
7396 });
7397 return this;
7398 }
7399
7400 if ( type === "object" ) {
7401 if ( red instanceof color ) {
7402 each( spaces, function( spaceName, space ) {
7403 if ( red[ space.cache ] ) {
7404 inst[ space.cache ] = red[ space.cache ].slice();
7405 }
7406 });
7407 } else {
7408 each( spaces, function( spaceName, space ) {
7409 var cache = space.cache;
7410 each( space.props, function( key, prop ) {
7411
7412 // if the cache doesn't exist, and we know how to convert
7413 if ( !inst[ cache ] && space.to ) {
7414
7415 // if the value was null, we don't need to copy it
7416 // if the key was alpha, we don't need to copy it either
7417 if ( key === "alpha" || red[ key ] == null ) {
7418 return;
7419 }
7420 inst[ cache ] = space.to( inst._rgba );
7421 }
7422
7423 // this is the only case where we allow nulls for ALL properties.
7424 // call clamp with alwaysAllowEmpty
7425 inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
7426 });
7427
7428 // everything defined but alpha?
7429 if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
7430 // use the default of 1
7431 inst[ cache ][ 3 ] = 1;
7432 if ( space.from ) {
7433 inst._rgba = space.from( inst[ cache ] );
7434 }
7435 }
7436 });
7437 }
7438 return this;
7439 }
7440 },
7441 is: function( compare ) {
7442 var is = color( compare ),
7443 same = true,
7444 inst = this;
7445
7446 each( spaces, function( _, space ) {
7447 var localCache,
7448 isCache = is[ space.cache ];
7449 if (isCache) {
7450 localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
7451 each( space.props, function( _, prop ) {
7452 if ( isCache[ prop.idx ] != null ) {
7453 same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
7454 return same;
7455 }
7456 });
7457 }
7458 return same;
7459 });
7460 return same;
7461 },
7462 _space: function() {
7463 var used = [],
7464 inst = this;
7465 each( spaces, function( spaceName, space ) {
7466 if ( inst[ space.cache ] ) {
7467 used.push( spaceName );
7468 }
7469 });
7470 return used.pop();
7471 },
7472 transition: function( other, distance ) {
7473 var end = color( other ),
7474 spaceName = end._space(),
7475 space = spaces[ spaceName ],
7476 startColor = this.alpha() === 0 ? color( "transparent" ) : this,
7477 start = startColor[ space.cache ] || space.to( startColor._rgba ),
7478 result = start.slice();
7479
7480 end = end[ space.cache ];
7481 each( space.props, function( key, prop ) {
7482 var index = prop.idx,
7483 startValue = start[ index ],
7484 endValue = end[ index ],
7485 type = propTypes[ prop.type ] || {};
7486
7487 // if null, don't override start value
7488 if ( endValue === null ) {
7489 return;
7490 }
7491 // if null - use end
7492 if ( startValue === null ) {
7493 result[ index ] = endValue;
7494 } else {
7495 if ( type.mod ) {
7496 if ( endValue - startValue > type.mod / 2 ) {
7497 startValue += type.mod;
7498 } else if ( startValue - endValue > type.mod / 2 ) {
7499 startValue -= type.mod;
7500 }
7501 }
7502 result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
7503 }
7504 });
7505 return this[ spaceName ]( result );
7506 },
7507 blend: function( opaque ) {
7508 // if we are already opaque - return ourself
7509 if ( this._rgba[ 3 ] === 1 ) {
7510 return this;
7511 }
7512
7513 var rgb = this._rgba.slice(),
7514 a = rgb.pop(),
7515 blend = color( opaque )._rgba;
7516
7517 return color( jQuery.map( rgb, function( v, i ) {
7518 return ( 1 - a ) * blend[ i ] + a * v;
7519 }));
7520 },
7521 toRgbaString: function() {
7522 var prefix = "rgba(",
7523 rgba = jQuery.map( this._rgba, function( v, i ) {
7524 return v == null ? ( i > 2 ? 1 : 0 ) : v;
7525 });
7526
7527 if ( rgba[ 3 ] === 1 ) {
7528 rgba.pop();
7529 prefix = "rgb(";
7530 }
7531
7532 return prefix + rgba.join() + ")";
7533 },
7534 toHslaString: function() {
7535 var prefix = "hsla(",
7536 hsla = jQuery.map( this.hsla(), function( v, i ) {
7537 if ( v == null ) {
7538 v = i > 2 ? 1 : 0;
7539 }
7540
7541 // catch 1 and 2
7542 if ( i && i < 3 ) {
7543 v = Math.round( v * 100 ) + "%";
7544 }
7545 return v;
7546 });
7547
7548 if ( hsla[ 3 ] === 1 ) {
7549 hsla.pop();
7550 prefix = "hsl(";
7551 }
7552 return prefix + hsla.join() + ")";
7553 },
7554 toHexString: function( includeAlpha ) {
7555 var rgba = this._rgba.slice(),
7556 alpha = rgba.pop();
7557
7558 if ( includeAlpha ) {
7559 rgba.push( ~~( alpha * 255 ) );
7560 }
7561
7562 return "#" + jQuery.map( rgba, function( v ) {
7563
7564 // default to 0 when nulls exist
7565 v = ( v || 0 ).toString( 16 );
7566 return v.length === 1 ? "0" + v : v;
7567 }).join("");
7568 },
7569 toString: function() {
7570 return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
7571 }
7572 });
7573 color.fn.parse.prototype = color.fn;
7574
7575 // hsla conversions adapted from:
7576 // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
7577
7578 function hue2rgb( p, q, h ) {
7579 h = ( h + 1 ) % 1;
7580 if ( h * 6 < 1 ) {
7581 return p + (q - p) * h * 6;
7582 }
7583 if ( h * 2 < 1) {
7584 return q;
7585 }
7586 if ( h * 3 < 2 ) {
7587 return p + (q - p) * ((2/3) - h) * 6;
7588 }
7589 return p;
7590 }
7591
7592 spaces.hsla.to = function ( rgba ) {
7593 if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
7594 return [ null, null, null, rgba[ 3 ] ];
7595 }
7596 var r = rgba[ 0 ] / 255,
7597 g = rgba[ 1 ] / 255,
7598 b = rgba[ 2 ] / 255,
7599 a = rgba[ 3 ],
7600 max = Math.max( r, g, b ),
7601 min = Math.min( r, g, b ),
7602 diff = max - min,
7603 add = max + min,
7604 l = add * 0.5,
7605 h, s;
7606
7607 if ( min === max ) {
7608 h = 0;
7609 } else if ( r === max ) {
7610 h = ( 60 * ( g - b ) / diff ) + 360;
7611 } else if ( g === max ) {
7612 h = ( 60 * ( b - r ) / diff ) + 120;
7613 } else {
7614 h = ( 60 * ( r - g ) / diff ) + 240;
7615 }
7616
7617 // chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
7618 // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
7619 if ( diff === 0 ) {
7620 s = 0;
7621 } else if ( l <= 0.5 ) {
7622 s = diff / add;
7623 } else {
7624 s = diff / ( 2 - add );
7625 }
7626 return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
7627 };
7628
7629 spaces.hsla.from = function ( hsla ) {
7630 if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
7631 return [ null, null, null, hsla[ 3 ] ];
7632 }
7633 var h = hsla[ 0 ] / 360,
7634 s = hsla[ 1 ],
7635 l = hsla[ 2 ],
7636 a = hsla[ 3 ],
7637 q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
7638 p = 2 * l - q;
7639
7640 return [
7641 Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
7642 Math.round( hue2rgb( p, q, h ) * 255 ),
7643 Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
7644 a
7645 ];
7646 };
7647
7648
7649 each( spaces, function( spaceName, space ) {
7650 var props = space.props,
7651 cache = space.cache,
7652 to = space.to,
7653 from = space.from;
7654
7655 // makes rgba() and hsla()
7656 color.fn[ spaceName ] = function( value ) {
7657
7658 // generate a cache for this space if it doesn't exist
7659 if ( to && !this[ cache ] ) {
7660 this[ cache ] = to( this._rgba );
7661 }
7662 if ( value === undefined ) {
7663 return this[ cache ].slice();
7664 }
7665
7666 var ret,
7667 type = jQuery.type( value ),
7668 arr = ( type === "array" || type === "object" ) ? value : arguments,
7669 local = this[ cache ].slice();
7670
7671 each( props, function( key, prop ) {
7672 var val = arr[ type === "object" ? key : prop.idx ];
7673 if ( val == null ) {
7674 val = local[ prop.idx ];
7675 }
7676 local[ prop.idx ] = clamp( val, prop );
7677 });
7678
7679 if ( from ) {
7680 ret = color( from( local ) );
7681 ret[ cache ] = local;
7682 return ret;
7683 } else {
7684 return color( local );
7685 }
7686 };
7687
7688 // makes red() green() blue() alpha() hue() saturation() lightness()
7689 each( props, function( key, prop ) {
7690 // alpha is included in more than one space
7691 if ( color.fn[ key ] ) {
7692 return;
7693 }
7694 color.fn[ key ] = function( value ) {
7695 var vtype = jQuery.type( value ),
7696 fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
7697 local = this[ fn ](),
7698 cur = local[ prop.idx ],
7699 match;
7700
7701 if ( vtype === "undefined" ) {
7702 return cur;
7703 }
7704
7705 if ( vtype === "function" ) {
7706 value = value.call( this, cur );
7707 vtype = jQuery.type( value );
7708 }
7709 if ( value == null && prop.empty ) {
7710 return this;
7711 }
7712 if ( vtype === "string" ) {
7713 match = rplusequals.exec( value );
7714 if ( match ) {
7715 value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
7716 }
7717 }
7718 local[ prop.idx ] = value;
7719 return this[ fn ]( local );
7720 };
7721 });
7722 });
7723
7724 // add cssHook and .fx.step function for each named hook.
7725 // accept a space separated string of properties
7726 color.hook = function( hook ) {
7727 var hooks = hook.split( " " );
7728 each( hooks, function( i, hook ) {
7729 jQuery.cssHooks[ hook ] = {
7730 set: function( elem, value ) {
7731 var parsed, curElem,
7732 backgroundColor = "";
7733
7734 if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
7735 value = color( parsed || value );
7736 if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
7737 curElem = hook === "backgroundColor" ? elem.parentNode : elem;
7738 while (
7739 (backgroundColor === "" || backgroundColor === "transparent") &&
7740 curElem && curElem.style
7741 ) {
7742 try {
7743 backgroundColor = jQuery.css( curElem, "backgroundColor" );
7744 curElem = curElem.parentNode;
7745 } catch ( e ) {
7746 }
7747 }
7748
7749 value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
7750 backgroundColor :
7751 "_default" );
7752 }
7753
7754 value = value.toRgbaString();
7755 }
7756 try {
7757 elem.style[ hook ] = value;
7758 } catch( e ) {
7759 // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
7760 }
7761 }
7762 };
7763 jQuery.fx.step[ hook ] = function( fx ) {
7764 if ( !fx.colorInit ) {
7765 fx.start = color( fx.elem, hook );
7766 fx.end = color( fx.end );
7767 fx.colorInit = true;
7768 }
7769 jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
7770 };
7771 });
7772
7773 };
7774
7775 color.hook( stepHooks );
7776
7777 jQuery.cssHooks.borderColor = {
7778 expand: function( value ) {
7779 var expanded = {};
7780
7781 each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
7782 expanded[ "border" + part + "Color" ] = value;
7783 });
7784 return expanded;
7785 }
7786 };
7787
7788 // Basic color names only.
7789 // Usage of any of the other color names requires adding yourself or including
7790 // jquery.color.svg-names.js.
7791 colors = jQuery.Color.names = {
7792 // 4.1. Basic color keywords
7793 aqua: "#00ffff",
7794 black: "#000000",
7795 blue: "#0000ff",
7796 fuchsia: "#ff00ff",
7797 gray: "#808080",
7798 green: "#008000",
7799 lime: "#00ff00",
7800 maroon: "#800000",
7801 navy: "#000080",
7802 olive: "#808000",
7803 purple: "#800080",
7804 red: "#ff0000",
7805 silver: "#c0c0c0",
7806 teal: "#008080",
7807 white: "#ffffff",
7808 yellow: "#ffff00",
7809
7810 // 4.2.3. "transparent" color keyword
7811 transparent: [ null, null, null, 0 ],
7812
7813 _default: "#ffffff"
7814 };
7815
7816 })( jQuery );
7817
7818
7819 /******************************************************************************/
7820 /****************************** CLASS ANIMATIONS ******************************/
7821 /******************************************************************************/
7822 (function() {
7823
7824 var classAnimationActions = [ "add", "remove", "toggle" ],
7825 shorthandStyles = {
7826 border: 1,
7827 borderBottom: 1,
7828 borderColor: 1,
7829 borderLeft: 1,
7830 borderRight: 1,
7831 borderTop: 1,
7832 borderWidth: 1,
7833 margin: 1,
7834 padding: 1
7835 };
7836
7837 $.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) {
7838 $.fx.step[ prop ] = function( fx ) {
7839 if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
7840 jQuery.style( fx.elem, prop, fx.end );
7841 fx.setAttr = true;
7842 }
7843 };
7844 });
7845
7846 function getElementStyles( elem ) {
7847 var key, len,
7848 style = elem.ownerDocument.defaultView ?
7849 elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
7850 elem.currentStyle,
7851 styles = {};
7852
7853 if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
7854 len = style.length;
7855 while ( len-- ) {
7856 key = style[ len ];
7857 if ( typeof style[ key ] === "string" ) {
7858 styles[ $.camelCase( key ) ] = style[ key ];
7859 }
7860 }
7861 // support: Opera, IE <9
7862 } else {
7863 for ( key in style ) {
7864 if ( typeof style[ key ] === "string" ) {
7865 styles[ key ] = style[ key ];
7866 }
7867 }
7868 }
7869
7870 return styles;
7871 }
7872
7873
7874 function styleDifference( oldStyle, newStyle ) {
7875 var diff = {},
7876 name, value;
7877
7878 for ( name in newStyle ) {
7879 value = newStyle[ name ];
7880 if ( oldStyle[ name ] !== value ) {
7881 if ( !shorthandStyles[ name ] ) {
7882 if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
7883 diff[ name ] = value;
7884 }
7885 }
7886 }
7887 }
7888
7889 return diff;
7890 }
7891
7892 // support: jQuery <1.8
7893 if ( !$.fn.addBack ) {
7894 $.fn.addBack = function( selector ) {
7895 return this.add( selector == null ?
7896 this.prevObject : this.prevObject.filter( selector )
7897 );
7898 };
7899 }
7900
7901 $.effects.animateClass = function( value, duration, easing, callback ) {
7902 var o = $.speed( duration, easing, callback );
7903
7904 return this.queue( function() {
7905 var animated = $( this ),
7906 baseClass = animated.attr( "class" ) || "",
7907 applyClassChange,
7908 allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
7909
7910 // map the animated objects to store the original styles.
7911 allAnimations = allAnimations.map(function() {
7912 var el = $( this );
7913 return {
7914 el: el,
7915 start: getElementStyles( this )
7916 };
7917 });
7918
7919 // apply class change
7920 applyClassChange = function() {
7921 $.each( classAnimationActions, function(i, action) {
7922 if ( value[ action ] ) {
7923 animated[ action + "Class" ]( value[ action ] );
7924 }
7925 });
7926 };
7927 applyClassChange();
7928
7929 // map all animated objects again - calculate new styles and diff
7930 allAnimations = allAnimations.map(function() {
7931 this.end = getElementStyles( this.el[ 0 ] );
7932 this.diff = styleDifference( this.start, this.end );
7933 return this;
7934 });
7935
7936 // apply original class
7937 animated.attr( "class", baseClass );
7938
7939 // map all animated objects again - this time collecting a promise
7940 allAnimations = allAnimations.map(function() {
7941 var styleInfo = this,
7942 dfd = $.Deferred(),
7943 opts = $.extend({}, o, {
7944 queue: false,
7945 complete: function() {
7946 dfd.resolve( styleInfo );
7947 }
7948 });
7949
7950 this.el.animate( this.diff, opts );
7951 return dfd.promise();
7952 });
7953
7954 // once all animations have completed:
7955 $.when.apply( $, allAnimations.get() ).done(function() {
7956
7957 // set the final class
7958 applyClassChange();
7959
7960 // for each animated element,
7961 // clear all css properties that were animated
7962 $.each( arguments, function() {
7963 var el = this.el;
7964 $.each( this.diff, function(key) {
7965 el.css( key, "" );
7966 });
7967 });
7968
7969 // this is guarnteed to be there if you use jQuery.speed()
7970 // it also handles dequeuing the next anim...
7971 o.complete.call( animated[ 0 ] );
7972 });
7973 });
7974 };
7975
7976 $.fn.extend({
7977 addClass: (function( orig ) {
7978 return function( classNames, speed, easing, callback ) {
7979 return speed ?
7980 $.effects.animateClass.call( this,
7981 { add: classNames }, speed, easing, callback ) :
7982 orig.apply( this, arguments );
7983 };
7984 })( $.fn.addClass ),
7985
7986 removeClass: (function( orig ) {
7987 return function( classNames, speed, easing, callback ) {
7988 return arguments.length > 1 ?
7989 $.effects.animateClass.call( this,
7990 { remove: classNames }, speed, easing, callback ) :
7991 orig.apply( this, arguments );
7992 };
7993 })( $.fn.removeClass ),
7994
7995 toggleClass: (function( orig ) {
7996 return function( classNames, force, speed, easing, callback ) {
7997 if ( typeof force === "boolean" || force === undefined ) {
7998 if ( !speed ) {
7999 // without speed parameter
8000 return orig.apply( this, arguments );
8001 } else {
8002 return $.effects.animateClass.call( this,
8003 (force ? { add: classNames } : { remove: classNames }),
8004 speed, easing, callback );
8005 }
8006 } else {
8007 // without force parameter
8008 return $.effects.animateClass.call( this,
8009 { toggle: classNames }, force, speed, easing );
8010 }
8011 };
8012 })( $.fn.toggleClass ),
8013
8014 switchClass: function( remove, add, speed, easing, callback) {
8015 return $.effects.animateClass.call( this, {
8016 add: add,
8017 remove: remove
8018 }, speed, easing, callback );
8019 }
8020 });
8021
8022 })();
8023
8024 /******************************************************************************/
8025 /*********************************** EFFECTS **********************************/
8026 /******************************************************************************/
8027
8028 (function() {
8029
8030 $.extend( $.effects, {
8031 version: "1.10.4",
8032
8033 // Saves a set of properties in a data storage
8034 save: function( element, set ) {
8035 for( var i=0; i < set.length; i++ ) {
8036 if ( set[ i ] !== null ) {
8037 element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
8038 }
8039 }
8040 },
8041
8042 // Restores a set of previously saved properties from a data storage
8043 restore: function( element, set ) {
8044 var val, i;
8045 for( i=0; i < set.length; i++ ) {
8046 if ( set[ i ] !== null ) {
8047 val = element.data( dataSpace + set[ i ] );
8048 // support: jQuery 1.6.2
8049 // http://bugs.jquery.com/ticket/9917
8050 // jQuery 1.6.2 incorrectly returns undefined for any falsy value.
8051 // We can't differentiate between "" and 0 here, so we just assume
8052 // empty string since it's likely to be a more common value...
8053 if ( val === undefined ) {
8054 val = "";
8055 }
8056 element.css( set[ i ], val );
8057 }
8058 }
8059 },
8060
8061 setMode: function( el, mode ) {
8062 if (mode === "toggle") {
8063 mode = el.is( ":hidden" ) ? "show" : "hide";
8064 }
8065 return mode;
8066 },
8067
8068 // Translates a [top,left] array into a baseline value
8069 // this should be a little more flexible in the future to handle a string & hash
8070 getBaseline: function( origin, original ) {
8071 var y, x;
8072 switch ( origin[ 0 ] ) {
8073 case "top": y = 0; break;
8074 case "middle": y = 0.5; break;
8075 case "bottom": y = 1; break;
8076 default: y = origin[ 0 ] / original.height;
8077 }
8078 switch ( origin[ 1 ] ) {
8079 case "left": x = 0; break;
8080 case "center": x = 0.5; break;
8081 case "right": x = 1; break;
8082 default: x = origin[ 1 ] / original.width;
8083 }
8084 return {
8085 x: x,
8086 y: y
8087 };
8088 },
8089
8090 // Wraps the element around a wrapper that copies position properties
8091 createWrapper: function( element ) {
8092
8093 // if the element is already wrapped, return it
8094 if ( element.parent().is( ".ui-effects-wrapper" )) {
8095 return element.parent();
8096 }
8097
8098 // wrap the element
8099 var props = {
8100 width: element.outerWidth(true),
8101 height: element.outerHeight(true),
8102 "float": element.css( "float" )
8103 },
8104 wrapper = $( "<div></div>" )
8105 .addClass( "ui-effects-wrapper" )
8106 .css({
8107 fontSize: "100%",
8108 background: "transparent",
8109 border: "none",
8110 margin: 0,
8111 padding: 0
8112 }),
8113 // Store the size in case width/height are defined in % - Fixes #5245
8114 size = {
8115 width: element.width(),
8116 height: element.height()
8117 },
8118 active = document.activeElement;
8119
8120 // support: Firefox
8121 // Firefox incorrectly exposes anonymous content
8122 // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
8123 try {
8124 active.id;
8125 } catch( e ) {
8126 active = document.body;
8127 }
8128
8129 element.wrap( wrapper );
8130
8131 // Fixes #7595 - Elements lose focus when wrapped.
8132 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
8133 $( active ).focus();
8134 }
8135
8136 wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element
8137
8138 // transfer positioning properties to the wrapper
8139 if ( element.css( "position" ) === "static" ) {
8140 wrapper.css({ position: "relative" });
8141 element.css({ position: "relative" });
8142 } else {
8143 $.extend( props, {
8144 position: element.css( "position" ),
8145 zIndex: element.css( "z-index" )
8146 });
8147 $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
8148 props[ pos ] = element.css( pos );
8149 if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
8150 props[ pos ] = "auto";
8151 }
8152 });
8153 element.css({
8154 position: "relative",
8155 top: 0,
8156 left: 0,
8157 right: "auto",
8158 bottom: "auto"
8159 });
8160 }
8161 element.css(size);
8162
8163 return wrapper.css( props ).show();
8164 },
8165
8166 removeWrapper: function( element ) {
8167 var active = document.activeElement;
8168
8169 if ( element.parent().is( ".ui-effects-wrapper" ) ) {
8170 element.parent().replaceWith( element );
8171
8172 // Fixes #7595 - Elements lose focus when wrapped.
8173 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
8174 $( active ).focus();
8175 }
8176 }
8177
8178
8179 return element;
8180 },
8181
8182 setTransition: function( element, list, factor, value ) {
8183 value = value || {};
8184 $.each( list, function( i, x ) {
8185 var unit = element.cssUnit( x );
8186 if ( unit[ 0 ] > 0 ) {
8187 value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
8188 }
8189 });
8190 return value;
8191 }
8192 });
8193
8194 // return an effect options object for the given parameters:
8195 function _normalizeArguments( effect, options, speed, callback ) {
8196
8197 // allow passing all options as the first parameter
8198 if ( $.isPlainObject( effect ) ) {
8199 options = effect;
8200 effect = effect.effect;
8201 }
8202
8203 // convert to an object
8204 effect = { effect: effect };
8205
8206 // catch (effect, null, ...)
8207 if ( options == null ) {
8208 options = {};
8209 }
8210
8211 // catch (effect, callback)
8212 if ( $.isFunction( options ) ) {
8213 callback = options;
8214 speed = null;
8215 options = {};
8216 }
8217
8218 // catch (effect, speed, ?)
8219 if ( typeof options === "number" || $.fx.speeds[ options ] ) {
8220 callback = speed;
8221 speed = options;
8222 options = {};
8223 }
8224
8225 // catch (effect, options, callback)
8226 if ( $.isFunction( speed ) ) {
8227 callback = speed;
8228 speed = null;
8229 }
8230
8231 // add options to effect
8232 if ( options ) {
8233 $.extend( effect, options );
8234 }
8235
8236 speed = speed || options.duration;
8237 effect.duration = $.fx.off ? 0 :
8238 typeof speed === "number" ? speed :
8239 speed in $.fx.speeds ? $.fx.speeds[ speed ] :
8240 $.fx.speeds._default;
8241
8242 effect.complete = callback || options.complete;
8243
8244 return effect;
8245 }
8246
8247 function standardAnimationOption( option ) {
8248 // Valid standard speeds (nothing, number, named speed)
8249 if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
8250 return true;
8251 }
8252
8253 // Invalid strings - treat as "normal" speed
8254 if ( typeof option === "string" && !$.effects.effect[ option ] ) {
8255 return true;
8256 }
8257
8258 // Complete callback
8259 if ( $.isFunction( option ) ) {
8260 return true;
8261 }
8262
8263 // Options hash (but not naming an effect)
8264 if ( typeof option === "object" && !option.effect ) {
8265 return true;
8266 }
8267
8268 // Didn't match any standard API
8269 return false;
8270 }
8271
8272 $.fn.extend({
8273 effect: function( /* effect, options, speed, callback */ ) {
8274 var args = _normalizeArguments.apply( this, arguments ),
8275 mode = args.mode,
8276 queue = args.queue,
8277 effectMethod = $.effects.effect[ args.effect ];
8278
8279 if ( $.fx.off || !effectMethod ) {
8280 // delegate to the original method (e.g., .show()) if possible
8281 if ( mode ) {
8282 return this[ mode ]( args.duration, args.complete );
8283 } else {
8284 return this.each( function() {
8285 if ( args.complete ) {
8286 args.complete.call( this );
8287 }
8288 });
8289 }
8290 }
8291
8292 function run( next ) {
8293 var elem = $( this ),
8294 complete = args.complete,
8295 mode = args.mode;
8296
8297 function done() {
8298 if ( $.isFunction( complete ) ) {
8299 complete.call( elem[0] );
8300 }
8301 if ( $.isFunction( next ) ) {
8302 next();
8303 }
8304 }
8305
8306 // If the element already has the correct final state, delegate to
8307 // the core methods so the internal tracking of "olddisplay" works.
8308 if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
8309 elem[ mode ]();
8310 done();
8311 } else {
8312 effectMethod.call( elem[0], args, done );
8313 }
8314 }
8315
8316 return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
8317 },
8318
8319 show: (function( orig ) {
8320 return function( option ) {
8321 if ( standardAnimationOption( option ) ) {
8322 return orig.apply( this, arguments );
8323 } else {
8324 var args = _normalizeArguments.apply( this, arguments );
8325 args.mode = "show";
8326 return this.effect.call( this, args );
8327 }
8328 };
8329 })( $.fn.show ),
8330
8331 hide: (function( orig ) {
8332 return function( option ) {
8333 if ( standardAnimationOption( option ) ) {
8334 return orig.apply( this, arguments );
8335 } else {
8336 var args = _normalizeArguments.apply( this, arguments );
8337 args.mode = "hide";
8338 return this.effect.call( this, args );
8339 }
8340 };
8341 })( $.fn.hide ),
8342
8343 toggle: (function( orig ) {
8344 return function( option ) {
8345 if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
8346 return orig.apply( this, arguments );
8347 } else {
8348 var args = _normalizeArguments.apply( this, arguments );
8349 args.mode = "toggle";
8350 return this.effect.call( this, args );
8351 }
8352 };
8353 })( $.fn.toggle ),
8354
8355 // helper functions
8356 cssUnit: function(key) {
8357 var style = this.css( key ),
8358 val = [];
8359
8360 $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
8361 if ( style.indexOf( unit ) > 0 ) {
8362 val = [ parseFloat( style ), unit ];
8363 }
8364 });
8365 return val;
8366 }
8367 });
8368
8369 })();
8370
8371 /******************************************************************************/
8372 /*********************************** EASING ***********************************/
8373 /******************************************************************************/
8374
8375 (function() {
8376
8377 // based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
8378
8379 var baseEasings = {};
8380
8381 $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
8382 baseEasings[ name ] = function( p ) {
8383 return Math.pow( p, i + 2 );
8384 };
8385 });
8386
8387 $.extend( baseEasings, {
8388 Sine: function ( p ) {
8389 return 1 - Math.cos( p * Math.PI / 2 );
8390 },
8391 Circ: function ( p ) {
8392 return 1 - Math.sqrt( 1 - p * p );
8393 },
8394 Elastic: function( p ) {
8395 return p === 0 || p === 1 ? p :
8396 -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 );
8397 },
8398 Back: function( p ) {
8399 return p * p * ( 3 * p - 2 );
8400 },
8401 Bounce: function ( p ) {
8402 var pow2,
8403 bounce = 4;
8404
8405 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
8406 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
8407 }
8408 });
8409
8410 $.each( baseEasings, function( name, easeIn ) {
8411 $.easing[ "easeIn" + name ] = easeIn;
8412 $.easing[ "easeOut" + name ] = function( p ) {
8413 return 1 - easeIn( 1 - p );
8414 };
8415 $.easing[ "easeInOut" + name ] = function( p ) {
8416 return p < 0.5 ?
8417 easeIn( p * 2 ) / 2 :
8418 1 - easeIn( p * -2 + 2 ) / 2;
8419 };
8420 });
8421
8422 })();
8423
8424 })(jQuery);
8425 (function( $, undefined ) {
8426
8427 var rvertical = /up|down|vertical/,
8428 rpositivemotion = /up|left|vertical|horizontal/;
8429
8430 $.effects.effect.blind = function( o, done ) {
8431 // Create element
8432 var el = $( this ),
8433 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
8434 mode = $.effects.setMode( el, o.mode || "hide" ),
8435 direction = o.direction || "up",
8436 vertical = rvertical.test( direction ),
8437 ref = vertical ? "height" : "width",
8438 ref2 = vertical ? "top" : "left",
8439 motion = rpositivemotion.test( direction ),
8440 animation = {},
8441 show = mode === "show",
8442 wrapper, distance, margin;
8443
8444 // if already wrapped, the wrapper's properties are my property. #6245
8445 if ( el.parent().is( ".ui-effects-wrapper" ) ) {
8446 $.effects.save( el.parent(), props );
8447 } else {
8448 $.effects.save( el, props );
8449 }
8450 el.show();
8451 wrapper = $.effects.createWrapper( el ).css({
8452 overflow: "hidden"
8453 });
8454
8455 distance = wrapper[ ref ]();
8456 margin = parseFloat( wrapper.css( ref2 ) ) || 0;
8457
8458 animation[ ref ] = show ? distance : 0;
8459 if ( !motion ) {
8460 el
8461 .css( vertical ? "bottom" : "right", 0 )
8462 .css( vertical ? "top" : "left", "auto" )
8463 .css({ position: "absolute" });
8464
8465 animation[ ref2 ] = show ? margin : distance + margin;
8466 }
8467
8468 // start at 0 if we are showing
8469 if ( show ) {
8470 wrapper.css( ref, 0 );
8471 if ( ! motion ) {
8472 wrapper.css( ref2, margin + distance );
8473 }
8474 }
8475
8476 // Animate
8477 wrapper.animate( animation, {
8478 duration: o.duration,
8479 easing: o.easing,
8480 queue: false,
8481 complete: function() {
8482 if ( mode === "hide" ) {
8483 el.hide();
8484 }
8485 $.effects.restore( el, props );
8486 $.effects.removeWrapper( el );
8487 done();
8488 }
8489 });
8490
8491 };
8492
8493 })(jQuery);
8494 (function( $, undefined ) {
8495
8496 $.effects.effect.bounce = function( o, done ) {
8497 var el = $( this ),
8498 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
8499
8500 // defaults:
8501 mode = $.effects.setMode( el, o.mode || "effect" ),
8502 hide = mode === "hide",
8503 show = mode === "show",
8504 direction = o.direction || "up",
8505 distance = o.distance,
8506 times = o.times || 5,
8507
8508 // number of internal animations
8509 anims = times * 2 + ( show || hide ? 1 : 0 ),
8510 speed = o.duration / anims,
8511 easing = o.easing,
8512
8513 // utility:
8514 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
8515 motion = ( direction === "up" || direction === "left" ),
8516 i,
8517 upAnim,
8518 downAnim,
8519
8520 // we will need to re-assemble the queue to stack our animations in place
8521 queue = el.queue(),
8522 queuelen = queue.length;
8523
8524 // Avoid touching opacity to prevent clearType and PNG issues in IE
8525 if ( show || hide ) {
8526 props.push( "opacity" );
8527 }
8528
8529 $.effects.save( el, props );
8530 el.show();
8531 $.effects.createWrapper( el ); // Create Wrapper
8532
8533 // default distance for the BIGGEST bounce is the outer Distance / 3
8534 if ( !distance ) {
8535 distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
8536 }
8537
8538 if ( show ) {
8539 downAnim = { opacity: 1 };
8540 downAnim[ ref ] = 0;
8541
8542 // if we are showing, force opacity 0 and set the initial position
8543 // then do the "first" animation
8544 el.css( "opacity", 0 )
8545 .css( ref, motion ? -distance * 2 : distance * 2 )
8546 .animate( downAnim, speed, easing );
8547 }
8548
8549 // start at the smallest distance if we are hiding
8550 if ( hide ) {
8551 distance = distance / Math.pow( 2, times - 1 );
8552 }
8553
8554 downAnim = {};
8555 downAnim[ ref ] = 0;
8556 // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
8557 for ( i = 0; i < times; i++ ) {
8558 upAnim = {};
8559 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
8560
8561 el.animate( upAnim, speed, easing )
8562 .animate( downAnim, speed, easing );
8563
8564 distance = hide ? distance * 2 : distance / 2;
8565 }
8566
8567 // Last Bounce when Hiding
8568 if ( hide ) {
8569 upAnim = { opacity: 0 };
8570 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
8571
8572 el.animate( upAnim, speed, easing );
8573 }
8574
8575 el.queue(function() {
8576 if ( hide ) {
8577 el.hide();
8578 }
8579 $.effects.restore( el, props );
8580 $.effects.removeWrapper( el );
8581 done();
8582 });
8583
8584 // inject all the animations we just queued to be first in line (after "inprogress")
8585 if ( queuelen > 1) {
8586 queue.splice.apply( queue,
8587 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
8588 }
8589 el.dequeue();
8590
8591 };
8592
8593 })(jQuery);
8594 (function( $, undefined ) {
8595
8596 $.effects.effect.clip = function( o, done ) {
8597 // Create element
8598 var el = $( this ),
8599 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
8600 mode = $.effects.setMode( el, o.mode || "hide" ),
8601 show = mode === "show",
8602 direction = o.direction || "vertical",
8603 vert = direction === "vertical",
8604 size = vert ? "height" : "width",
8605 position = vert ? "top" : "left",
8606 animation = {},
8607 wrapper, animate, distance;
8608
8609 // Save & Show
8610 $.effects.save( el, props );
8611 el.show();
8612
8613 // Create Wrapper
8614 wrapper = $.effects.createWrapper( el ).css({
8615 overflow: "hidden"
8616 });
8617 animate = ( el[0].tagName === "IMG" ) ? wrapper : el;
8618 distance = animate[ size ]();
8619
8620 // Shift
8621 if ( show ) {
8622 animate.css( size, 0 );
8623 animate.css( position, distance / 2 );
8624 }
8625
8626 // Create Animation Object:
8627 animation[ size ] = show ? distance : 0;
8628 animation[ position ] = show ? 0 : distance / 2;
8629
8630 // Animate
8631 animate.animate( animation, {
8632 queue: false,
8633 duration: o.duration,
8634 easing: o.easing,
8635 complete: function() {
8636 if ( !show ) {
8637 el.hide();
8638 }
8639 $.effects.restore( el, props );
8640 $.effects.removeWrapper( el );
8641 done();
8642 }
8643 });
8644
8645 };
8646
8647 })(jQuery);
8648 (function( $, undefined ) {
8649
8650 $.effects.effect.drop = function( o, done ) {
8651
8652 var el = $( this ),
8653 props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
8654 mode = $.effects.setMode( el, o.mode || "hide" ),
8655 show = mode === "show",
8656 direction = o.direction || "left",
8657 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
8658 motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
8659 animation = {
8660 opacity: show ? 1 : 0
8661 },
8662 distance;
8663
8664 // Adjust
8665 $.effects.save( el, props );
8666 el.show();
8667 $.effects.createWrapper( el );
8668
8669 distance = o.distance || el[ ref === "top" ? "outerHeight": "outerWidth" ]( true ) / 2;
8670
8671 if ( show ) {
8672 el
8673 .css( "opacity", 0 )
8674 .css( ref, motion === "pos" ? -distance : distance );
8675 }
8676
8677 // Animation
8678 animation[ ref ] = ( show ?
8679 ( motion === "pos" ? "+=" : "-=" ) :
8680 ( motion === "pos" ? "-=" : "+=" ) ) +
8681 distance;
8682
8683 // Animate
8684 el.animate( animation, {
8685 queue: false,
8686 duration: o.duration,
8687 easing: o.easing,
8688 complete: function() {
8689 if ( mode === "hide" ) {
8690 el.hide();
8691 }
8692 $.effects.restore( el, props );
8693 $.effects.removeWrapper( el );
8694 done();
8695 }
8696 });
8697 };
8698
8699 })(jQuery);
8700 (function( $, undefined ) {
8701
8702 $.effects.effect.explode = function( o, done ) {
8703
8704 var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3,
8705 cells = rows,
8706 el = $( this ),
8707 mode = $.effects.setMode( el, o.mode || "hide" ),
8708 show = mode === "show",
8709
8710 // show and then visibility:hidden the element before calculating offset
8711 offset = el.show().css( "visibility", "hidden" ).offset(),
8712
8713 // width and height of a piece
8714 width = Math.ceil( el.outerWidth() / cells ),
8715 height = Math.ceil( el.outerHeight() / rows ),
8716 pieces = [],
8717
8718 // loop
8719 i, j, left, top, mx, my;
8720
8721 // children animate complete:
8722 function childComplete() {
8723 pieces.push( this );
8724 if ( pieces.length === rows * cells ) {
8725 animComplete();
8726 }
8727 }
8728
8729 // clone the element for each row and cell.
8730 for( i = 0; i < rows ; i++ ) { // ===>
8731 top = offset.top + i * height;
8732 my = i - ( rows - 1 ) / 2 ;
8733
8734 for( j = 0; j < cells ; j++ ) { // |||
8735 left = offset.left + j * width;
8736 mx = j - ( cells - 1 ) / 2 ;
8737
8738 // Create a clone of the now hidden main element that will be absolute positioned
8739 // within a wrapper div off the -left and -top equal to size of our pieces
8740 el
8741 .clone()
8742 .appendTo( "body" )
8743 .wrap( "<div></div>" )
8744 .css({
8745 position: "absolute",
8746 visibility: "visible",
8747 left: -j * width,
8748 top: -i * height
8749 })
8750
8751 // select the wrapper - make it overflow: hidden and absolute positioned based on
8752 // where the original was located +left and +top equal to the size of pieces
8753 .parent()
8754 .addClass( "ui-effects-explode" )
8755 .css({
8756 position: "absolute",
8757 overflow: "hidden",
8758 width: width,
8759 height: height,
8760 left: left + ( show ? mx * width : 0 ),
8761 top: top + ( show ? my * height : 0 ),
8762 opacity: show ? 0 : 1
8763 }).animate({
8764 left: left + ( show ? 0 : mx * width ),
8765 top: top + ( show ? 0 : my * height ),
8766 opacity: show ? 1 : 0
8767 }, o.duration || 500, o.easing, childComplete );
8768 }
8769 }
8770
8771 function animComplete() {
8772 el.css({
8773 visibility: "visible"
8774 });
8775 $( pieces ).remove();
8776 if ( !show ) {
8777 el.hide();
8778 }
8779 done();
8780 }
8781 };
8782
8783 })(jQuery);
8784 (function( $, undefined ) {
8785
8786 $.effects.effect.fade = function( o, done ) {
8787 var el = $( this ),
8788 mode = $.effects.setMode( el, o.mode || "toggle" );
8789
8790 el.animate({
8791 opacity: mode
8792 }, {
8793 queue: false,
8794 duration: o.duration,
8795 easing: o.easing,
8796 complete: done
8797 });
8798 };
8799
8800 })( jQuery );
8801 (function( $, undefined ) {
8802
8803 $.effects.effect.fold = function( o, done ) {
8804
8805 // Create element
8806 var el = $( this ),
8807 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
8808 mode = $.effects.setMode( el, o.mode || "hide" ),
8809 show = mode === "show",
8810 hide = mode === "hide",
8811 size = o.size || 15,
8812 percent = /([0-9]+)%/.exec( size ),
8813 horizFirst = !!o.horizFirst,
8814 widthFirst = show !== horizFirst,
8815 ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ],
8816 duration = o.duration / 2,
8817 wrapper, distance,
8818 animation1 = {},
8819 animation2 = {};
8820
8821 $.effects.save( el, props );
8822 el.show();
8823
8824 // Create Wrapper
8825 wrapper = $.effects.createWrapper( el ).css({
8826 overflow: "hidden"
8827 });
8828 distance = widthFirst ?
8829 [ wrapper.width(), wrapper.height() ] :
8830 [ wrapper.height(), wrapper.width() ];
8831
8832 if ( percent ) {
8833 size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
8834 }
8835 if ( show ) {
8836 wrapper.css( horizFirst ? {
8837 height: 0,
8838 width: size
8839 } : {
8840 height: size,
8841 width: 0
8842 });
8843 }
8844
8845 // Animation
8846 animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size;
8847 animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0;
8848
8849 // Animate
8850 wrapper
8851 .animate( animation1, duration, o.easing )
8852 .animate( animation2, duration, o.easing, function() {
8853 if ( hide ) {
8854 el.hide();
8855 }
8856 $.effects.restore( el, props );
8857 $.effects.removeWrapper( el );
8858 done();
8859 });
8860
8861 };
8862
8863 })(jQuery);
8864 (function( $, undefined ) {
8865
8866 $.effects.effect.highlight = function( o, done ) {
8867 var elem = $( this ),
8868 props = [ "backgroundImage", "backgroundColor", "opacity" ],
8869 mode = $.effects.setMode( elem, o.mode || "show" ),
8870 animation = {
8871 backgroundColor: elem.css( "backgroundColor" )
8872 };
8873
8874 if (mode === "hide") {
8875 animation.opacity = 0;
8876 }
8877
8878 $.effects.save( elem, props );
8879
8880 elem
8881 .show()
8882 .css({
8883 backgroundImage: "none",
8884 backgroundColor: o.color || "#ffff99"
8885 })
8886 .animate( animation, {
8887 queue: false,
8888 duration: o.duration,
8889 easing: o.easing,
8890 complete: function() {
8891 if ( mode === "hide" ) {
8892 elem.hide();
8893 }
8894 $.effects.restore( elem, props );
8895 done();
8896 }
8897 });
8898 };
8899
8900 })(jQuery);
8901 (function( $, undefined ) {
8902
8903 $.effects.effect.pulsate = function( o, done ) {
8904 var elem = $( this ),
8905 mode = $.effects.setMode( elem, o.mode || "show" ),
8906 show = mode === "show",
8907 hide = mode === "hide",
8908 showhide = ( show || mode === "hide" ),
8909
8910 // showing or hiding leaves of the "last" animation
8911 anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
8912 duration = o.duration / anims,
8913 animateTo = 0,
8914 queue = elem.queue(),
8915 queuelen = queue.length,
8916 i;
8917
8918 if ( show || !elem.is(":visible")) {
8919 elem.css( "opacity", 0 ).show();
8920 animateTo = 1;
8921 }
8922
8923 // anims - 1 opacity "toggles"
8924 for ( i = 1; i < anims; i++ ) {
8925 elem.animate({
8926 opacity: animateTo
8927 }, duration, o.easing );
8928 animateTo = 1 - animateTo;
8929 }
8930
8931 elem.animate({
8932 opacity: animateTo
8933 }, duration, o.easing);
8934
8935 elem.queue(function() {
8936 if ( hide ) {
8937 elem.hide();
8938 }
8939 done();
8940 });
8941
8942 // We just queued up "anims" animations, we need to put them next in the queue
8943 if ( queuelen > 1 ) {
8944 queue.splice.apply( queue,
8945 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
8946 }
8947 elem.dequeue();
8948 };
8949
8950 })(jQuery);
8951 (function( $, undefined ) {
8952
8953 $.effects.effect.puff = function( o, done ) {
8954 var elem = $( this ),
8955 mode = $.effects.setMode( elem, o.mode || "hide" ),
8956 hide = mode === "hide",
8957 percent = parseInt( o.percent, 10 ) || 150,
8958 factor = percent / 100,
8959 original = {
8960 height: elem.height(),
8961 width: elem.width(),
8962 outerHeight: elem.outerHeight(),
8963 outerWidth: elem.outerWidth()
8964 };
8965
8966 $.extend( o, {
8967 effect: "scale",
8968 queue: false,
8969 fade: true,
8970 mode: mode,
8971 complete: done,
8972 percent: hide ? percent : 100,
8973 from: hide ?
8974 original :
8975 {
8976 height: original.height * factor,
8977 width: original.width * factor,
8978 outerHeight: original.outerHeight * factor,
8979 outerWidth: original.outerWidth * factor
8980 }
8981 });
8982
8983 elem.effect( o );
8984 };
8985
8986 $.effects.effect.scale = function( o, done ) {
8987
8988 // Create element
8989 var el = $( this ),
8990 options = $.extend( true, {}, o ),
8991 mode = $.effects.setMode( el, o.mode || "effect" ),
8992 percent = parseInt( o.percent, 10 ) ||
8993 ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ),
8994 direction = o.direction || "both",
8995 origin = o.origin,
8996 original = {
8997 height: el.height(),
8998 width: el.width(),
8999 outerHeight: el.outerHeight(),
9000 outerWidth: el.outerWidth()
9001 },
9002 factor = {
9003 y: direction !== "horizontal" ? (percent / 100) : 1,
9004 x: direction !== "vertical" ? (percent / 100) : 1
9005 };
9006
9007 // We are going to pass this effect to the size effect:
9008 options.effect = "size";
9009 options.queue = false;
9010 options.complete = done;
9011
9012 // Set default origin and restore for show/hide
9013 if ( mode !== "effect" ) {
9014 options.origin = origin || ["middle","center"];
9015 options.restore = true;
9016 }
9017
9018 options.from = o.from || ( mode === "show" ? {
9019 height: 0,
9020 width: 0,
9021 outerHeight: 0,
9022 outerWidth: 0
9023 } : original );
9024 options.to = {
9025 height: original.height * factor.y,
9026 width: original.width * factor.x,
9027 outerHeight: original.outerHeight * factor.y,
9028 outerWidth: original.outerWidth * factor.x
9029 };
9030
9031 // Fade option to support puff
9032 if ( options.fade ) {
9033 if ( mode === "show" ) {
9034 options.from.opacity = 0;
9035 options.to.opacity = 1;
9036 }
9037 if ( mode === "hide" ) {
9038 options.from.opacity = 1;
9039 options.to.opacity = 0;
9040 }
9041 }
9042
9043 // Animate
9044 el.effect( options );
9045
9046 };
9047
9048 $.effects.effect.size = function( o, done ) {
9049
9050 // Create element
9051 var original, baseline, factor,
9052 el = $( this ),
9053 props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ],
9054
9055 // Always restore
9056 props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ],
9057
9058 // Copy for children
9059 props2 = [ "width", "height", "overflow" ],
9060 cProps = [ "fontSize" ],
9061 vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
9062 hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
9063
9064 // Set options
9065 mode = $.effects.setMode( el, o.mode || "effect" ),
9066 restore = o.restore || mode !== "effect",
9067 scale = o.scale || "both",
9068 origin = o.origin || [ "middle", "center" ],
9069 position = el.css( "position" ),
9070 props = restore ? props0 : props1,
9071 zero = {
9072 height: 0,
9073 width: 0,
9074 outerHeight: 0,
9075 outerWidth: 0
9076 };
9077
9078 if ( mode === "show" ) {
9079 el.show();
9080 }
9081 original = {
9082 height: el.height(),
9083 width: el.width(),
9084 outerHeight: el.outerHeight(),
9085 outerWidth: el.outerWidth()
9086 };
9087
9088 if ( o.mode === "toggle" && mode === "show" ) {
9089 el.from = o.to || zero;
9090 el.to = o.from || original;
9091 } else {
9092 el.from = o.from || ( mode === "show" ? zero : original );
9093 el.to = o.to || ( mode === "hide" ? zero : original );
9094 }
9095
9096 // Set scaling factor
9097 factor = {
9098 from: {
9099 y: el.from.height / original.height,
9100 x: el.from.width / original.width
9101 },
9102 to: {
9103 y: el.to.height / original.height,
9104 x: el.to.width / original.width
9105 }
9106 };
9107
9108 // Scale the css box
9109 if ( scale === "box" || scale === "both" ) {
9110
9111 // Vertical props scaling
9112 if ( factor.from.y !== factor.to.y ) {
9113 props = props.concat( vProps );
9114 el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
9115 el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
9116 }
9117
9118 // Horizontal props scaling
9119 if ( factor.from.x !== factor.to.x ) {
9120 props = props.concat( hProps );
9121 el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
9122 el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
9123 }
9124 }
9125
9126 // Scale the content
9127 if ( scale === "content" || scale === "both" ) {
9128
9129 // Vertical props scaling
9130 if ( factor.from.y !== factor.to.y ) {
9131 props = props.concat( cProps ).concat( props2 );
9132 el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
9133 el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
9134 }
9135 }
9136
9137 $.effects.save( el, props );
9138 el.show();
9139 $.effects.createWrapper( el );
9140 el.css( "overflow", "hidden" ).css( el.from );
9141
9142 // Adjust
9143 if (origin) { // Calculate baseline shifts
9144 baseline = $.effects.getBaseline( origin, original );
9145 el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
9146 el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
9147 el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
9148 el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
9149 }
9150 el.css( el.from ); // set top & left
9151
9152 // Animate
9153 if ( scale === "content" || scale === "both" ) { // Scale the children
9154
9155 // Add margins/font-size
9156 vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps);
9157 hProps = hProps.concat([ "marginLeft", "marginRight" ]);
9158 props2 = props0.concat(vProps).concat(hProps);
9159
9160 el.find( "*[width]" ).each( function(){
9161 var child = $( this ),
9162 c_original = {
9163 height: child.height(),
9164 width: child.width(),
9165 outerHeight: child.outerHeight(),
9166 outerWidth: child.outerWidth()
9167 };
9168 if (restore) {
9169 $.effects.save(child, props2);
9170 }
9171
9172 child.from = {
9173 height: c_original.height * factor.from.y,
9174 width: c_original.width * factor.from.x,
9175 outerHeight: c_original.outerHeight * factor.from.y,
9176 outerWidth: c_original.outerWidth * factor.from.x
9177 };
9178 child.to = {
9179 height: c_original.height * factor.to.y,
9180 width: c_original.width * factor.to.x,
9181 outerHeight: c_original.height * factor.to.y,
9182 outerWidth: c_original.width * factor.to.x
9183 };
9184
9185 // Vertical props scaling
9186 if ( factor.from.y !== factor.to.y ) {
9187 child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
9188 child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
9189 }
9190
9191 // Horizontal props scaling
9192 if ( factor.from.x !== factor.to.x ) {
9193 child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
9194 child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
9195 }
9196
9197 // Animate children
9198 child.css( child.from );
9199 child.animate( child.to, o.duration, o.easing, function() {
9200
9201 // Restore children
9202 if ( restore ) {
9203 $.effects.restore( child, props2 );
9204 }
9205 });
9206 });
9207 }
9208
9209 // Animate
9210 el.animate( el.to, {
9211 queue: false,
9212 duration: o.duration,
9213 easing: o.easing,
9214 complete: function() {
9215 if ( el.to.opacity === 0 ) {
9216 el.css( "opacity", el.from.opacity );
9217 }
9218 if( mode === "hide" ) {
9219 el.hide();
9220 }
9221 $.effects.restore( el, props );
9222 if ( !restore ) {
9223
9224 // we need to calculate our new positioning based on the scaling
9225 if ( position === "static" ) {
9226 el.css({
9227 position: "relative",
9228 top: el.to.top,
9229 left: el.to.left
9230 });
9231 } else {
9232 $.each([ "top", "left" ], function( idx, pos ) {
9233 el.css( pos, function( _, str ) {
9234 var val = parseInt( str, 10 ),
9235 toRef = idx ? el.to.left : el.to.top;
9236
9237 // if original was "auto", recalculate the new value from wrapper
9238 if ( str === "auto" ) {
9239 return toRef + "px";
9240 }
9241
9242 return val + toRef + "px";
9243 });
9244 });
9245 }
9246 }
9247
9248 $.effects.removeWrapper( el );
9249 done();
9250 }
9251 });
9252
9253 };
9254
9255 })(jQuery);
9256 (function( $, undefined ) {
9257
9258 $.effects.effect.shake = function( o, done ) {
9259
9260 var el = $( this ),
9261 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
9262 mode = $.effects.setMode( el, o.mode || "effect" ),
9263 direction = o.direction || "left",
9264 distance = o.distance || 20,
9265 times = o.times || 3,
9266 anims = times * 2 + 1,
9267 speed = Math.round(o.duration/anims),
9268 ref = (direction === "up" || direction === "down") ? "top" : "left",
9269 positiveMotion = (direction === "up" || direction === "left"),
9270 animation = {},
9271 animation1 = {},
9272 animation2 = {},
9273 i,
9274
9275 // we will need to re-assemble the queue to stack our animations in place
9276 queue = el.queue(),
9277 queuelen = queue.length;
9278
9279 $.effects.save( el, props );
9280 el.show();
9281 $.effects.createWrapper( el );
9282
9283 // Animation
9284 animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
9285 animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
9286 animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
9287
9288 // Animate
9289 el.animate( animation, speed, o.easing );
9290
9291 // Shakes
9292 for ( i = 1; i < times; i++ ) {
9293 el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing );
9294 }
9295 el
9296 .animate( animation1, speed, o.easing )
9297 .animate( animation, speed / 2, o.easing )
9298 .queue(function() {
9299 if ( mode === "hide" ) {
9300 el.hide();
9301 }
9302 $.effects.restore( el, props );
9303 $.effects.removeWrapper( el );
9304 done();
9305 });
9306
9307 // inject all the animations we just queued to be first in line (after "inprogress")
9308 if ( queuelen > 1) {
9309 queue.splice.apply( queue,
9310 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
9311 }
9312 el.dequeue();
9313
9314 };
9315
9316 })(jQuery);
9317 (function( $, undefined ) {
9318
9319 $.effects.effect.slide = function( o, done ) {
9320
9321 // Create element
9322 var el = $( this ),
9323 props = [ "position", "top", "bottom", "left", "right", "width", "height" ],
9324 mode = $.effects.setMode( el, o.mode || "show" ),
9325 show = mode === "show",
9326 direction = o.direction || "left",
9327 ref = (direction === "up" || direction === "down") ? "top" : "left",
9328 positiveMotion = (direction === "up" || direction === "left"),
9329 distance,
9330 animation = {};
9331
9332 // Adjust
9333 $.effects.save( el, props );
9334 el.show();
9335 distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true );
9336
9337 $.effects.createWrapper( el ).css({
9338 overflow: "hidden"
9339 });
9340
9341 if ( show ) {
9342 el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance );
9343 }
9344
9345 // Animation
9346 animation[ ref ] = ( show ?
9347 ( positiveMotion ? "+=" : "-=") :
9348 ( positiveMotion ? "-=" : "+=")) +
9349 distance;
9350
9351 // Animate
9352 el.animate( animation, {
9353 queue: false,
9354 duration: o.duration,
9355 easing: o.easing,
9356 complete: function() {
9357 if ( mode === "hide" ) {
9358 el.hide();
9359 }
9360 $.effects.restore( el, props );
9361 $.effects.removeWrapper( el );
9362 done();
9363 }
9364 });
9365 };
9366
9367 })(jQuery);
9368 (function( $, undefined ) {
9369
9370 $.effects.effect.transfer = function( o, done ) {
9371 var elem = $( this ),
9372 target = $( o.to ),
9373 targetFixed = target.css( "position" ) === "fixed",
9374 body = $("body"),
9375 fixTop = targetFixed ? body.scrollTop() : 0,
9376 fixLeft = targetFixed ? body.scrollLeft() : 0,
9377 endPosition = target.offset(),
9378 animation = {
9379 top: endPosition.top - fixTop ,
9380 left: endPosition.left - fixLeft ,
9381 height: target.innerHeight(),
9382 width: target.innerWidth()
9383 },
9384 startPosition = elem.offset(),
9385 transfer = $( "<div class='ui-effects-transfer'></div>" )
9386 .appendTo( document.body )
9387 .addClass( o.className )
9388 .css({
9389 top: startPosition.top - fixTop ,
9390 left: startPosition.left - fixLeft ,
9391 height: elem.innerHeight(),
9392 width: elem.innerWidth(),
9393 position: targetFixed ? "fixed" : "absolute"
9394 })
9395 .animate( animation, o.duration, o.easing, function() {
9396 transfer.remove();
9397 done();
9398 });
9399 };
9400
9401 })(jQuery);
9402 (function( $, undefined ) {
9403
9404 $.widget( "ui.menu", {
9405 version: "1.10.4",
9406 defaultElement: "<ul>",
9407 delay: 300,
9408 options: {
9409 icons: {
9410 submenu: "ui-icon-carat-1-e"
9411 },
9412 menus: "ul",
9413 position: {
9414 my: "left top",
9415 at: "right top"
9416 },
9417 role: "menu",
9418
9419 // callbacks
9420 blur: null,
9421 focus: null,
9422 select: null
9423 },
9424
9425 _create: function() {
9426 this.activeMenu = this.element;
9427 // flag used to prevent firing of the click handler
9428 // as the event bubbles up through nested menus
9429 this.mouseHandled = false;
9430 this.element
9431 .uniqueId()
9432 .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
9433 .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
9434 .attr({
9435 role: this.options.role,
9436 tabIndex: 0
9437 })
9438 // need to catch all clicks on disabled menu
9439 // not possible through _on
9440 .bind( "click" + this.eventNamespace, $.proxy(function( event ) {
9441 if ( this.options.disabled ) {
9442 event.preventDefault();
9443 }
9444 }, this ));
9445
9446 if ( this.options.disabled ) {
9447 this.element
9448 .addClass( "ui-state-disabled" )
9449 .attr( "aria-disabled", "true" );
9450 }
9451
9452 this._on({
9453 // Prevent focus from sticking to links inside menu after clicking
9454 // them (focus should always stay on UL during navigation).
9455 "mousedown .ui-menu-item > a": function( event ) {
9456 event.preventDefault();
9457 },
9458 "click .ui-state-disabled > a": function( event ) {
9459 event.preventDefault();
9460 },
9461 "click .ui-menu-item:has(a)": function( event ) {
9462 var target = $( event.target ).closest( ".ui-menu-item" );
9463 if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
9464 this.select( event );
9465
9466 // Only set the mouseHandled flag if the event will bubble, see #9469.
9467 if ( !event.isPropagationStopped() ) {
9468 this.mouseHandled = true;
9469 }
9470
9471 // Open submenu on click
9472 if ( target.has( ".ui-menu" ).length ) {
9473 this.expand( event );
9474 } else if ( !this.element.is( ":focus" ) && $( this.document[ 0 ].activeElement ).closest( ".ui-menu" ).length ) {
9475
9476 // Redirect focus to the menu
9477 this.element.trigger( "focus", [ true ] );
9478
9479 // If the active item is on the top level, let it stay active.
9480 // Otherwise, blur the active item since it is no longer visible.
9481 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
9482 clearTimeout( this.timer );
9483 }
9484 }
9485 }
9486 },
9487 "mouseenter .ui-menu-item": function( event ) {
9488 var target = $( event.currentTarget );
9489 // Remove ui-state-active class from siblings of the newly focused menu item
9490 // to avoid a jump caused by adjacent elements both having a class with a border
9491 target.siblings().children( ".ui-state-active" ).removeClass( "ui-state-active" );
9492 this.focus( event, target );
9493 },
9494 mouseleave: "collapseAll",
9495 "mouseleave .ui-menu": "collapseAll",
9496 focus: function( event, keepActiveItem ) {
9497 // If there's already an active item, keep it active
9498 // If not, activate the first item
9499 var item = this.active || this.element.children( ".ui-menu-item" ).eq( 0 );
9500
9501 if ( !keepActiveItem ) {
9502 this.focus( event, item );
9503 }
9504 },
9505 blur: function( event ) {
9506 this._delay(function() {
9507 if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
9508 this.collapseAll( event );
9509 }
9510 });
9511 },
9512 keydown: "_keydown"
9513 });
9514
9515 this.refresh();
9516
9517 // Clicks outside of a menu collapse any open menus
9518 this._on( this.document, {
9519 click: function( event ) {
9520 if ( !$( event.target ).closest( ".ui-menu" ).length ) {
9521 this.collapseAll( event );
9522 }
9523
9524 // Reset the mouseHandled flag
9525 this.mouseHandled = false;
9526 }
9527 });
9528 },
9529
9530 _destroy: function() {
9531 // Destroy (sub)menus
9532 this.element
9533 .removeAttr( "aria-activedescendant" )
9534 .find( ".ui-menu" ).addBack()
9535 .removeClass( "ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons" )
9536 .removeAttr( "role" )
9537 .removeAttr( "tabIndex" )
9538 .removeAttr( "aria-labelledby" )
9539 .removeAttr( "aria-expanded" )
9540 .removeAttr( "aria-hidden" )
9541 .removeAttr( "aria-disabled" )
9542 .removeUniqueId()
9543 .show();
9544
9545 // Destroy menu items
9546 this.element.find( ".ui-menu-item" )
9547 .removeClass( "ui-menu-item" )
9548 .removeAttr( "role" )
9549 .removeAttr( "aria-disabled" )
9550 .children( "a" )
9551 .removeUniqueId()
9552 .removeClass( "ui-corner-all ui-state-hover" )
9553 .removeAttr( "tabIndex" )
9554 .removeAttr( "role" )
9555 .removeAttr( "aria-haspopup" )
9556 .children().each( function() {
9557 var elem = $( this );
9558 if ( elem.data( "ui-menu-submenu-carat" ) ) {
9559 elem.remove();
9560 }
9561 });
9562
9563 // Destroy menu dividers
9564 this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
9565 },
9566
9567 _keydown: function( event ) {
9568 var match, prev, character, skip, regex,
9569 preventDefault = true;
9570
9571 function escape( value ) {
9572 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
9573 }
9574
9575 switch ( event.keyCode ) {
9576 case $.ui.keyCode.PAGE_UP:
9577 this.previousPage( event );
9578 break;
9579 case $.ui.keyCode.PAGE_DOWN:
9580 this.nextPage( event );
9581 break;
9582 case $.ui.keyCode.HOME:
9583 this._move( "first", "first", event );
9584 break;
9585 case $.ui.keyCode.END:
9586 this._move( "last", "last", event );
9587 break;
9588 case $.ui.keyCode.UP:
9589 this.previous( event );
9590 break;
9591 case $.ui.keyCode.DOWN:
9592 this.next( event );
9593 break;
9594 case $.ui.keyCode.LEFT:
9595 this.collapse( event );
9596 break;
9597 case $.ui.keyCode.RIGHT:
9598 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
9599 this.expand( event );
9600 }
9601 break;
9602 case $.ui.keyCode.ENTER:
9603 case $.ui.keyCode.SPACE:
9604 this._activate( event );
9605 break;
9606 case $.ui.keyCode.ESCAPE:
9607 this.collapse( event );
9608 break;
9609 default:
9610 preventDefault = false;
9611 prev = this.previousFilter || "";
9612 character = String.fromCharCode( event.keyCode );
9613 skip = false;
9614
9615 clearTimeout( this.filterTimer );
9616
9617 if ( character === prev ) {
9618 skip = true;
9619 } else {
9620 character = prev + character;
9621 }
9622
9623 regex = new RegExp( "^" + escape( character ), "i" );
9624 match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
9625 return regex.test( $( this ).children( "a" ).text() );
9626 });
9627 match = skip && match.index( this.active.next() ) !== -1 ?
9628 this.active.nextAll( ".ui-menu-item" ) :
9629 match;
9630
9631 // If no matches on the current filter, reset to the last character pressed
9632 // to move down the menu to the first item that starts with that character
9633 if ( !match.length ) {
9634 character = String.fromCharCode( event.keyCode );
9635 regex = new RegExp( "^" + escape( character ), "i" );
9636 match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
9637 return regex.test( $( this ).children( "a" ).text() );
9638 });
9639 }
9640
9641 if ( match.length ) {
9642 this.focus( event, match );
9643 if ( match.length > 1 ) {
9644 this.previousFilter = character;
9645 this.filterTimer = this._delay(function() {
9646 delete this.previousFilter;
9647 }, 1000 );
9648 } else {
9649 delete this.previousFilter;
9650 }
9651 } else {
9652 delete this.previousFilter;
9653 }
9654 }
9655
9656 if ( preventDefault ) {
9657 event.preventDefault();
9658 }
9659 },
9660
9661 _activate: function( event ) {
9662 if ( !this.active.is( ".ui-state-disabled" ) ) {
9663 if ( this.active.children( "a[aria-haspopup='true']" ).length ) {
9664 this.expand( event );
9665 } else {
9666 this.select( event );
9667 }
9668 }
9669 },
9670
9671 refresh: function() {
9672 var menus,
9673 icon = this.options.icons.submenu,
9674 submenus = this.element.find( this.options.menus );
9675
9676 this.element.toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length );
9677
9678 // Initialize nested menus
9679 submenus.filter( ":not(.ui-menu)" )
9680 .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
9681 .hide()
9682 .attr({
9683 role: this.options.role,
9684 "aria-hidden": "true",
9685 "aria-expanded": "false"
9686 })
9687 .each(function() {
9688 var menu = $( this ),
9689 item = menu.prev( "a" ),
9690 submenuCarat = $( "<span>" )
9691 .addClass( "ui-menu-icon ui-icon " + icon )
9692 .data( "ui-menu-submenu-carat", true );
9693
9694 item
9695 .attr( "aria-haspopup", "true" )
9696 .prepend( submenuCarat );
9697 menu.attr( "aria-labelledby", item.attr( "id" ) );
9698 });
9699
9700 menus = submenus.add( this.element );
9701
9702 // Don't refresh list items that are already adapted
9703 menus.children( ":not(.ui-menu-item):has(a)" )
9704 .addClass( "ui-menu-item" )
9705 .attr( "role", "presentation" )
9706 .children( "a" )
9707 .uniqueId()
9708 .addClass( "ui-corner-all" )
9709 .attr({
9710 tabIndex: -1,
9711 role: this._itemRole()
9712 });
9713
9714 // Initialize unlinked menu-items containing spaces and/or dashes only as dividers
9715 menus.children( ":not(.ui-menu-item)" ).each(function() {
9716 var item = $( this );
9717 // hyphen, em dash, en dash
9718 if ( !/[^\-\u2014\u2013\s]/.test( item.text() ) ) {
9719 item.addClass( "ui-widget-content ui-menu-divider" );
9720 }
9721 });
9722
9723 // Add aria-disabled attribute to any disabled menu item
9724 menus.children( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
9725
9726 // If the active item has been removed, blur the menu
9727 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
9728 this.blur();
9729 }
9730 },
9731
9732 _itemRole: function() {
9733 return {
9734 menu: "menuitem",
9735 listbox: "option"
9736 }[ this.options.role ];
9737 },
9738
9739 _setOption: function( key, value ) {
9740 if ( key === "icons" ) {
9741 this.element.find( ".ui-menu-icon" )
9742 .removeClass( this.options.icons.submenu )
9743 .addClass( value.submenu );
9744 }
9745 this._super( key, value );
9746 },
9747
9748 focus: function( event, item ) {
9749 var nested, focused;
9750 this.blur( event, event && event.type === "focus" );
9751
9752 this._scrollIntoView( item );
9753
9754 this.active = item.first();
9755 focused = this.active.children( "a" ).addClass( "ui-state-focus" );
9756 // Only update aria-activedescendant if there's a role
9757 // otherwise we assume focus is managed elsewhere
9758 if ( this.options.role ) {
9759 this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
9760 }
9761
9762 // Highlight active parent menu item, if any
9763 this.active
9764 .parent()
9765 .closest( ".ui-menu-item" )
9766 .children( "a:first" )
9767 .addClass( "ui-state-active" );
9768
9769 if ( event && event.type === "keydown" ) {
9770 this._close();
9771 } else {
9772 this.timer = this._delay(function() {
9773 this._close();
9774 }, this.delay );
9775 }
9776
9777 nested = item.children( ".ui-menu" );
9778 if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
9779 this._startOpening(nested);
9780 }
9781 this.activeMenu = item.parent();
9782
9783 this._trigger( "focus", event, { item: item } );
9784 },
9785
9786 _scrollIntoView: function( item ) {
9787 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
9788 if ( this._hasScroll() ) {
9789 borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
9790 paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
9791 offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
9792 scroll = this.activeMenu.scrollTop();
9793 elementHeight = this.activeMenu.height();
9794 itemHeight = item.height();
9795
9796 if ( offset < 0 ) {
9797 this.activeMenu.scrollTop( scroll + offset );
9798 } else if ( offset + itemHeight > elementHeight ) {
9799 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
9800 }
9801 }
9802 },
9803
9804 blur: function( event, fromFocus ) {
9805 if ( !fromFocus ) {
9806 clearTimeout( this.timer );
9807 }
9808
9809 if ( !this.active ) {
9810 return;
9811 }
9812
9813 this.active.children( "a" ).removeClass( "ui-state-focus" );
9814 this.active = null;
9815
9816 this._trigger( "blur", event, { item: this.active } );
9817 },
9818
9819 _startOpening: function( submenu ) {
9820 clearTimeout( this.timer );
9821
9822 // Don't open if already open fixes a Firefox bug that caused a .5 pixel
9823 // shift in the submenu position when mousing over the carat icon
9824 if ( submenu.attr( "aria-hidden" ) !== "true" ) {
9825 return;
9826 }
9827
9828 this.timer = this._delay(function() {
9829 this._close();
9830 this._open( submenu );
9831 }, this.delay );
9832 },
9833
9834 _open: function( submenu ) {
9835 var position = $.extend({
9836 of: this.active
9837 }, this.options.position );
9838
9839 clearTimeout( this.timer );
9840 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
9841 .hide()
9842 .attr( "aria-hidden", "true" );
9843
9844 submenu
9845 .show()
9846 .removeAttr( "aria-hidden" )
9847 .attr( "aria-expanded", "true" )
9848 .position( position );
9849 },
9850
9851 collapseAll: function( event, all ) {
9852 clearTimeout( this.timer );
9853 this.timer = this._delay(function() {
9854 // If we were passed an event, look for the submenu that contains the event
9855 var currentMenu = all ? this.element :
9856 $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
9857
9858 // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
9859 if ( !currentMenu.length ) {
9860 currentMenu = this.element;
9861 }
9862
9863 this._close( currentMenu );
9864
9865 this.blur( event );
9866 this.activeMenu = currentMenu;
9867 }, this.delay );
9868 },
9869
9870 // With no arguments, closes the currently active menu - if nothing is active
9871 // it closes all menus. If passed an argument, it will search for menus BELOW
9872 _close: function( startMenu ) {
9873 if ( !startMenu ) {
9874 startMenu = this.active ? this.active.parent() : this.element;
9875 }
9876
9877 startMenu
9878 .find( ".ui-menu" )
9879 .hide()
9880 .attr( "aria-hidden", "true" )
9881 .attr( "aria-expanded", "false" )
9882 .end()
9883 .find( "a.ui-state-active" )
9884 .removeClass( "ui-state-active" );
9885 },
9886
9887 collapse: function( event ) {
9888 var newItem = this.active &&
9889 this.active.parent().closest( ".ui-menu-item", this.element );
9890 if ( newItem && newItem.length ) {
9891 this._close();
9892 this.focus( event, newItem );
9893 }
9894 },
9895
9896 expand: function( event ) {
9897 var newItem = this.active &&
9898 this.active
9899 .children( ".ui-menu " )
9900 .children( ".ui-menu-item" )
9901 .first();
9902
9903 if ( newItem && newItem.length ) {
9904 this._open( newItem.parent() );
9905
9906 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
9907 this._delay(function() {
9908 this.focus( event, newItem );
9909 });
9910 }
9911 },
9912
9913 next: function( event ) {
9914 this._move( "next", "first", event );
9915 },
9916
9917 previous: function( event ) {
9918 this._move( "prev", "last", event );
9919 },
9920
9921 isFirstItem: function() {
9922 return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
9923 },
9924
9925 isLastItem: function() {
9926 return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
9927 },
9928
9929 _move: function( direction, filter, event ) {
9930 var next;
9931 if ( this.active ) {
9932 if ( direction === "first" || direction === "last" ) {
9933 next = this.active
9934 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
9935 .eq( -1 );
9936 } else {
9937 next = this.active
9938 [ direction + "All" ]( ".ui-menu-item" )
9939 .eq( 0 );
9940 }
9941 }
9942 if ( !next || !next.length || !this.active ) {
9943 next = this.activeMenu.children( ".ui-menu-item" )[ filter ]();
9944 }
9945
9946 this.focus( event, next );
9947 },
9948
9949 nextPage: function( event ) {
9950 var item, base, height;
9951
9952 if ( !this.active ) {
9953 this.next( event );
9954 return;
9955 }
9956 if ( this.isLastItem() ) {
9957 return;
9958 }
9959 if ( this._hasScroll() ) {
9960 base = this.active.offset().top;
9961 height = this.element.height();
9962 this.active.nextAll( ".ui-menu-item" ).each(function() {
9963 item = $( this );
9964 return item.offset().top - base - height < 0;
9965 });
9966
9967 this.focus( event, item );
9968 } else {
9969 this.focus( event, this.activeMenu.children( ".ui-menu-item" )
9970 [ !this.active ? "first" : "last" ]() );
9971 }
9972 },
9973
9974 previousPage: function( event ) {
9975 var item, base, height;
9976 if ( !this.active ) {
9977 this.next( event );
9978 return;
9979 }
9980 if ( this.isFirstItem() ) {
9981 return;
9982 }
9983 if ( this._hasScroll() ) {
9984 base = this.active.offset().top;
9985 height = this.element.height();
9986 this.active.prevAll( ".ui-menu-item" ).each(function() {
9987 item = $( this );
9988 return item.offset().top - base + height > 0;
9989 });
9990
9991 this.focus( event, item );
9992 } else {
9993 this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
9994 }
9995 },
9996
9997 _hasScroll: function() {
9998 return this.element.outerHeight() < this.element.prop( "scrollHeight" );
9999 },
10000
10001 select: function( event ) {
10002 // TODO: It should never be possible to not have an active item at this
10003 // point, but the tests don't trigger mouseenter before click.
10004 this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
10005 var ui = { item: this.active };
10006 if ( !this.active.has( ".ui-menu" ).length ) {
10007 this.collapseAll( event, true );
10008 }
10009 this._trigger( "select", event, ui );
10010 }
10011 });
10012
10013 }( jQuery ));
10014 (function( $, undefined ) {
10015
10016 $.widget( "ui.progressbar", {
10017 version: "1.10.4",
10018 options: {
10019 max: 100,
10020 value: 0,
10021
10022 change: null,
10023 complete: null
10024 },
10025
10026 min: 0,
10027
10028 _create: function() {
10029 // Constrain initial value
10030 this.oldValue = this.options.value = this._constrainedValue();
10031
10032 this.element
10033 .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
10034 .attr({
10035 // Only set static values, aria-valuenow and aria-valuemax are
10036 // set inside _refreshValue()
10037 role: "progressbar",
10038 "aria-valuemin": this.min
10039 });
10040
10041 this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
10042 .appendTo( this.element );
10043
10044 this._refreshValue();
10045 },
10046
10047 _destroy: function() {
10048 this.element
10049 .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
10050 .removeAttr( "role" )
10051 .removeAttr( "aria-valuemin" )
10052 .removeAttr( "aria-valuemax" )
10053 .removeAttr( "aria-valuenow" );
10054
10055 this.valueDiv.remove();
10056 },
10057
10058 value: function( newValue ) {
10059 if ( newValue === undefined ) {
10060 return this.options.value;
10061 }
10062
10063 this.options.value = this._constrainedValue( newValue );
10064 this._refreshValue();
10065 },
10066
10067 _constrainedValue: function( newValue ) {
10068 if ( newValue === undefined ) {
10069 newValue = this.options.value;
10070 }
10071
10072 this.indeterminate = newValue === false;
10073
10074 // sanitize value
10075 if ( typeof newValue !== "number" ) {
10076 newValue = 0;
10077 }
10078
10079 return this.indeterminate ? false :
10080 Math.min( this.options.max, Math.max( this.min, newValue ) );
10081 },
10082
10083 _setOptions: function( options ) {
10084 // Ensure "value" option is set after other values (like max)
10085 var value = options.value;
10086 delete options.value;
10087
10088 this._super( options );
10089
10090 this.options.value = this._constrainedValue( value );
10091 this._refreshValue();
10092 },
10093
10094 _setOption: function( key, value ) {
10095 if ( key === "max" ) {
10096 // Don't allow a max less than min
10097 value = Math.max( this.min, value );
10098 }
10099
10100 this._super( key, value );
10101 },
10102
10103 _percentage: function() {
10104 return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
10105 },
10106
10107 _refreshValue: function() {
10108 var value = this.options.value,
10109 percentage = this._percentage();
10110
10111 this.valueDiv
10112 .toggle( this.indeterminate || value > this.min )
10113 .toggleClass( "ui-corner-right", value === this.options.max )
10114 .width( percentage.toFixed(0) + "%" );
10115
10116 this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate );
10117
10118 if ( this.indeterminate ) {
10119 this.element.removeAttr( "aria-valuenow" );
10120 if ( !this.overlayDiv ) {
10121 this.overlayDiv = $( "<div class='ui-progressbar-overlay'></div>" ).appendTo( this.valueDiv );
10122 }
10123 } else {
10124 this.element.attr({
10125 "aria-valuemax": this.options.max,
10126 "aria-valuenow": value
10127 });
10128 if ( this.overlayDiv ) {
10129 this.overlayDiv.remove();
10130 this.overlayDiv = null;
10131 }
10132 }
10133
10134 if ( this.oldValue !== value ) {
10135 this.oldValue = value;
10136 this._trigger( "change" );
10137 }
10138 if ( value === this.options.max ) {
10139 this._trigger( "complete" );
10140 }
10141 }
10142 });
10143
10144 })( jQuery );
10145 (function( $, undefined ) {
10146
10147 function num(v) {
10148 return parseInt(v, 10) || 0;
10149 }
10150
10151 function isNumber(value) {
10152 return !isNaN(parseInt(value, 10));
10153 }
10154
10155 $.widget("ui.resizable", $.ui.mouse, {
10156 version: "1.10.4",
10157 widgetEventPrefix: "resize",
10158 options: {
10159 alsoResize: false,
10160 animate: false,
10161 animateDuration: "slow",
10162 animateEasing: "swing",
10163 aspectRatio: false,
10164 autoHide: false,
10165 containment: false,
10166 ghost: false,
10167 grid: false,
10168 handles: "e,s,se",
10169 helper: false,
10170 maxHeight: null,
10171 maxWidth: null,
10172 minHeight: 10,
10173 minWidth: 10,
10174 // See #7960
10175 zIndex: 90,
10176
10177 // callbacks
10178 resize: null,
10179 start: null,
10180 stop: null
10181 },
10182 _create: function() {
10183
10184 var n, i, handle, axis, hname,
10185 that = this,
10186 o = this.options;
10187 this.element.addClass("ui-resizable");
10188
10189 $.extend(this, {
10190 _aspectRatio: !!(o.aspectRatio),
10191 aspectRatio: o.aspectRatio,
10192 originalElement: this.element,
10193 _proportionallyResizeElements: [],
10194 _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
10195 });
10196
10197 //Wrap the element if it cannot hold child nodes
10198 if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {
10199
10200 //Create a wrapper element and set the wrapper to the new current internal element
10201 this.element.wrap(
10202 $("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({
10203 position: this.element.css("position"),
10204 width: this.element.outerWidth(),
10205 height: this.element.outerHeight(),
10206 top: this.element.css("top"),
10207 left: this.element.css("left")
10208 })
10209 );
10210
10211 //Overwrite the original this.element
10212 this.element = this.element.parent().data(
10213 "ui-resizable", this.element.data("ui-resizable")
10214 );
10215
10216 this.elementIsWrapper = true;
10217
10218 //Move margins to the wrapper
10219 this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") });
10220 this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});
10221
10222 //Prevent Safari textarea resize
10223 this.originalResizeStyle = this.originalElement.css("resize");
10224 this.originalElement.css("resize", "none");
10225
10226 //Push the actual element to our proportionallyResize internal array
10227 this._proportionallyResizeElements.push(this.originalElement.css({ position: "static", zoom: 1, display: "block" }));
10228
10229 // avoid IE jump (hard set the margin)
10230 this.originalElement.css({ margin: this.originalElement.css("margin") });
10231
10232 // fix handlers offset
10233 this._proportionallyResize();
10234
10235 }
10236
10237 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" });
10238 if(this.handles.constructor === String) {
10239
10240 if ( this.handles === "all") {
10241 this.handles = "n,e,s,w,se,sw,ne,nw";
10242 }
10243
10244 n = this.handles.split(",");
10245 this.handles = {};
10246
10247 for(i = 0; i < n.length; i++) {
10248
10249 handle = $.trim(n[i]);
10250 hname = "ui-resizable-"+handle;
10251 axis = $("<div class='ui-resizable-handle " + hname + "'></div>");
10252
10253 // Apply zIndex to all handles - see #7960
10254 axis.css({ zIndex: o.zIndex });
10255
10256 //TODO : What's going on here?
10257 if ("se" === handle) {
10258 axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se");
10259 }
10260
10261 //Insert into internal handles object and append to element
10262 this.handles[handle] = ".ui-resizable-"+handle;
10263 this.element.append(axis);
10264 }
10265
10266 }
10267
10268 this._renderAxis = function(target) {
10269
10270 var i, axis, padPos, padWrapper;
10271
10272 target = target || this.element;
10273
10274 for(i in this.handles) {
10275
10276 if(this.handles[i].constructor === String) {
10277 this.handles[i] = $(this.handles[i], this.element).show();
10278 }
10279
10280 //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)
10281 if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {
10282
10283 axis = $(this.handles[i], this.element);
10284
10285 //Checking the correct pad and border
10286 padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
10287
10288 //The padding type i have to apply...
10289 padPos = [ "padding",
10290 /ne|nw|n/.test(i) ? "Top" :
10291 /se|sw|s/.test(i) ? "Bottom" :
10292 /^e$/.test(i) ? "Right" : "Left" ].join("");
10293
10294 target.css(padPos, padWrapper);
10295
10296 this._proportionallyResize();
10297
10298 }
10299
10300 //TODO: What's that good for? There's not anything to be executed left
10301 if(!$(this.handles[i]).length) {
10302 continue;
10303 }
10304 }
10305 };
10306
10307 //TODO: make renderAxis a prototype function
10308 this._renderAxis(this.element);
10309
10310 this._handles = $(".ui-resizable-handle", this.element)
10311 .disableSelection();
10312
10313 //Matching axis name
10314 this._handles.mouseover(function() {
10315 if (!that.resizing) {
10316 if (this.className) {
10317 axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
10318 }
10319 //Axis, default = se
10320 that.axis = axis && axis[1] ? axis[1] : "se";
10321 }
10322 });
10323
10324 //If we want to auto hide the elements
10325 if (o.autoHide) {
10326 this._handles.hide();
10327 $(this.element)
10328 .addClass("ui-resizable-autohide")
10329 .mouseenter(function() {
10330 if (o.disabled) {
10331 return;
10332 }
10333 $(this).removeClass("ui-resizable-autohide");
10334 that._handles.show();
10335 })
10336 .mouseleave(function(){
10337 if (o.disabled) {
10338 return;
10339 }
10340 if (!that.resizing) {
10341 $(this).addClass("ui-resizable-autohide");
10342 that._handles.hide();
10343 }
10344 });
10345 }
10346
10347 //Initialize the mouse interaction
10348 this._mouseInit();
10349
10350 },
10351
10352 _destroy: function() {
10353
10354 this._mouseDestroy();
10355
10356 var wrapper,
10357 _destroy = function(exp) {
10358 $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
10359 .removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove();
10360 };
10361
10362 //TODO: Unwrap at same DOM position
10363 if (this.elementIsWrapper) {
10364 _destroy(this.element);
10365 wrapper = this.element;
10366 this.originalElement.css({
10367 position: wrapper.css("position"),
10368 width: wrapper.outerWidth(),
10369 height: wrapper.outerHeight(),
10370 top: wrapper.css("top"),
10371 left: wrapper.css("left")
10372 }).insertAfter( wrapper );
10373 wrapper.remove();
10374 }
10375
10376 this.originalElement.css("resize", this.originalResizeStyle);
10377 _destroy(this.originalElement);
10378
10379 return this;
10380 },
10381
10382 _mouseCapture: function(event) {
10383 var i, handle,
10384 capture = false;
10385
10386 for (i in this.handles) {
10387 handle = $(this.handles[i])[0];
10388 if (handle === event.target || $.contains(handle, event.target)) {
10389 capture = true;
10390 }
10391 }
10392
10393 return !this.options.disabled && capture;
10394 },
10395
10396 _mouseStart: function(event) {
10397
10398 var curleft, curtop, cursor,
10399 o = this.options,
10400 iniPos = this.element.position(),
10401 el = this.element;
10402
10403 this.resizing = true;
10404
10405 // bugfix for http://dev.jquery.com/ticket/1749
10406 if ( (/absolute/).test( el.css("position") ) ) {
10407 el.css({ position: "absolute", top: el.css("top"), left: el.css("left") });
10408 } else if (el.is(".ui-draggable")) {
10409 el.css({ position: "absolute", top: iniPos.top, left: iniPos.left });
10410 }
10411
10412 this._renderProxy();
10413
10414 curleft = num(this.helper.css("left"));
10415 curtop = num(this.helper.css("top"));
10416
10417 if (o.containment) {
10418 curleft += $(o.containment).scrollLeft() || 0;
10419 curtop += $(o.containment).scrollTop() || 0;
10420 }
10421
10422 //Store needed variables
10423 this.offset = this.helper.offset();
10424 this.position = { left: curleft, top: curtop };
10425 this.size = this._helper ? { width: this.helper.width(), height: this.helper.height() } : { width: el.width(), height: el.height() };
10426 this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
10427 this.originalPosition = { left: curleft, top: curtop };
10428 this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };
10429 this.originalMousePosition = { left: event.pageX, top: event.pageY };
10430
10431 //Aspect Ratio
10432 this.aspectRatio = (typeof o.aspectRatio === "number") ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1);
10433
10434 cursor = $(".ui-resizable-" + this.axis).css("cursor");
10435 $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor);
10436
10437 el.addClass("ui-resizable-resizing");
10438 this._propagate("start", event);
10439 return true;
10440 },
10441
10442 _mouseDrag: function(event) {
10443
10444 //Increase performance, avoid regex
10445 var data,
10446 el = this.helper, props = {},
10447 smp = this.originalMousePosition,
10448 a = this.axis,
10449 prevTop = this.position.top,
10450 prevLeft = this.position.left,
10451 prevWidth = this.size.width,
10452 prevHeight = this.size.height,
10453 dx = (event.pageX-smp.left)||0,
10454 dy = (event.pageY-smp.top)||0,
10455 trigger = this._change[a];
10456
10457 if (!trigger) {
10458 return false;
10459 }
10460
10461 // Calculate the attrs that will be change
10462 data = trigger.apply(this, [event, dx, dy]);
10463
10464 // Put this in the mouseDrag handler since the user can start pressing shift while resizing
10465 this._updateVirtualBoundaries(event.shiftKey);
10466 if (this._aspectRatio || event.shiftKey) {
10467 data = this._updateRatio(data, event);
10468 }
10469
10470 data = this._respectSize(data, event);
10471
10472 this._updateCache(data);
10473
10474 // plugins callbacks need to be called first
10475 this._propagate("resize", event);
10476
10477 if (this.position.top !== prevTop) {
10478 props.top = this.position.top + "px";
10479 }
10480 if (this.position.left !== prevLeft) {
10481 props.left = this.position.left + "px";
10482 }
10483 if (this.size.width !== prevWidth) {
10484 props.width = this.size.width + "px";
10485 }
10486 if (this.size.height !== prevHeight) {
10487 props.height = this.size.height + "px";
10488 }
10489 el.css(props);
10490
10491 if (!this._helper && this._proportionallyResizeElements.length) {
10492 this._proportionallyResize();
10493 }
10494
10495 // Call the user callback if the element was resized
10496 if ( ! $.isEmptyObject(props) ) {
10497 this._trigger("resize", event, this.ui());
10498 }
10499
10500 return false;
10501 },
10502
10503 _mouseStop: function(event) {
10504
10505 this.resizing = false;
10506 var pr, ista, soffseth, soffsetw, s, left, top,
10507 o = this.options, that = this;
10508
10509 if(this._helper) {
10510
10511 pr = this._proportionallyResizeElements;
10512 ista = pr.length && (/textarea/i).test(pr[0].nodeName);
10513 soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height;
10514 soffsetw = ista ? 0 : that.sizeDiff.width;
10515
10516 s = { width: (that.helper.width() - soffsetw), height: (that.helper.height() - soffseth) };
10517 left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null;
10518 top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null;
10519
10520 if (!o.animate) {
10521 this.element.css($.extend(s, { top: top, left: left }));
10522 }
10523
10524 that.helper.height(that.size.height);
10525 that.helper.width(that.size.width);
10526
10527 if (this._helper && !o.animate) {
10528 this._proportionallyResize();
10529 }
10530 }
10531
10532 $("body").css("cursor", "auto");
10533
10534 this.element.removeClass("ui-resizable-resizing");
10535
10536 this._propagate("stop", event);
10537
10538 if (this._helper) {
10539 this.helper.remove();
10540 }
10541
10542 return false;
10543
10544 },
10545
10546 _updateVirtualBoundaries: function(forceAspectRatio) {
10547 var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
10548 o = this.options;
10549
10550 b = {
10551 minWidth: isNumber(o.minWidth) ? o.minWidth : 0,
10552 maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity,
10553 minHeight: isNumber(o.minHeight) ? o.minHeight : 0,
10554 maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity
10555 };
10556
10557 if(this._aspectRatio || forceAspectRatio) {
10558 // We want to create an enclosing box whose aspect ration is the requested one
10559 // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension
10560 pMinWidth = b.minHeight * this.aspectRatio;
10561 pMinHeight = b.minWidth / this.aspectRatio;
10562 pMaxWidth = b.maxHeight * this.aspectRatio;
10563 pMaxHeight = b.maxWidth / this.aspectRatio;
10564
10565 if(pMinWidth > b.minWidth) {
10566 b.minWidth = pMinWidth;
10567 }
10568 if(pMinHeight > b.minHeight) {
10569 b.minHeight = pMinHeight;
10570 }
10571 if(pMaxWidth < b.maxWidth) {
10572 b.maxWidth = pMaxWidth;
10573 }
10574 if(pMaxHeight < b.maxHeight) {
10575 b.maxHeight = pMaxHeight;
10576 }
10577 }
10578 this._vBoundaries = b;
10579 },
10580
10581 _updateCache: function(data) {
10582 this.offset = this.helper.offset();
10583 if (isNumber(data.left)) {
10584 this.position.left = data.left;
10585 }
10586 if (isNumber(data.top)) {
10587 this.position.top = data.top;
10588 }
10589 if (isNumber(data.height)) {
10590 this.size.height = data.height;
10591 }
10592 if (isNumber(data.width)) {
10593 this.size.width = data.width;
10594 }
10595 },
10596
10597 _updateRatio: function( data ) {
10598
10599 var cpos = this.position,
10600 csize = this.size,
10601 a = this.axis;
10602
10603 if (isNumber(data.height)) {
10604 data.width = (data.height * this.aspectRatio);
10605 } else if (isNumber(data.width)) {
10606 data.height = (data.width / this.aspectRatio);
10607 }
10608
10609 if (a === "sw") {
10610 data.left = cpos.left + (csize.width - data.width);
10611 data.top = null;
10612 }
10613 if (a === "nw") {
10614 data.top = cpos.top + (csize.height - data.height);
10615 data.left = cpos.left + (csize.width - data.width);
10616 }
10617
10618 return data;
10619 },
10620
10621 _respectSize: function( data ) {
10622
10623 var o = this._vBoundaries,
10624 a = this.axis,
10625 ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
10626 isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height),
10627 dw = this.originalPosition.left + this.originalSize.width,
10628 dh = this.position.top + this.size.height,
10629 cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
10630 if (isminw) {
10631 data.width = o.minWidth;
10632 }
10633 if (isminh) {
10634 data.height = o.minHeight;
10635 }
10636 if (ismaxw) {
10637 data.width = o.maxWidth;
10638 }
10639 if (ismaxh) {
10640 data.height = o.maxHeight;
10641 }
10642
10643 if (isminw && cw) {
10644 data.left = dw - o.minWidth;
10645 }
10646 if (ismaxw && cw) {
10647 data.left = dw - o.maxWidth;
10648 }
10649 if (isminh && ch) {
10650 data.top = dh - o.minHeight;
10651 }
10652 if (ismaxh && ch) {
10653 data.top = dh - o.maxHeight;
10654 }
10655
10656 // fixing jump error on top/left - bug #2330
10657 if (!data.width && !data.height && !data.left && data.top) {
10658 data.top = null;
10659 } else if (!data.width && !data.height && !data.top && data.left) {
10660 data.left = null;
10661 }
10662
10663 return data;
10664 },
10665
10666 _proportionallyResize: function() {
10667
10668 if (!this._proportionallyResizeElements.length) {
10669 return;
10670 }
10671
10672 var i, j, borders, paddings, prel,
10673 element = this.helper || this.element;
10674
10675 for ( i=0; i < this._proportionallyResizeElements.length; i++) {
10676
10677 prel = this._proportionallyResizeElements[i];
10678
10679 if (!this.borderDif) {
10680 this.borderDif = [];
10681 borders = [prel.css("borderTopWidth"), prel.css("borderRightWidth"), prel.css("borderBottomWidth"), prel.css("borderLeftWidth")];
10682 paddings = [prel.css("paddingTop"), prel.css("paddingRight"), prel.css("paddingBottom"), prel.css("paddingLeft")];
10683
10684 for ( j = 0; j < borders.length; j++ ) {
10685 this.borderDif[ j ] = ( parseInt( borders[ j ], 10 ) || 0 ) + ( parseInt( paddings[ j ], 10 ) || 0 );
10686 }
10687 }
10688
10689 prel.css({
10690 height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0,
10691 width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0
10692 });
10693
10694 }
10695
10696 },
10697
10698 _renderProxy: function() {
10699
10700 var el = this.element, o = this.options;
10701 this.elementOffset = el.offset();
10702
10703 if(this._helper) {
10704
10705 this.helper = this.helper || $("<div style='overflow:hidden;'></div>");
10706
10707 this.helper.addClass(this._helper).css({
10708 width: this.element.outerWidth() - 1,
10709 height: this.element.outerHeight() - 1,
10710 position: "absolute",
10711 left: this.elementOffset.left +"px",
10712 top: this.elementOffset.top +"px",
10713 zIndex: ++o.zIndex //TODO: Don't modify option
10714 });
10715
10716 this.helper
10717 .appendTo("body")
10718 .disableSelection();
10719
10720 } else {
10721 this.helper = this.element;
10722 }
10723
10724 },
10725
10726 _change: {
10727 e: function(event, dx) {
10728 return { width: this.originalSize.width + dx };
10729 },
10730 w: function(event, dx) {
10731 var cs = this.originalSize, sp = this.originalPosition;
10732 return { left: sp.left + dx, width: cs.width - dx };
10733 },
10734 n: function(event, dx, dy) {
10735 var cs = this.originalSize, sp = this.originalPosition;
10736 return { top: sp.top + dy, height: cs.height - dy };
10737 },
10738 s: function(event, dx, dy) {
10739 return { height: this.originalSize.height + dy };
10740 },
10741 se: function(event, dx, dy) {
10742 return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
10743 },
10744 sw: function(event, dx, dy) {
10745 return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
10746 },
10747 ne: function(event, dx, dy) {
10748 return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
10749 },
10750 nw: function(event, dx, dy) {
10751 return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
10752 }
10753 },
10754
10755 _propagate: function(n, event) {
10756 $.ui.plugin.call(this, n, [event, this.ui()]);
10757 (n !== "resize" && this._trigger(n, event, this.ui()));
10758 },
10759
10760 plugins: {},
10761
10762 ui: function() {
10763 return {
10764 originalElement: this.originalElement,
10765 element: this.element,
10766 helper: this.helper,
10767 position: this.position,
10768 size: this.size,
10769 originalSize: this.originalSize,
10770 originalPosition: this.originalPosition
10771 };
10772 }
10773
10774 });
10775
10776 /*
10777 * Resizable Extensions
10778 */
10779
10780 $.ui.plugin.add("resizable", "animate", {
10781
10782 stop: function( event ) {
10783 var that = $(this).data("ui-resizable"),
10784 o = that.options,
10785 pr = that._proportionallyResizeElements,
10786 ista = pr.length && (/textarea/i).test(pr[0].nodeName),
10787 soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height,
10788 soffsetw = ista ? 0 : that.sizeDiff.width,
10789 style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) },
10790 left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null,
10791 top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null;
10792
10793 that.element.animate(
10794 $.extend(style, top && left ? { top: top, left: left } : {}), {
10795 duration: o.animateDuration,
10796 easing: o.animateEasing,
10797 step: function() {
10798
10799 var data = {
10800 width: parseInt(that.element.css("width"), 10),
10801 height: parseInt(that.element.css("height"), 10),
10802 top: parseInt(that.element.css("top"), 10),
10803 left: parseInt(that.element.css("left"), 10)
10804 };
10805
10806 if (pr && pr.length) {
10807 $(pr[0]).css({ width: data.width, height: data.height });
10808 }
10809
10810 // propagating resize, and updating values for each animation step
10811 that._updateCache(data);
10812 that._propagate("resize", event);
10813
10814 }
10815 }
10816 );
10817 }
10818
10819 });
10820
10821 $.ui.plugin.add("resizable", "containment", {
10822
10823 start: function() {
10824 var element, p, co, ch, cw, width, height,
10825 that = $(this).data("ui-resizable"),
10826 o = that.options,
10827 el = that.element,
10828 oc = o.containment,
10829 ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc;
10830
10831 if (!ce) {
10832 return;
10833 }
10834
10835 that.containerElement = $(ce);
10836
10837 if (/document/.test(oc) || oc === document) {
10838 that.containerOffset = { left: 0, top: 0 };
10839 that.containerPosition = { left: 0, top: 0 };
10840
10841 that.parentData = {
10842 element: $(document), left: 0, top: 0,
10843 width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight
10844 };
10845 }
10846
10847 // i'm a node, so compute top, left, right, bottom
10848 else {
10849 element = $(ce);
10850 p = [];
10851 $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); });
10852
10853 that.containerOffset = element.offset();
10854 that.containerPosition = element.position();
10855 that.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) };
10856
10857 co = that.containerOffset;
10858 ch = that.containerSize.height;
10859 cw = that.containerSize.width;
10860 width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw );
10861 height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch);
10862
10863 that.parentData = {
10864 element: ce, left: co.left, top: co.top, width: width, height: height
10865 };
10866 }
10867 },
10868
10869 resize: function( event ) {
10870 var woset, hoset, isParent, isOffsetRelative,
10871 that = $(this).data("ui-resizable"),
10872 o = that.options,
10873 co = that.containerOffset, cp = that.position,
10874 pRatio = that._aspectRatio || event.shiftKey,
10875 cop = { top:0, left:0 }, ce = that.containerElement;
10876
10877 if (ce[0] !== document && (/static/).test(ce.css("position"))) {
10878 cop = co;
10879 }
10880
10881 if (cp.left < (that._helper ? co.left : 0)) {
10882 that.size.width = that.size.width + (that._helper ? (that.position.left - co.left) : (that.position.left - cop.left));
10883 if (pRatio) {
10884 that.size.height = that.size.width / that.aspectRatio;
10885 }
10886 that.position.left = o.helper ? co.left : 0;
10887 }
10888
10889 if (cp.top < (that._helper ? co.top : 0)) {
10890 that.size.height = that.size.height + (that._helper ? (that.position.top - co.top) : that.position.top);
10891 if (pRatio) {
10892 that.size.width = that.size.height * that.aspectRatio;
10893 }
10894 that.position.top = that._helper ? co.top : 0;
10895 }
10896
10897 that.offset.left = that.parentData.left+that.position.left;
10898 that.offset.top = that.parentData.top+that.position.top;
10899
10900 woset = Math.abs( (that._helper ? that.offset.left - cop.left : (that.offset.left - cop.left)) + that.sizeDiff.width );
10901 hoset = Math.abs( (that._helper ? that.offset.top - cop.top : (that.offset.top - co.top)) + that.sizeDiff.height );
10902
10903 isParent = that.containerElement.get(0) === that.element.parent().get(0);
10904 isOffsetRelative = /relative|absolute/.test(that.containerElement.css("position"));
10905
10906 if ( isParent && isOffsetRelative ) {
10907 woset -= Math.abs( that.parentData.left );
10908 }
10909
10910 if (woset + that.size.width >= that.parentData.width) {
10911 that.size.width = that.parentData.width - woset;
10912 if (pRatio) {
10913 that.size.height = that.size.width / that.aspectRatio;
10914 }
10915 }
10916
10917 if (hoset + that.size.height >= that.parentData.height) {
10918 that.size.height = that.parentData.height - hoset;
10919 if (pRatio) {
10920 that.size.width = that.size.height * that.aspectRatio;
10921 }
10922 }
10923 },
10924
10925 stop: function(){
10926 var that = $(this).data("ui-resizable"),
10927 o = that.options,
10928 co = that.containerOffset,
10929 cop = that.containerPosition,
10930 ce = that.containerElement,
10931 helper = $(that.helper),
10932 ho = helper.offset(),
10933 w = helper.outerWidth() - that.sizeDiff.width,
10934 h = helper.outerHeight() - that.sizeDiff.height;
10935
10936 if (that._helper && !o.animate && (/relative/).test(ce.css("position"))) {
10937 $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
10938 }
10939
10940 if (that._helper && !o.animate && (/static/).test(ce.css("position"))) {
10941 $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
10942 }
10943
10944 }
10945 });
10946
10947 $.ui.plugin.add("resizable", "alsoResize", {
10948
10949 start: function () {
10950 var that = $(this).data("ui-resizable"),
10951 o = that.options,
10952 _store = function (exp) {
10953 $(exp).each(function() {
10954 var el = $(this);
10955 el.data("ui-resizable-alsoresize", {
10956 width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
10957 left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10)
10958 });
10959 });
10960 };
10961
10962 if (typeof(o.alsoResize) === "object" && !o.alsoResize.parentNode) {
10963 if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); }
10964 else { $.each(o.alsoResize, function (exp) { _store(exp); }); }
10965 }else{
10966 _store(o.alsoResize);
10967 }
10968 },
10969
10970 resize: function (event, ui) {
10971 var that = $(this).data("ui-resizable"),
10972 o = that.options,
10973 os = that.originalSize,
10974 op = that.originalPosition,
10975 delta = {
10976 height: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0,
10977 top: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0
10978 },
10979
10980 _alsoResize = function (exp, c) {
10981 $(exp).each(function() {
10982 var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {},
10983 css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ["width", "height"] : ["width", "height", "top", "left"];
10984
10985 $.each(css, function (i, prop) {
10986 var sum = (start[prop]||0) + (delta[prop]||0);
10987 if (sum && sum >= 0) {
10988 style[prop] = sum || null;
10989 }
10990 });
10991
10992 el.css(style);
10993 });
10994 };
10995
10996 if (typeof(o.alsoResize) === "object" && !o.alsoResize.nodeType) {
10997 $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); });
10998 }else{
10999 _alsoResize(o.alsoResize);
11000 }
11001 },
11002
11003 stop: function () {
11004 $(this).removeData("resizable-alsoresize");
11005 }
11006 });
11007
11008 $.ui.plugin.add("resizable", "ghost", {
11009
11010 start: function() {
11011
11012 var that = $(this).data("ui-resizable"), o = that.options, cs = that.size;
11013
11014 that.ghost = that.originalElement.clone();
11015 that.ghost
11016 .css({ opacity: 0.25, display: "block", position: "relative", height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 })
11017 .addClass("ui-resizable-ghost")
11018 .addClass(typeof o.ghost === "string" ? o.ghost : "");
11019
11020 that.ghost.appendTo(that.helper);
11021
11022 },
11023
11024 resize: function(){
11025 var that = $(this).data("ui-resizable");
11026 if (that.ghost) {
11027 that.ghost.css({ position: "relative", height: that.size.height, width: that.size.width });
11028 }
11029 },
11030
11031 stop: function() {
11032 var that = $(this).data("ui-resizable");
11033 if (that.ghost && that.helper) {
11034 that.helper.get(0).removeChild(that.ghost.get(0));
11035 }
11036 }
11037
11038 });
11039
11040 $.ui.plugin.add("resizable", "grid", {
11041
11042 resize: function() {
11043 var that = $(this).data("ui-resizable"),
11044 o = that.options,
11045 cs = that.size,
11046 os = that.originalSize,
11047 op = that.originalPosition,
11048 a = that.axis,
11049 grid = typeof o.grid === "number" ? [o.grid, o.grid] : o.grid,
11050 gridX = (grid[0]||1),
11051 gridY = (grid[1]||1),
11052 ox = Math.round((cs.width - os.width) / gridX) * gridX,
11053 oy = Math.round((cs.height - os.height) / gridY) * gridY,
11054 newWidth = os.width + ox,
11055 newHeight = os.height + oy,
11056 isMaxWidth = o.maxWidth && (o.maxWidth < newWidth),
11057 isMaxHeight = o.maxHeight && (o.maxHeight < newHeight),
11058 isMinWidth = o.minWidth && (o.minWidth > newWidth),
11059 isMinHeight = o.minHeight && (o.minHeight > newHeight);
11060
11061 o.grid = grid;
11062
11063 if (isMinWidth) {
11064 newWidth = newWidth + gridX;
11065 }
11066 if (isMinHeight) {
11067 newHeight = newHeight + gridY;
11068 }
11069 if (isMaxWidth) {
11070 newWidth = newWidth - gridX;
11071 }
11072 if (isMaxHeight) {
11073 newHeight = newHeight - gridY;
11074 }
11075
11076 if (/^(se|s|e)$/.test(a)) {
11077 that.size.width = newWidth;
11078 that.size.height = newHeight;
11079 } else if (/^(ne)$/.test(a)) {
11080 that.size.width = newWidth;
11081 that.size.height = newHeight;
11082 that.position.top = op.top - oy;
11083 } else if (/^(sw)$/.test(a)) {
11084 that.size.width = newWidth;
11085 that.size.height = newHeight;
11086 that.position.left = op.left - ox;
11087 } else {
11088 if ( newHeight - gridY > 0 ) {
11089 that.size.height = newHeight;
11090 that.position.top = op.top - oy;
11091 } else {
11092 that.size.height = gridY;
11093 that.position.top = op.top + os.height - gridY;
11094 }
11095 if ( newWidth - gridX > 0 ) {
11096 that.size.width = newWidth;
11097 that.position.left = op.left - ox;
11098 } else {
11099 that.size.width = gridX;
11100 that.position.left = op.left + os.width - gridX;
11101 }
11102 }
11103 }
11104
11105 });
11106
11107 })(jQuery);
11108 (function( $, undefined ) {
11109
11110 $.widget("ui.selectable", $.ui.mouse, {
11111 version: "1.10.4",
11112 options: {
11113 appendTo: "body",
11114 autoRefresh: true,
11115 distance: 0,
11116 filter: "*",
11117 tolerance: "touch",
11118
11119 // callbacks
11120 selected: null,
11121 selecting: null,
11122 start: null,
11123 stop: null,
11124 unselected: null,
11125 unselecting: null
11126 },
11127 _create: function() {
11128 var selectees,
11129 that = this;
11130
11131 this.element.addClass("ui-selectable");
11132
11133 this.dragged = false;
11134
11135 // cache selectee children based on filter
11136 this.refresh = function() {
11137 selectees = $(that.options.filter, that.element[0]);
11138 selectees.addClass("ui-selectee");
11139 selectees.each(function() {
11140 var $this = $(this),
11141 pos = $this.offset();
11142 $.data(this, "selectable-item", {
11143 element: this,
11144 $element: $this,
11145 left: pos.left,
11146 top: pos.top,
11147 right: pos.left + $this.outerWidth(),
11148 bottom: pos.top + $this.outerHeight(),
11149 startselected: false,
11150 selected: $this.hasClass("ui-selected"),
11151 selecting: $this.hasClass("ui-selecting"),
11152 unselecting: $this.hasClass("ui-unselecting")
11153 });
11154 });
11155 };
11156 this.refresh();
11157
11158 this.selectees = selectees.addClass("ui-selectee");
11159
11160 this._mouseInit();
11161
11162 this.helper = $("<div class='ui-selectable-helper'></div>");
11163 },
11164
11165 _destroy: function() {
11166 this.selectees
11167 .removeClass("ui-selectee")
11168 .removeData("selectable-item");
11169 this.element
11170 .removeClass("ui-selectable ui-selectable-disabled");
11171 this._mouseDestroy();
11172 },
11173
11174 _mouseStart: function(event) {
11175 var that = this,
11176 options = this.options;
11177
11178 this.opos = [event.pageX, event.pageY];
11179
11180 if (this.options.disabled) {
11181 return;
11182 }
11183
11184 this.selectees = $(options.filter, this.element[0]);
11185
11186 this._trigger("start", event);
11187
11188 $(options.appendTo).append(this.helper);
11189 // position helper (lasso)
11190 this.helper.css({
11191 "left": event.pageX,
11192 "top": event.pageY,
11193 "width": 0,
11194 "height": 0
11195 });
11196
11197 if (options.autoRefresh) {
11198 this.refresh();
11199 }
11200
11201 this.selectees.filter(".ui-selected").each(function() {
11202 var selectee = $.data(this, "selectable-item");
11203 selectee.startselected = true;
11204 if (!event.metaKey && !event.ctrlKey) {
11205 selectee.$element.removeClass("ui-selected");
11206 selectee.selected = false;
11207 selectee.$element.addClass("ui-unselecting");
11208 selectee.unselecting = true;
11209 // selectable UNSELECTING callback
11210 that._trigger("unselecting", event, {
11211 unselecting: selectee.element
11212 });
11213 }
11214 });
11215
11216 $(event.target).parents().addBack().each(function() {
11217 var doSelect,
11218 selectee = $.data(this, "selectable-item");
11219 if (selectee) {
11220 doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected");
11221 selectee.$element
11222 .removeClass(doSelect ? "ui-unselecting" : "ui-selected")
11223 .addClass(doSelect ? "ui-selecting" : "ui-unselecting");
11224 selectee.unselecting = !doSelect;
11225 selectee.selecting = doSelect;
11226 selectee.selected = doSelect;
11227 // selectable (UN)SELECTING callback
11228 if (doSelect) {
11229 that._trigger("selecting", event, {
11230 selecting: selectee.element
11231 });
11232 } else {
11233 that._trigger("unselecting", event, {
11234 unselecting: selectee.element
11235 });
11236 }
11237 return false;
11238 }
11239 });
11240
11241 },
11242
11243 _mouseDrag: function(event) {
11244
11245 this.dragged = true;
11246
11247 if (this.options.disabled) {
11248 return;
11249 }
11250
11251 var tmp,
11252 that = this,
11253 options = this.options,
11254 x1 = this.opos[0],
11255 y1 = this.opos[1],
11256 x2 = event.pageX,
11257 y2 = event.pageY;
11258
11259 if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; }
11260 if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; }
11261 this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1});
11262
11263 this.selectees.each(function() {
11264 var selectee = $.data(this, "selectable-item"),
11265 hit = false;
11266
11267 //prevent helper from being selected if appendTo: selectable
11268 if (!selectee || selectee.element === that.element[0]) {
11269 return;
11270 }
11271
11272 if (options.tolerance === "touch") {
11273 hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
11274 } else if (options.tolerance === "fit") {
11275 hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
11276 }
11277
11278 if (hit) {
11279 // SELECT
11280 if (selectee.selected) {
11281 selectee.$element.removeClass("ui-selected");
11282 selectee.selected = false;
11283 }
11284 if (selectee.unselecting) {
11285 selectee.$element.removeClass("ui-unselecting");
11286 selectee.unselecting = false;
11287 }
11288 if (!selectee.selecting) {
11289 selectee.$element.addClass("ui-selecting");
11290 selectee.selecting = true;
11291 // selectable SELECTING callback
11292 that._trigger("selecting", event, {
11293 selecting: selectee.element
11294 });
11295 }
11296 } else {
11297 // UNSELECT
11298 if (selectee.selecting) {
11299 if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
11300 selectee.$element.removeClass("ui-selecting");
11301 selectee.selecting = false;
11302 selectee.$element.addClass("ui-selected");
11303 selectee.selected = true;
11304 } else {
11305 selectee.$element.removeClass("ui-selecting");
11306 selectee.selecting = false;
11307 if (selectee.startselected) {
11308 selectee.$element.addClass("ui-unselecting");
11309 selectee.unselecting = true;
11310 }
11311 // selectable UNSELECTING callback
11312 that._trigger("unselecting", event, {
11313 unselecting: selectee.element
11314 });
11315 }
11316 }
11317 if (selectee.selected) {
11318 if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
11319 selectee.$element.removeClass("ui-selected");
11320 selectee.selected = false;
11321
11322 selectee.$element.addClass("ui-unselecting");
11323 selectee.unselecting = true;
11324 // selectable UNSELECTING callback
11325 that._trigger("unselecting", event, {
11326 unselecting: selectee.element
11327 });
11328 }
11329 }
11330 }
11331 });
11332
11333 return false;
11334 },
11335
11336 _mouseStop: function(event) {
11337 var that = this;
11338
11339 this.dragged = false;
11340
11341 $(".ui-unselecting", this.element[0]).each(function() {
11342 var selectee = $.data(this, "selectable-item");
11343 selectee.$element.removeClass("ui-unselecting");
11344 selectee.unselecting = false;
11345 selectee.startselected = false;
11346 that._trigger("unselected", event, {
11347 unselected: selectee.element
11348 });
11349 });
11350 $(".ui-selecting", this.element[0]).each(function() {
11351 var selectee = $.data(this, "selectable-item");
11352 selectee.$element.removeClass("ui-selecting").addClass("ui-selected");
11353 selectee.selecting = false;
11354 selectee.selected = true;
11355 selectee.startselected = true;
11356 that._trigger("selected", event, {
11357 selected: selectee.element
11358 });
11359 });
11360 this._trigger("stop", event);
11361
11362 this.helper.remove();
11363
11364 return false;
11365 }
11366
11367 });
11368
11369 })(jQuery);
11370 (function( $, undefined ) {
11371
11372 // number of pages in a slider
11373 // (how many times can you page up/down to go through the whole range)
11374 var numPages = 5;
11375
11376 $.widget( "ui.slider", $.ui.mouse, {
11377 version: "1.10.4",
11378 widgetEventPrefix: "slide",
11379
11380 options: {
11381 animate: false,
11382 distance: 0,
11383 max: 100,
11384 min: 0,
11385 orientation: "horizontal",
11386 range: false,
11387 step: 1,
11388 value: 0,
11389 values: null,
11390
11391 // callbacks
11392 change: null,
11393 slide: null,
11394 start: null,
11395 stop: null
11396 },
11397
11398 _create: function() {
11399 this._keySliding = false;
11400 this._mouseSliding = false;
11401 this._animateOff = true;
11402 this._handleIndex = null;
11403 this._detectOrientation();
11404 this._mouseInit();
11405
11406 this.element
11407 .addClass( "ui-slider" +
11408 " ui-slider-" + this.orientation +
11409 " ui-widget" +
11410 " ui-widget-content" +
11411 " ui-corner-all");
11412
11413 this._refresh();
11414 this._setOption( "disabled", this.options.disabled );
11415
11416 this._animateOff = false;
11417 },
11418
11419 _refresh: function() {
11420 this._createRange();
11421 this._createHandles();
11422 this._setupEvents();
11423 this._refreshValue();
11424 },
11425
11426 _createHandles: function() {
11427 var i, handleCount,
11428 options = this.options,
11429 existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
11430 handle = "<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",
11431 handles = [];
11432
11433 handleCount = ( options.values && options.values.length ) || 1;
11434
11435 if ( existingHandles.length > handleCount ) {
11436 existingHandles.slice( handleCount ).remove();
11437 existingHandles = existingHandles.slice( 0, handleCount );
11438 }
11439
11440 for ( i = existingHandles.length; i < handleCount; i++ ) {
11441 handles.push( handle );
11442 }
11443
11444 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
11445
11446 this.handle = this.handles.eq( 0 );
11447
11448 this.handles.each(function( i ) {
11449 $( this ).data( "ui-slider-handle-index", i );
11450 });
11451 },
11452
11453 _createRange: function() {
11454 var options = this.options,
11455 classes = "";
11456
11457 if ( options.range ) {
11458 if ( options.range === true ) {
11459 if ( !options.values ) {
11460 options.values = [ this._valueMin(), this._valueMin() ];
11461 } else if ( options.values.length && options.values.length !== 2 ) {
11462 options.values = [ options.values[0], options.values[0] ];
11463 } else if ( $.isArray( options.values ) ) {
11464 options.values = options.values.slice(0);
11465 }
11466 }
11467
11468 if ( !this.range || !this.range.length ) {
11469 this.range = $( "<div></div>" )
11470 .appendTo( this.element );
11471
11472 classes = "ui-slider-range" +
11473 // note: this isn't the most fittingly semantic framework class for this element,
11474 // but worked best visually with a variety of themes
11475 " ui-widget-header ui-corner-all";
11476 } else {
11477 this.range.removeClass( "ui-slider-range-min ui-slider-range-max" )
11478 // Handle range switching from true to min/max
11479 .css({
11480 "left": "",
11481 "bottom": ""
11482 });
11483 }
11484
11485 this.range.addClass( classes +
11486 ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) );
11487 } else {
11488 if ( this.range ) {
11489 this.range.remove();
11490 }
11491 this.range = null;
11492 }
11493 },
11494
11495 _setupEvents: function() {
11496 var elements = this.handles.add( this.range ).filter( "a" );
11497 this._off( elements );
11498 this._on( elements, this._handleEvents );
11499 this._hoverable( elements );
11500 this._focusable( elements );
11501 },
11502
11503 _destroy: function() {
11504 this.handles.remove();
11505 if ( this.range ) {
11506 this.range.remove();
11507 }
11508
11509 this.element
11510 .removeClass( "ui-slider" +
11511 " ui-slider-horizontal" +
11512 " ui-slider-vertical" +
11513 " ui-widget" +
11514 " ui-widget-content" +
11515 " ui-corner-all" );
11516
11517 this._mouseDestroy();
11518 },
11519
11520 _mouseCapture: function( event ) {
11521 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
11522 that = this,
11523 o = this.options;
11524
11525 if ( o.disabled ) {
11526 return false;
11527 }
11528
11529 this.elementSize = {
11530 width: this.element.outerWidth(),
11531 height: this.element.outerHeight()
11532 };
11533 this.elementOffset = this.element.offset();
11534
11535 position = { x: event.pageX, y: event.pageY };
11536 normValue = this._normValueFromMouse( position );
11537 distance = this._valueMax() - this._valueMin() + 1;
11538 this.handles.each(function( i ) {
11539 var thisDistance = Math.abs( normValue - that.values(i) );
11540 if (( distance > thisDistance ) ||
11541 ( distance === thisDistance &&
11542 (i === that._lastChangedValue || that.values(i) === o.min ))) {
11543 distance = thisDistance;
11544 closestHandle = $( this );
11545 index = i;
11546 }
11547 });
11548
11549 allowed = this._start( event, index );
11550 if ( allowed === false ) {
11551 return false;
11552 }
11553 this._mouseSliding = true;
11554
11555 this._handleIndex = index;
11556
11557 closestHandle
11558 .addClass( "ui-state-active" )
11559 .focus();
11560
11561 offset = closestHandle.offset();
11562 mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
11563 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
11564 left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
11565 top: event.pageY - offset.top -
11566 ( closestHandle.height() / 2 ) -
11567 ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
11568 ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
11569 ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
11570 };
11571
11572 if ( !this.handles.hasClass( "ui-state-hover" ) ) {
11573 this._slide( event, index, normValue );
11574 }
11575 this._animateOff = true;
11576 return true;
11577 },
11578
11579 _mouseStart: function() {
11580 return true;
11581 },
11582
11583 _mouseDrag: function( event ) {
11584 var position = { x: event.pageX, y: event.pageY },
11585 normValue = this._normValueFromMouse( position );
11586
11587 this._slide( event, this._handleIndex, normValue );
11588
11589 return false;
11590 },
11591
11592 _mouseStop: function( event ) {
11593 this.handles.removeClass( "ui-state-active" );
11594 this._mouseSliding = false;
11595
11596 this._stop( event, this._handleIndex );
11597 this._change( event, this._handleIndex );
11598
11599 this._handleIndex = null;
11600 this._clickOffset = null;
11601 this._animateOff = false;
11602
11603 return false;
11604 },
11605
11606 _detectOrientation: function() {
11607 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
11608 },
11609
11610 _normValueFromMouse: function( position ) {
11611 var pixelTotal,
11612 pixelMouse,
11613 percentMouse,
11614 valueTotal,
11615 valueMouse;
11616
11617 if ( this.orientation === "horizontal" ) {
11618 pixelTotal = this.elementSize.width;
11619 pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
11620 } else {
11621 pixelTotal = this.elementSize.height;
11622 pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
11623 }
11624
11625 percentMouse = ( pixelMouse / pixelTotal );
11626 if ( percentMouse > 1 ) {
11627 percentMouse = 1;
11628 }
11629 if ( percentMouse < 0 ) {
11630 percentMouse = 0;
11631 }
11632 if ( this.orientation === "vertical" ) {
11633 percentMouse = 1 - percentMouse;
11634 }
11635
11636 valueTotal = this._valueMax() - this._valueMin();
11637 valueMouse = this._valueMin() + percentMouse * valueTotal;
11638
11639 return this._trimAlignValue( valueMouse );
11640 },
11641
11642 _start: function( event, index ) {
11643 var uiHash = {
11644 handle: this.handles[ index ],
11645 value: this.value()
11646 };
11647 if ( this.options.values && this.options.values.length ) {
11648 uiHash.value = this.values( index );
11649 uiHash.values = this.values();
11650 }
11651 return this._trigger( "start", event, uiHash );
11652 },
11653
11654 _slide: function( event, index, newVal ) {
11655 var otherVal,
11656 newValues,
11657 allowed;
11658
11659 if ( this.options.values && this.options.values.length ) {
11660 otherVal = this.values( index ? 0 : 1 );
11661
11662 if ( ( this.options.values.length === 2 && this.options.range === true ) &&
11663 ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
11664 ) {
11665 newVal = otherVal;
11666 }
11667
11668 if ( newVal !== this.values( index ) ) {
11669 newValues = this.values();
11670 newValues[ index ] = newVal;
11671 // A slide can be canceled by returning false from the slide callback
11672 allowed = this._trigger( "slide", event, {
11673 handle: this.handles[ index ],
11674 value: newVal,
11675 values: newValues
11676 } );
11677 otherVal = this.values( index ? 0 : 1 );
11678 if ( allowed !== false ) {
11679 this.values( index, newVal );
11680 }
11681 }
11682 } else {
11683 if ( newVal !== this.value() ) {
11684 // A slide can be canceled by returning false from the slide callback
11685 allowed = this._trigger( "slide", event, {
11686 handle: this.handles[ index ],
11687 value: newVal
11688 } );
11689 if ( allowed !== false ) {
11690 this.value( newVal );
11691 }
11692 }
11693 }
11694 },
11695
11696 _stop: function( event, index ) {
11697 var uiHash = {
11698 handle: this.handles[ index ],
11699 value: this.value()
11700 };
11701 if ( this.options.values && this.options.values.length ) {
11702 uiHash.value = this.values( index );
11703 uiHash.values = this.values();
11704 }
11705
11706 this._trigger( "stop", event, uiHash );
11707 },
11708
11709 _change: function( event, index ) {
11710 if ( !this._keySliding && !this._mouseSliding ) {
11711 var uiHash = {
11712 handle: this.handles[ index ],
11713 value: this.value()
11714 };
11715 if ( this.options.values && this.options.values.length ) {
11716 uiHash.value = this.values( index );
11717 uiHash.values = this.values();
11718 }
11719
11720 //store the last changed value index for reference when handles overlap
11721 this._lastChangedValue = index;
11722
11723 this._trigger( "change", event, uiHash );
11724 }
11725 },
11726
11727 value: function( newValue ) {
11728 if ( arguments.length ) {
11729 this.options.value = this._trimAlignValue( newValue );
11730 this._refreshValue();
11731 this._change( null, 0 );
11732 return;
11733 }
11734
11735 return this._value();
11736 },
11737
11738 values: function( index, newValue ) {
11739 var vals,
11740 newValues,
11741 i;
11742
11743 if ( arguments.length > 1 ) {
11744 this.options.values[ index ] = this._trimAlignValue( newValue );
11745 this._refreshValue();
11746 this._change( null, index );
11747 return;
11748 }
11749
11750 if ( arguments.length ) {
11751 if ( $.isArray( arguments[ 0 ] ) ) {
11752 vals = this.options.values;
11753 newValues = arguments[ 0 ];
11754 for ( i = 0; i < vals.length; i += 1 ) {
11755 vals[ i ] = this._trimAlignValue( newValues[ i ] );
11756 this._change( null, i );
11757 }
11758 this._refreshValue();
11759 } else {
11760 if ( this.options.values && this.options.values.length ) {
11761 return this._values( index );
11762 } else {
11763 return this.value();
11764 }
11765 }
11766 } else {
11767 return this._values();
11768 }
11769 },
11770
11771 _setOption: function( key, value ) {
11772 var i,
11773 valsLength = 0;
11774
11775 if ( key === "range" && this.options.range === true ) {
11776 if ( value === "min" ) {
11777 this.options.value = this._values( 0 );
11778 this.options.values = null;
11779 } else if ( value === "max" ) {
11780 this.options.value = this._values( this.options.values.length-1 );
11781 this.options.values = null;
11782 }
11783 }
11784
11785 if ( $.isArray( this.options.values ) ) {
11786 valsLength = this.options.values.length;
11787 }
11788
11789 $.Widget.prototype._setOption.apply( this, arguments );
11790
11791 switch ( key ) {
11792 case "orientation":
11793 this._detectOrientation();
11794 this.element
11795 .removeClass( "ui-slider-horizontal ui-slider-vertical" )
11796 .addClass( "ui-slider-" + this.orientation );
11797 this._refreshValue();
11798 break;
11799 case "value":
11800 this._animateOff = true;
11801 this._refreshValue();
11802 this._change( null, 0 );
11803 this._animateOff = false;
11804 break;
11805 case "values":
11806 this._animateOff = true;
11807 this._refreshValue();
11808 for ( i = 0; i < valsLength; i += 1 ) {
11809 this._change( null, i );
11810 }
11811 this._animateOff = false;
11812 break;
11813 case "min":
11814 case "max":
11815 this._animateOff = true;
11816 this._refreshValue();
11817 this._animateOff = false;
11818 break;
11819 case "range":
11820 this._animateOff = true;
11821 this._refresh();
11822 this._animateOff = false;
11823 break;
11824 }
11825 },
11826
11827 //internal value getter
11828 // _value() returns value trimmed by min and max, aligned by step
11829 _value: function() {
11830 var val = this.options.value;
11831 val = this._trimAlignValue( val );
11832
11833 return val;
11834 },
11835
11836 //internal values getter
11837 // _values() returns array of values trimmed by min and max, aligned by step
11838 // _values( index ) returns single value trimmed by min and max, aligned by step
11839 _values: function( index ) {
11840 var val,
11841 vals,
11842 i;
11843
11844 if ( arguments.length ) {
11845 val = this.options.values[ index ];
11846 val = this._trimAlignValue( val );
11847
11848 return val;
11849 } else if ( this.options.values && this.options.values.length ) {
11850 // .slice() creates a copy of the array
11851 // this copy gets trimmed by min and max and then returned
11852 vals = this.options.values.slice();
11853 for ( i = 0; i < vals.length; i+= 1) {
11854 vals[ i ] = this._trimAlignValue( vals[ i ] );
11855 }
11856
11857 return vals;
11858 } else {
11859 return [];
11860 }
11861 },
11862
11863 // returns the step-aligned value that val is closest to, between (inclusive) min and max
11864 _trimAlignValue: function( val ) {
11865 if ( val <= this._valueMin() ) {
11866 return this._valueMin();
11867 }
11868 if ( val >= this._valueMax() ) {
11869 return this._valueMax();
11870 }
11871 var step = ( this.options.step > 0 ) ? this.options.step : 1,
11872 valModStep = (val - this._valueMin()) % step,
11873 alignValue = val - valModStep;
11874
11875 if ( Math.abs(valModStep) * 2 >= step ) {
11876 alignValue += ( valModStep > 0 ) ? step : ( -step );
11877 }
11878
11879 // Since JavaScript has problems with large floats, round
11880 // the final value to 5 digits after the decimal point (see #4124)
11881 return parseFloat( alignValue.toFixed(5) );
11882 },
11883
11884 _valueMin: function() {
11885 return this.options.min;
11886 },
11887
11888 _valueMax: function() {
11889 return this.options.max;
11890 },
11891
11892 _refreshValue: function() {
11893 var lastValPercent, valPercent, value, valueMin, valueMax,
11894 oRange = this.options.range,
11895 o = this.options,
11896 that = this,
11897 animate = ( !this._animateOff ) ? o.animate : false,
11898 _set = {};
11899
11900 if ( this.options.values && this.options.values.length ) {
11901 this.handles.each(function( i ) {
11902 valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
11903 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
11904 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
11905 if ( that.options.range === true ) {
11906 if ( that.orientation === "horizontal" ) {
11907 if ( i === 0 ) {
11908 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
11909 }
11910 if ( i === 1 ) {
11911 that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
11912 }
11913 } else {
11914 if ( i === 0 ) {
11915 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
11916 }
11917 if ( i === 1 ) {
11918 that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
11919 }
11920 }
11921 }
11922 lastValPercent = valPercent;
11923 });
11924 } else {
11925 value = this.value();
11926 valueMin = this._valueMin();
11927 valueMax = this._valueMax();
11928 valPercent = ( valueMax !== valueMin ) ?
11929 ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
11930 0;
11931 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
11932 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
11933
11934 if ( oRange === "min" && this.orientation === "horizontal" ) {
11935 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
11936 }
11937 if ( oRange === "max" && this.orientation === "horizontal" ) {
11938 this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
11939 }
11940 if ( oRange === "min" && this.orientation === "vertical" ) {
11941 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
11942 }
11943 if ( oRange === "max" && this.orientation === "vertical" ) {
11944 this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
11945 }
11946 }
11947 },
11948
11949 _handleEvents: {
11950 keydown: function( event ) {
11951 var allowed, curVal, newVal, step,
11952 index = $( event.target ).data( "ui-slider-handle-index" );
11953
11954 switch ( event.keyCode ) {
11955 case $.ui.keyCode.HOME:
11956 case $.ui.keyCode.END:
11957 case $.ui.keyCode.PAGE_UP:
11958 case $.ui.keyCode.PAGE_DOWN:
11959 case $.ui.keyCode.UP:
11960 case $.ui.keyCode.RIGHT:
11961 case $.ui.keyCode.DOWN:
11962 case $.ui.keyCode.LEFT:
11963 event.preventDefault();
11964 if ( !this._keySliding ) {
11965 this._keySliding = true;
11966 $( event.target ).addClass( "ui-state-active" );
11967 allowed = this._start( event, index );
11968 if ( allowed === false ) {
11969 return;
11970 }
11971 }
11972 break;
11973 }
11974
11975 step = this.options.step;
11976 if ( this.options.values && this.options.values.length ) {
11977 curVal = newVal = this.values( index );
11978 } else {
11979 curVal = newVal = this.value();
11980 }
11981
11982 switch ( event.keyCode ) {
11983 case $.ui.keyCode.HOME:
11984 newVal = this._valueMin();
11985 break;
11986 case $.ui.keyCode.END:
11987 newVal = this._valueMax();
11988 break;
11989 case $.ui.keyCode.PAGE_UP:
11990 newVal = this._trimAlignValue( curVal + ( (this._valueMax() - this._valueMin()) / numPages ) );
11991 break;
11992 case $.ui.keyCode.PAGE_DOWN:
11993 newVal = this._trimAlignValue( curVal - ( (this._valueMax() - this._valueMin()) / numPages ) );
11994 break;
11995 case $.ui.keyCode.UP:
11996 case $.ui.keyCode.RIGHT:
11997 if ( curVal === this._valueMax() ) {
11998 return;
11999 }
12000 newVal = this._trimAlignValue( curVal + step );
12001 break;
12002 case $.ui.keyCode.DOWN:
12003 case $.ui.keyCode.LEFT:
12004 if ( curVal === this._valueMin() ) {
12005 return;
12006 }
12007 newVal = this._trimAlignValue( curVal - step );
12008 break;
12009 }
12010
12011 this._slide( event, index, newVal );
12012 },
12013 click: function( event ) {
12014 event.preventDefault();
12015 },
12016 keyup: function( event ) {
12017 var index = $( event.target ).data( "ui-slider-handle-index" );
12018
12019 if ( this._keySliding ) {
12020 this._keySliding = false;
12021 this._stop( event, index );
12022 this._change( event, index );
12023 $( event.target ).removeClass( "ui-state-active" );
12024 }
12025 }
12026 }
12027
12028 });
12029
12030 }(jQuery));
12031 (function( $, undefined ) {
12032
12033 function isOverAxis( x, reference, size ) {
12034 return ( x > reference ) && ( x < ( reference + size ) );
12035 }
12036
12037 function isFloating(item) {
12038 return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display"));
12039 }
12040
12041 $.widget("ui.sortable", $.ui.mouse, {
12042 version: "1.10.4",
12043 widgetEventPrefix: "sort",
12044 ready: false,
12045 options: {
12046 appendTo: "parent",
12047 axis: false,
12048 connectWith: false,
12049 containment: false,
12050 cursor: "auto",
12051 cursorAt: false,
12052 dropOnEmpty: true,
12053 forcePlaceholderSize: false,
12054 forceHelperSize: false,
12055 grid: false,
12056 handle: false,
12057 helper: "original",
12058 items: "> *",
12059 opacity: false,
12060 placeholder: false,
12061 revert: false,
12062 scroll: true,
12063 scrollSensitivity: 20,
12064 scrollSpeed: 20,
12065 scope: "default",
12066 tolerance: "intersect",
12067 zIndex: 1000,
12068
12069 // callbacks
12070 activate: null,
12071 beforeStop: null,
12072 change: null,
12073 deactivate: null,
12074 out: null,
12075 over: null,
12076 receive: null,
12077 remove: null,
12078 sort: null,
12079 start: null,
12080 stop: null,
12081 update: null
12082 },
12083 _create: function() {
12084
12085 var o = this.options;
12086 this.containerCache = {};
12087 this.element.addClass("ui-sortable");
12088
12089 //Get the items
12090 this.refresh();
12091
12092 //Let's determine if the items are being displayed horizontally
12093 this.floating = this.items.length ? o.axis === "x" || isFloating(this.items[0].item) : false;
12094
12095 //Let's determine the parent's offset
12096 this.offset = this.element.offset();
12097
12098 //Initialize mouse events for interaction
12099 this._mouseInit();
12100
12101 //We're ready to go
12102 this.ready = true;
12103
12104 },
12105
12106 _destroy: function() {
12107 this.element
12108 .removeClass("ui-sortable ui-sortable-disabled");
12109 this._mouseDestroy();
12110
12111 for ( var i = this.items.length - 1; i >= 0; i-- ) {
12112 this.items[i].item.removeData(this.widgetName + "-item");
12113 }
12114
12115 return this;
12116 },
12117
12118 _setOption: function(key, value){
12119 if ( key === "disabled" ) {
12120 this.options[ key ] = value;
12121
12122 this.widget().toggleClass( "ui-sortable-disabled", !!value );
12123 } else {
12124 // Don't call widget base _setOption for disable as it adds ui-state-disabled class
12125 $.Widget.prototype._setOption.apply(this, arguments);
12126 }
12127 },
12128
12129 _mouseCapture: function(event, overrideHandle) {
12130 var currentItem = null,
12131 validHandle = false,
12132 that = this;
12133
12134 if (this.reverting) {
12135 return false;
12136 }
12137
12138 if(this.options.disabled || this.options.type === "static") {
12139 return false;
12140 }
12141
12142 //We have to refresh the items data once first
12143 this._refreshItems(event);
12144
12145 //Find out if the clicked node (or one of its parents) is a actual item in this.items
12146 $(event.target).parents().each(function() {
12147 if($.data(this, that.widgetName + "-item") === that) {
12148 currentItem = $(this);
12149 return false;
12150 }
12151 });
12152 if($.data(event.target, that.widgetName + "-item") === that) {
12153 currentItem = $(event.target);
12154 }
12155
12156 if(!currentItem) {
12157 return false;
12158 }
12159 if(this.options.handle && !overrideHandle) {
12160 $(this.options.handle, currentItem).find("*").addBack().each(function() {
12161 if(this === event.target) {
12162 validHandle = true;
12163 }
12164 });
12165 if(!validHandle) {
12166 return false;
12167 }
12168 }
12169
12170 this.currentItem = currentItem;
12171 this._removeCurrentsFromItems();
12172 return true;
12173
12174 },
12175
12176 _mouseStart: function(event, overrideHandle, noActivation) {
12177
12178 var i, body,
12179 o = this.options;
12180
12181 this.currentContainer = this;
12182
12183 //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
12184 this.refreshPositions();
12185
12186 //Create and append the visible helper
12187 this.helper = this._createHelper(event);
12188
12189 //Cache the helper size
12190 this._cacheHelperProportions();
12191
12192 /*
12193 * - Position generation -
12194 * This block generates everything position related - it's the core of draggables.
12195 */
12196
12197 //Cache the margins of the original element
12198 this._cacheMargins();
12199
12200 //Get the next scrolling parent
12201 this.scrollParent = this.helper.scrollParent();
12202
12203 //The element's absolute position on the page minus margins
12204 this.offset = this.currentItem.offset();
12205 this.offset = {
12206 top: this.offset.top - this.margins.top,
12207 left: this.offset.left - this.margins.left
12208 };
12209
12210 $.extend(this.offset, {
12211 click: { //Where the click happened, relative to the element
12212 left: event.pageX - this.offset.left,
12213 top: event.pageY - this.offset.top
12214 },
12215 parent: this._getParentOffset(),
12216 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
12217 });
12218
12219 // Only after we got the offset, we can change the helper's position to absolute
12220 // TODO: Still need to figure out a way to make relative sorting possible
12221 this.helper.css("position", "absolute");
12222 this.cssPosition = this.helper.css("position");
12223
12224 //Generate the original position
12225 this.originalPosition = this._generatePosition(event);
12226 this.originalPageX = event.pageX;
12227 this.originalPageY = event.pageY;
12228
12229 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
12230 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
12231
12232 //Cache the former DOM position
12233 this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
12234
12235 //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
12236 if(this.helper[0] !== this.currentItem[0]) {
12237 this.currentItem.hide();
12238 }
12239
12240 //Create the placeholder
12241 this._createPlaceholder();
12242
12243 //Set a containment if given in the options
12244 if(o.containment) {
12245 this._setContainment();
12246 }
12247
12248 if( o.cursor && o.cursor !== "auto" ) { // cursor option
12249 body = this.document.find( "body" );
12250
12251 // support: IE
12252 this.storedCursor = body.css( "cursor" );
12253 body.css( "cursor", o.cursor );
12254
12255 this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body );
12256 }
12257
12258 if(o.opacity) { // opacity option
12259 if (this.helper.css("opacity")) {
12260 this._storedOpacity = this.helper.css("opacity");
12261 }
12262 this.helper.css("opacity", o.opacity);
12263 }
12264
12265 if(o.zIndex) { // zIndex option
12266 if (this.helper.css("zIndex")) {
12267 this._storedZIndex = this.helper.css("zIndex");
12268 }
12269 this.helper.css("zIndex", o.zIndex);
12270 }
12271
12272 //Prepare scrolling
12273 if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
12274 this.overflowOffset = this.scrollParent.offset();
12275 }
12276
12277 //Call callbacks
12278 this._trigger("start", event, this._uiHash());
12279
12280 //Recache the helper size
12281 if(!this._preserveHelperProportions) {
12282 this._cacheHelperProportions();
12283 }
12284
12285
12286 //Post "activate" events to possible containers
12287 if( !noActivation ) {
12288 for ( i = this.containers.length - 1; i >= 0; i-- ) {
12289 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
12290 }
12291 }
12292
12293 //Prepare possible droppables
12294 if($.ui.ddmanager) {
12295 $.ui.ddmanager.current = this;
12296 }
12297
12298 if ($.ui.ddmanager && !o.dropBehaviour) {
12299 $.ui.ddmanager.prepareOffsets(this, event);
12300 }
12301
12302 this.dragging = true;
12303
12304 this.helper.addClass("ui-sortable-helper");
12305 this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
12306 return true;
12307
12308 },
12309
12310 _mouseDrag: function(event) {
12311 var i, item, itemElement, intersection,
12312 o = this.options,
12313 scrolled = false;
12314
12315 //Compute the helpers position
12316 this.position = this._generatePosition(event);
12317 this.positionAbs = this._convertPositionTo("absolute");
12318
12319 if (!this.lastPositionAbs) {
12320 this.lastPositionAbs = this.positionAbs;
12321 }
12322
12323 //Do scrolling
12324 if(this.options.scroll) {
12325 if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
12326
12327 if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
12328 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
12329 } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
12330 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
12331 }
12332
12333 if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
12334 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
12335 } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
12336 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
12337 }
12338
12339 } else {
12340
12341 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
12342 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
12343 } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
12344 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
12345 }
12346
12347 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
12348 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
12349 } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
12350 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
12351 }
12352
12353 }
12354
12355 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
12356 $.ui.ddmanager.prepareOffsets(this, event);
12357 }
12358 }
12359
12360 //Regenerate the absolute position used for position checks
12361 this.positionAbs = this._convertPositionTo("absolute");
12362
12363 //Set the helper position
12364 if(!this.options.axis || this.options.axis !== "y") {
12365 this.helper[0].style.left = this.position.left+"px";
12366 }
12367 if(!this.options.axis || this.options.axis !== "x") {
12368 this.helper[0].style.top = this.position.top+"px";
12369 }
12370
12371 //Rearrange
12372 for (i = this.items.length - 1; i >= 0; i--) {
12373
12374 //Cache variables and intersection, continue if no intersection
12375 item = this.items[i];
12376 itemElement = item.item[0];
12377 intersection = this._intersectsWithPointer(item);
12378 if (!intersection) {
12379 continue;
12380 }
12381
12382 // Only put the placeholder inside the current Container, skip all
12383 // items from other containers. This works because when moving
12384 // an item from one container to another the
12385 // currentContainer is switched before the placeholder is moved.
12386 //
12387 // Without this, moving items in "sub-sortables" can cause
12388 // the placeholder to jitter beetween the outer and inner container.
12389 if (item.instance !== this.currentContainer) {
12390 continue;
12391 }
12392
12393 // cannot intersect with itself
12394 // no useless actions that have been done before
12395 // no action if the item moved is the parent of the item checked
12396 if (itemElement !== this.currentItem[0] &&
12397 this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement &&
12398 !$.contains(this.placeholder[0], itemElement) &&
12399 (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true)
12400 ) {
12401
12402 this.direction = intersection === 1 ? "down" : "up";
12403
12404 if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
12405 this._rearrange(event, item);
12406 } else {
12407 break;
12408 }
12409
12410 this._trigger("change", event, this._uiHash());
12411 break;
12412 }
12413 }
12414
12415 //Post events to containers
12416 this._contactContainers(event);
12417
12418 //Interconnect with droppables
12419 if($.ui.ddmanager) {
12420 $.ui.ddmanager.drag(this, event);
12421 }
12422
12423 //Call callbacks
12424 this._trigger("sort", event, this._uiHash());
12425
12426 this.lastPositionAbs = this.positionAbs;
12427 return false;
12428
12429 },
12430
12431 _mouseStop: function(event, noPropagation) {
12432
12433 if(!event) {
12434 return;
12435 }
12436
12437 //If we are using droppables, inform the manager about the drop
12438 if ($.ui.ddmanager && !this.options.dropBehaviour) {
12439 $.ui.ddmanager.drop(this, event);
12440 }
12441
12442 if(this.options.revert) {
12443 var that = this,
12444 cur = this.placeholder.offset(),
12445 axis = this.options.axis,
12446 animation = {};
12447
12448 if ( !axis || axis === "x" ) {
12449 animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft);
12450 }
12451 if ( !axis || axis === "y" ) {
12452 animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop);
12453 }
12454 this.reverting = true;
12455 $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() {
12456 that._clear(event);
12457 });
12458 } else {
12459 this._clear(event, noPropagation);
12460 }
12461
12462 return false;
12463
12464 },
12465
12466 cancel: function() {
12467
12468 if(this.dragging) {
12469
12470 this._mouseUp({ target: null });
12471
12472 if(this.options.helper === "original") {
12473 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
12474 } else {
12475 this.currentItem.show();
12476 }
12477
12478 //Post deactivating events to containers
12479 for (var i = this.containers.length - 1; i >= 0; i--){
12480 this.containers[i]._trigger("deactivate", null, this._uiHash(this));
12481 if(this.containers[i].containerCache.over) {
12482 this.containers[i]._trigger("out", null, this._uiHash(this));
12483 this.containers[i].containerCache.over = 0;
12484 }
12485 }
12486
12487 }
12488
12489 if (this.placeholder) {
12490 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
12491 if(this.placeholder[0].parentNode) {
12492 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
12493 }
12494 if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) {
12495 this.helper.remove();
12496 }
12497
12498 $.extend(this, {
12499 helper: null,
12500 dragging: false,
12501 reverting: false,
12502 _noFinalSort: null
12503 });
12504
12505 if(this.domPosition.prev) {
12506 $(this.domPosition.prev).after(this.currentItem);
12507 } else {
12508 $(this.domPosition.parent).prepend(this.currentItem);
12509 }
12510 }
12511
12512 return this;
12513
12514 },
12515
12516 serialize: function(o) {
12517
12518 var items = this._getItemsAsjQuery(o && o.connected),
12519 str = [];
12520 o = o || {};
12521
12522 $(items).each(function() {
12523 var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/));
12524 if (res) {
12525 str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2]));
12526 }
12527 });
12528
12529 if(!str.length && o.key) {
12530 str.push(o.key + "=");
12531 }
12532
12533 return str.join("&");
12534
12535 },
12536
12537 toArray: function(o) {
12538
12539 var items = this._getItemsAsjQuery(o && o.connected),
12540 ret = [];
12541
12542 o = o || {};
12543
12544 items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); });
12545 return ret;
12546
12547 },
12548
12549 /* Be careful with the following core functions */
12550 _intersectsWith: function(item) {
12551
12552 var x1 = this.positionAbs.left,
12553 x2 = x1 + this.helperProportions.width,
12554 y1 = this.positionAbs.top,
12555 y2 = y1 + this.helperProportions.height,
12556 l = item.left,
12557 r = l + item.width,
12558 t = item.top,
12559 b = t + item.height,
12560 dyClick = this.offset.click.top,
12561 dxClick = this.offset.click.left,
12562 isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ),
12563 isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ),
12564 isOverElement = isOverElementHeight && isOverElementWidth;
12565
12566 if ( this.options.tolerance === "pointer" ||
12567 this.options.forcePointerForContainers ||
12568 (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"])
12569 ) {
12570 return isOverElement;
12571 } else {
12572
12573 return (l < x1 + (this.helperProportions.width / 2) && // Right Half
12574 x2 - (this.helperProportions.width / 2) < r && // Left Half
12575 t < y1 + (this.helperProportions.height / 2) && // Bottom Half
12576 y2 - (this.helperProportions.height / 2) < b ); // Top Half
12577
12578 }
12579 },
12580
12581 _intersectsWithPointer: function(item) {
12582
12583 var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
12584 isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
12585 isOverElement = isOverElementHeight && isOverElementWidth,
12586 verticalDirection = this._getDragVerticalDirection(),
12587 horizontalDirection = this._getDragHorizontalDirection();
12588
12589 if (!isOverElement) {
12590 return false;
12591 }
12592
12593 return this.floating ?
12594 ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 )
12595 : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) );
12596
12597 },
12598
12599 _intersectsWithSides: function(item) {
12600
12601 var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
12602 isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
12603 verticalDirection = this._getDragVerticalDirection(),
12604 horizontalDirection = this._getDragHorizontalDirection();
12605
12606 if (this.floating && horizontalDirection) {
12607 return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf));
12608 } else {
12609 return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf));
12610 }
12611
12612 },
12613
12614 _getDragVerticalDirection: function() {
12615 var delta = this.positionAbs.top - this.lastPositionAbs.top;
12616 return delta !== 0 && (delta > 0 ? "down" : "up");
12617 },
12618
12619 _getDragHorizontalDirection: function() {
12620 var delta = this.positionAbs.left - this.lastPositionAbs.left;
12621 return delta !== 0 && (delta > 0 ? "right" : "left");
12622 },
12623
12624 refresh: function(event) {
12625 this._refreshItems(event);
12626 this.refreshPositions();
12627 return this;
12628 },
12629
12630 _connectWith: function() {
12631 var options = this.options;
12632 return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith;
12633 },
12634
12635 _getItemsAsjQuery: function(connected) {
12636
12637 var i, j, cur, inst,
12638 items = [],
12639 queries = [],
12640 connectWith = this._connectWith();
12641
12642 if(connectWith && connected) {
12643 for (i = connectWith.length - 1; i >= 0; i--){
12644 cur = $(connectWith[i]);
12645 for ( j = cur.length - 1; j >= 0; j--){
12646 inst = $.data(cur[j], this.widgetFullName);
12647 if(inst && inst !== this && !inst.options.disabled) {
12648 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]);
12649 }
12650 }
12651 }
12652 }
12653
12654 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]);
12655
12656 function addItems() {
12657 items.push( this );
12658 }
12659 for (i = queries.length - 1; i >= 0; i--){
12660 queries[i][0].each( addItems );
12661 }
12662
12663 return $(items);
12664
12665 },
12666
12667 _removeCurrentsFromItems: function() {
12668
12669 var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
12670
12671 this.items = $.grep(this.items, function (item) {
12672 for (var j=0; j < list.length; j++) {
12673 if(list[j] === item.item[0]) {
12674 return false;
12675 }
12676 }
12677 return true;
12678 });
12679
12680 },
12681
12682 _refreshItems: function(event) {
12683
12684 this.items = [];
12685 this.containers = [this];
12686
12687 var i, j, cur, inst, targetData, _queries, item, queriesLength,
12688 items = this.items,
12689 queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]],
12690 connectWith = this._connectWith();
12691
12692 if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
12693 for (i = connectWith.length - 1; i >= 0; i--){
12694 cur = $(connectWith[i]);
12695 for (j = cur.length - 1; j >= 0; j--){
12696 inst = $.data(cur[j], this.widgetFullName);
12697 if(inst && inst !== this && !inst.options.disabled) {
12698 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
12699 this.containers.push(inst);
12700 }
12701 }
12702 }
12703 }
12704
12705 for (i = queries.length - 1; i >= 0; i--) {
12706 targetData = queries[i][1];
12707 _queries = queries[i][0];
12708
12709 for (j=0, queriesLength = _queries.length; j < queriesLength; j++) {
12710 item = $(_queries[j]);
12711
12712 item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager)
12713
12714 items.push({
12715 item: item,
12716 instance: targetData,
12717 width: 0, height: 0,
12718 left: 0, top: 0
12719 });
12720 }
12721 }
12722
12723 },
12724
12725 refreshPositions: function(fast) {
12726
12727 //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
12728 if(this.offsetParent && this.helper) {
12729 this.offset.parent = this._getParentOffset();
12730 }
12731
12732 var i, item, t, p;
12733
12734 for (i = this.items.length - 1; i >= 0; i--){
12735 item = this.items[i];
12736
12737 //We ignore calculating positions of all connected containers when we're not over them
12738 if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) {
12739 continue;
12740 }
12741
12742 t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
12743
12744 if (!fast) {
12745 item.width = t.outerWidth();
12746 item.height = t.outerHeight();
12747 }
12748
12749 p = t.offset();
12750 item.left = p.left;
12751 item.top = p.top;
12752 }
12753
12754 if(this.options.custom && this.options.custom.refreshContainers) {
12755 this.options.custom.refreshContainers.call(this);
12756 } else {
12757 for (i = this.containers.length - 1; i >= 0; i--){
12758 p = this.containers[i].element.offset();
12759 this.containers[i].containerCache.left = p.left;
12760 this.containers[i].containerCache.top = p.top;
12761 this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
12762 this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
12763 }
12764 }
12765
12766 return this;
12767 },
12768
12769 _createPlaceholder: function(that) {
12770 that = that || this;
12771 var className,
12772 o = that.options;
12773
12774 if(!o.placeholder || o.placeholder.constructor === String) {
12775 className = o.placeholder;
12776 o.placeholder = {
12777 element: function() {
12778
12779 var nodeName = that.currentItem[0].nodeName.toLowerCase(),
12780 element = $( "<" + nodeName + ">", that.document[0] )
12781 .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
12782 .removeClass("ui-sortable-helper");
12783
12784 if ( nodeName === "tr" ) {
12785 that.currentItem.children().each(function() {
12786 $( "<td>&#160;</td>", that.document[0] )
12787 .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
12788 .appendTo( element );
12789 });
12790 } else if ( nodeName === "img" ) {
12791 element.attr( "src", that.currentItem.attr( "src" ) );
12792 }
12793
12794 if ( !className ) {
12795 element.css( "visibility", "hidden" );
12796 }
12797
12798 return element;
12799 },
12800 update: function(container, p) {
12801
12802 // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
12803 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
12804 if(className && !o.forcePlaceholderSize) {
12805 return;
12806 }
12807
12808 //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
12809 if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); }
12810 if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); }
12811 }
12812 };
12813 }
12814
12815 //Create the placeholder
12816 that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));
12817
12818 //Append it after the actual current item
12819 that.currentItem.after(that.placeholder);
12820
12821 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
12822 o.placeholder.update(that, that.placeholder);
12823
12824 },
12825
12826 _contactContainers: function(event) {
12827 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom, floating,
12828 innermostContainer = null,
12829 innermostIndex = null;
12830
12831 // get innermost container that intersects with item
12832 for (i = this.containers.length - 1; i >= 0; i--) {
12833
12834 // never consider a container that's located within the item itself
12835 if($.contains(this.currentItem[0], this.containers[i].element[0])) {
12836 continue;
12837 }
12838
12839 if(this._intersectsWith(this.containers[i].containerCache)) {
12840
12841 // if we've already found a container and it's more "inner" than this, then continue
12842 if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) {
12843 continue;
12844 }
12845
12846 innermostContainer = this.containers[i];
12847 innermostIndex = i;
12848
12849 } else {
12850 // container doesn't intersect. trigger "out" event if necessary
12851 if(this.containers[i].containerCache.over) {
12852 this.containers[i]._trigger("out", event, this._uiHash(this));
12853 this.containers[i].containerCache.over = 0;
12854 }
12855 }
12856
12857 }
12858
12859 // if no intersecting containers found, return
12860 if(!innermostContainer) {
12861 return;
12862 }
12863
12864 // move the item into the container if it's not there already
12865 if(this.containers.length === 1) {
12866 if (!this.containers[innermostIndex].containerCache.over) {
12867 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
12868 this.containers[innermostIndex].containerCache.over = 1;
12869 }
12870 } else {
12871
12872 //When entering a new container, we will find the item with the least distance and append our item near it
12873 dist = 10000;
12874 itemWithLeastDistance = null;
12875 floating = innermostContainer.floating || isFloating(this.currentItem);
12876 posProperty = floating ? "left" : "top";
12877 sizeProperty = floating ? "width" : "height";
12878 base = this.positionAbs[posProperty] + this.offset.click[posProperty];
12879 for (j = this.items.length - 1; j >= 0; j--) {
12880 if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) {
12881 continue;
12882 }
12883 if(this.items[j].item[0] === this.currentItem[0]) {
12884 continue;
12885 }
12886 if (floating && !isOverAxis(this.positionAbs.top + this.offset.click.top, this.items[j].top, this.items[j].height)) {
12887 continue;
12888 }
12889 cur = this.items[j].item.offset()[posProperty];
12890 nearBottom = false;
12891 if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){
12892 nearBottom = true;
12893 cur += this.items[j][sizeProperty];
12894 }
12895
12896 if(Math.abs(cur - base) < dist) {
12897 dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j];
12898 this.direction = nearBottom ? "up": "down";
12899 }
12900 }
12901
12902 //Check if dropOnEmpty is enabled
12903 if(!itemWithLeastDistance && !this.options.dropOnEmpty) {
12904 return;
12905 }
12906
12907 if(this.currentContainer === this.containers[innermostIndex]) {
12908 return;
12909 }
12910
12911 itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
12912 this._trigger("change", event, this._uiHash());
12913 this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
12914 this.currentContainer = this.containers[innermostIndex];
12915
12916 //Update the placeholder
12917 this.options.placeholder.update(this.currentContainer, this.placeholder);
12918
12919 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
12920 this.containers[innermostIndex].containerCache.over = 1;
12921 }
12922
12923
12924 },
12925
12926 _createHelper: function(event) {
12927
12928 var o = this.options,
12929 helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem);
12930
12931 //Add the helper to the DOM if that didn't happen already
12932 if(!helper.parents("body").length) {
12933 $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
12934 }
12935
12936 if(helper[0] === this.currentItem[0]) {
12937 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") };
12938 }
12939
12940 if(!helper[0].style.width || o.forceHelperSize) {
12941 helper.width(this.currentItem.width());
12942 }
12943 if(!helper[0].style.height || o.forceHelperSize) {
12944 helper.height(this.currentItem.height());
12945 }
12946
12947 return helper;
12948
12949 },
12950
12951 _adjustOffsetFromHelper: function(obj) {
12952 if (typeof obj === "string") {
12953 obj = obj.split(" ");
12954 }
12955 if ($.isArray(obj)) {
12956 obj = {left: +obj[0], top: +obj[1] || 0};
12957 }
12958 if ("left" in obj) {
12959 this.offset.click.left = obj.left + this.margins.left;
12960 }
12961 if ("right" in obj) {
12962 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
12963 }
12964 if ("top" in obj) {
12965 this.offset.click.top = obj.top + this.margins.top;
12966 }
12967 if ("bottom" in obj) {
12968 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
12969 }
12970 },
12971
12972 _getParentOffset: function() {
12973
12974
12975 //Get the offsetParent and cache its position
12976 this.offsetParent = this.helper.offsetParent();
12977 var po = this.offsetParent.offset();
12978
12979 // This is a special case where we need to modify a offset calculated on start, since the following happened:
12980 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
12981 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
12982 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
12983 if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
12984 po.left += this.scrollParent.scrollLeft();
12985 po.top += this.scrollParent.scrollTop();
12986 }
12987
12988 // This needs to be actually done for all browsers, since pageX/pageY includes this information
12989 // with an ugly IE fix
12990 if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
12991 po = { top: 0, left: 0 };
12992 }
12993
12994 return {
12995 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
12996 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
12997 };
12998
12999 },
13000
13001 _getRelativeOffset: function() {
13002
13003 if(this.cssPosition === "relative") {
13004 var p = this.currentItem.position();
13005 return {
13006 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
13007 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
13008 };
13009 } else {
13010 return { top: 0, left: 0 };
13011 }
13012
13013 },
13014
13015 _cacheMargins: function() {
13016 this.margins = {
13017 left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
13018 top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
13019 };
13020 },
13021
13022 _cacheHelperProportions: function() {
13023 this.helperProportions = {
13024 width: this.helper.outerWidth(),
13025 height: this.helper.outerHeight()
13026 };
13027 },
13028
13029 _setContainment: function() {
13030
13031 var ce, co, over,
13032 o = this.options;
13033 if(o.containment === "parent") {
13034 o.containment = this.helper[0].parentNode;
13035 }
13036 if(o.containment === "document" || o.containment === "window") {
13037 this.containment = [
13038 0 - this.offset.relative.left - this.offset.parent.left,
13039 0 - this.offset.relative.top - this.offset.parent.top,
13040 $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left,
13041 ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
13042 ];
13043 }
13044
13045 if(!(/^(document|window|parent)$/).test(o.containment)) {
13046 ce = $(o.containment)[0];
13047 co = $(o.containment).offset();
13048 over = ($(ce).css("overflow") !== "hidden");
13049
13050 this.containment = [
13051 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
13052 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
13053 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,
13054 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
13055 ];
13056 }
13057
13058 },
13059
13060 _convertPositionTo: function(d, pos) {
13061
13062 if(!pos) {
13063 pos = this.position;
13064 }
13065 var mod = d === "absolute" ? 1 : -1,
13066 scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,
13067 scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
13068
13069 return {
13070 top: (
13071 pos.top + // The absolute mouse position
13072 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
13073 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
13074 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
13075 ),
13076 left: (
13077 pos.left + // The absolute mouse position
13078 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
13079 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
13080 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
13081 )
13082 };
13083
13084 },
13085
13086 _generatePosition: function(event) {
13087
13088 var top, left,
13089 o = this.options,
13090 pageX = event.pageX,
13091 pageY = event.pageY,
13092 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);
13093
13094 // This is another very weird special case that only happens for relative elements:
13095 // 1. If the css position is relative
13096 // 2. and the scroll parent is the document or similar to the offset parent
13097 // we have to refresh the relative offset during the scroll so there are no jumps
13098 if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) {
13099 this.offset.relative = this._getRelativeOffset();
13100 }
13101
13102 /*
13103 * - Position constraining -
13104 * Constrain the position to a mix of grid, containment.
13105 */
13106
13107 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
13108
13109 if(this.containment) {
13110 if(event.pageX - this.offset.click.left < this.containment[0]) {
13111 pageX = this.containment[0] + this.offset.click.left;
13112 }
13113 if(event.pageY - this.offset.click.top < this.containment[1]) {
13114 pageY = this.containment[1] + this.offset.click.top;
13115 }
13116 if(event.pageX - this.offset.click.left > this.containment[2]) {
13117 pageX = this.containment[2] + this.offset.click.left;
13118 }
13119 if(event.pageY - this.offset.click.top > this.containment[3]) {
13120 pageY = this.containment[3] + this.offset.click.top;
13121 }
13122 }
13123
13124 if(o.grid) {
13125 top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
13126 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;
13127
13128 left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
13129 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;
13130 }
13131
13132 }
13133
13134 return {
13135 top: (
13136 pageY - // The absolute mouse position
13137 this.offset.click.top - // Click offset (relative to the element)
13138 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
13139 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
13140 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
13141 ),
13142 left: (
13143 pageX - // The absolute mouse position
13144 this.offset.click.left - // Click offset (relative to the element)
13145 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
13146 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
13147 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
13148 )
13149 };
13150
13151 },
13152
13153 _rearrange: function(event, i, a, hardRefresh) {
13154
13155 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));
13156
13157 //Various things done here to improve the performance:
13158 // 1. we create a setTimeout, that calls refreshPositions
13159 // 2. on the instance, we have a counter variable, that get's higher after every append
13160 // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
13161 // 4. this lets only the last addition to the timeout stack through
13162 this.counter = this.counter ? ++this.counter : 1;
13163 var counter = this.counter;
13164
13165 this._delay(function() {
13166 if(counter === this.counter) {
13167 this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
13168 }
13169 });
13170
13171 },
13172
13173 _clear: function(event, noPropagation) {
13174
13175 this.reverting = false;
13176 // We delay all events that have to be triggered to after the point where the placeholder has been removed and
13177 // everything else normalized again
13178 var i,
13179 delayedTriggers = [];
13180
13181 // We first have to update the dom position of the actual currentItem
13182 // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
13183 if(!this._noFinalSort && this.currentItem.parent().length) {
13184 this.placeholder.before(this.currentItem);
13185 }
13186 this._noFinalSort = null;
13187
13188 if(this.helper[0] === this.currentItem[0]) {
13189 for(i in this._storedCSS) {
13190 if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") {
13191 this._storedCSS[i] = "";
13192 }
13193 }
13194 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
13195 } else {
13196 this.currentItem.show();
13197 }
13198
13199 if(this.fromOutside && !noPropagation) {
13200 delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
13201 }
13202 if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) {
13203 delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
13204 }
13205
13206 // Check if the items Container has Changed and trigger appropriate
13207 // events.
13208 if (this !== this.currentContainer) {
13209 if(!noPropagation) {
13210 delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
13211 delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
13212 delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
13213 }
13214 }
13215
13216
13217 //Post events to containers
13218 function delayEvent( type, instance, container ) {
13219 return function( event ) {
13220 container._trigger( type, event, instance._uiHash( instance ) );
13221 };
13222 }
13223 for (i = this.containers.length - 1; i >= 0; i--){
13224 if (!noPropagation) {
13225 delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
13226 }
13227 if(this.containers[i].containerCache.over) {
13228 delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
13229 this.containers[i].containerCache.over = 0;
13230 }
13231 }
13232
13233 //Do what was originally in plugins
13234 if ( this.storedCursor ) {
13235 this.document.find( "body" ).css( "cursor", this.storedCursor );
13236 this.storedStylesheet.remove();
13237 }
13238 if(this._storedOpacity) {
13239 this.helper.css("opacity", this._storedOpacity);
13240 }
13241 if(this._storedZIndex) {
13242 this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex);
13243 }
13244
13245 this.dragging = false;
13246 if(this.cancelHelperRemoval) {
13247 if(!noPropagation) {
13248 this._trigger("beforeStop", event, this._uiHash());
13249 for (i=0; i < delayedTriggers.length; i++) {
13250 delayedTriggers[i].call(this, event);
13251 } //Trigger all delayed events
13252 this._trigger("stop", event, this._uiHash());
13253 }
13254
13255 this.fromOutside = false;
13256 return false;
13257 }
13258
13259 if(!noPropagation) {
13260 this._trigger("beforeStop", event, this._uiHash());
13261 }
13262
13263 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
13264 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
13265
13266 if(this.helper[0] !== this.currentItem[0]) {
13267 this.helper.remove();
13268 }
13269 this.helper = null;
13270
13271 if(!noPropagation) {
13272 for (i=0; i < delayedTriggers.length; i++) {
13273 delayedTriggers[i].call(this, event);
13274 } //Trigger all delayed events
13275 this._trigger("stop", event, this._uiHash());
13276 }
13277
13278 this.fromOutside = false;
13279 return true;
13280
13281 },
13282
13283 _trigger: function() {
13284 if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
13285 this.cancel();
13286 }
13287 },
13288
13289 _uiHash: function(_inst) {
13290 var inst = _inst || this;
13291 return {
13292 helper: inst.helper,
13293 placeholder: inst.placeholder || $([]),
13294 position: inst.position,
13295 originalPosition: inst.originalPosition,
13296 offset: inst.positionAbs,
13297 item: inst.currentItem,
13298 sender: _inst ? _inst.element : null
13299 };
13300 }
13301
13302 });
13303
13304 })(jQuery);
13305 (function( $ ) {
13306
13307 function modifier( fn ) {
13308 return function() {
13309 var previous = this.element.val();
13310 fn.apply( this, arguments );
13311 this._refresh();
13312 if ( previous !== this.element.val() ) {
13313 this._trigger( "change" );
13314 }
13315 };
13316 }
13317
13318 $.widget( "ui.spinner", {
13319 version: "1.10.4",
13320 defaultElement: "<input>",
13321 widgetEventPrefix: "spin",
13322 options: {
13323 culture: null,
13324 icons: {
13325 down: "ui-icon-triangle-1-s",
13326 up: "ui-icon-triangle-1-n"
13327 },
13328 incremental: true,
13329 max: null,
13330 min: null,
13331 numberFormat: null,
13332 page: 10,
13333 step: 1,
13334
13335 change: null,
13336 spin: null,
13337 start: null,
13338 stop: null
13339 },
13340
13341 _create: function() {
13342 // handle string values that need to be parsed
13343 this._setOption( "max", this.options.max );
13344 this._setOption( "min", this.options.min );
13345 this._setOption( "step", this.options.step );
13346
13347 // Only format if there is a value, prevents the field from being marked
13348 // as invalid in Firefox, see #9573.
13349 if ( this.value() !== "" ) {
13350 // Format the value, but don't constrain.
13351 this._value( this.element.val(), true );
13352 }
13353
13354 this._draw();
13355 this._on( this._events );
13356 this._refresh();
13357
13358 // turning off autocomplete prevents the browser from remembering the
13359 // value when navigating through history, so we re-enable autocomplete
13360 // if the page is unloaded before the widget is destroyed. #7790
13361 this._on( this.window, {
13362 beforeunload: function() {
13363 this.element.removeAttr( "autocomplete" );
13364 }
13365 });
13366 },
13367
13368 _getCreateOptions: function() {
13369 var options = {},
13370 element = this.element;
13371
13372 $.each( [ "min", "max", "step" ], function( i, option ) {
13373 var value = element.attr( option );
13374 if ( value !== undefined && value.length ) {
13375 options[ option ] = value;
13376 }
13377 });
13378
13379 return options;
13380 },
13381
13382 _events: {
13383 keydown: function( event ) {
13384 if ( this._start( event ) && this._keydown( event ) ) {
13385 event.preventDefault();
13386 }
13387 },
13388 keyup: "_stop",
13389 focus: function() {
13390 this.previous = this.element.val();
13391 },
13392 blur: function( event ) {
13393 if ( this.cancelBlur ) {
13394 delete this.cancelBlur;
13395 return;
13396 }
13397
13398 this._stop();
13399 this._refresh();
13400 if ( this.previous !== this.element.val() ) {
13401 this._trigger( "change", event );
13402 }
13403 },
13404 mousewheel: function( event, delta ) {
13405 if ( !delta ) {
13406 return;
13407 }
13408 if ( !this.spinning && !this._start( event ) ) {
13409 return false;
13410 }
13411
13412 this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
13413 clearTimeout( this.mousewheelTimer );
13414 this.mousewheelTimer = this._delay(function() {
13415 if ( this.spinning ) {
13416 this._stop( event );
13417 }
13418 }, 100 );
13419 event.preventDefault();
13420 },
13421 "mousedown .ui-spinner-button": function( event ) {
13422 var previous;
13423
13424 // We never want the buttons to have focus; whenever the user is
13425 // interacting with the spinner, the focus should be on the input.
13426 // If the input is focused then this.previous is properly set from
13427 // when the input first received focus. If the input is not focused
13428 // then we need to set this.previous based on the value before spinning.
13429 previous = this.element[0] === this.document[0].activeElement ?
13430 this.previous : this.element.val();
13431 function checkFocus() {
13432 var isActive = this.element[0] === this.document[0].activeElement;
13433 if ( !isActive ) {
13434 this.element.focus();
13435 this.previous = previous;
13436 // support: IE
13437 // IE sets focus asynchronously, so we need to check if focus
13438 // moved off of the input because the user clicked on the button.
13439 this._delay(function() {
13440 this.previous = previous;
13441 });
13442 }
13443 }
13444
13445 // ensure focus is on (or stays on) the text field
13446 event.preventDefault();
13447 checkFocus.call( this );
13448
13449 // support: IE
13450 // IE doesn't prevent moving focus even with event.preventDefault()
13451 // so we set a flag to know when we should ignore the blur event
13452 // and check (again) if focus moved off of the input.
13453 this.cancelBlur = true;
13454 this._delay(function() {
13455 delete this.cancelBlur;
13456 checkFocus.call( this );
13457 });
13458
13459 if ( this._start( event ) === false ) {
13460 return;
13461 }
13462
13463 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
13464 },
13465 "mouseup .ui-spinner-button": "_stop",
13466 "mouseenter .ui-spinner-button": function( event ) {
13467 // button will add ui-state-active if mouse was down while mouseleave and kept down
13468 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
13469 return;
13470 }
13471
13472 if ( this._start( event ) === false ) {
13473 return false;
13474 }
13475 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
13476 },
13477 // TODO: do we really want to consider this a stop?
13478 // shouldn't we just stop the repeater and wait until mouseup before
13479 // we trigger the stop event?
13480 "mouseleave .ui-spinner-button": "_stop"
13481 },
13482
13483 _draw: function() {
13484 var uiSpinner = this.uiSpinner = this.element
13485 .addClass( "ui-spinner-input" )
13486 .attr( "autocomplete", "off" )
13487 .wrap( this._uiSpinnerHtml() )
13488 .parent()
13489 // add buttons
13490 .append( this._buttonHtml() );
13491
13492 this.element.attr( "role", "spinbutton" );
13493
13494 // button bindings
13495 this.buttons = uiSpinner.find( ".ui-spinner-button" )
13496 .attr( "tabIndex", -1 )
13497 .button()
13498 .removeClass( "ui-corner-all" );
13499
13500 // IE 6 doesn't understand height: 50% for the buttons
13501 // unless the wrapper has an explicit height
13502 if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&
13503 uiSpinner.height() > 0 ) {
13504 uiSpinner.height( uiSpinner.height() );
13505 }
13506
13507 // disable spinner if element was already disabled
13508 if ( this.options.disabled ) {
13509 this.disable();
13510 }
13511 },
13512
13513 _keydown: function( event ) {
13514 var options = this.options,
13515 keyCode = $.ui.keyCode;
13516
13517 switch ( event.keyCode ) {
13518 case keyCode.UP:
13519 this._repeat( null, 1, event );
13520 return true;
13521 case keyCode.DOWN:
13522 this._repeat( null, -1, event );
13523 return true;
13524 case keyCode.PAGE_UP:
13525 this._repeat( null, options.page, event );
13526 return true;
13527 case keyCode.PAGE_DOWN:
13528 this._repeat( null, -options.page, event );
13529 return true;
13530 }
13531
13532 return false;
13533 },
13534
13535 _uiSpinnerHtml: function() {
13536 return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>";
13537 },
13538
13539 _buttonHtml: function() {
13540 return "" +
13541 "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" +
13542 "<span class='ui-icon " + this.options.icons.up + "'>&#9650;</span>" +
13543 "</a>" +
13544 "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" +
13545 "<span class='ui-icon " + this.options.icons.down + "'>&#9660;</span>" +
13546 "</a>";
13547 },
13548
13549 _start: function( event ) {
13550 if ( !this.spinning && this._trigger( "start", event ) === false ) {
13551 return false;
13552 }
13553
13554 if ( !this.counter ) {
13555 this.counter = 1;
13556 }
13557 this.spinning = true;
13558 return true;
13559 },
13560
13561 _repeat: function( i, steps, event ) {
13562 i = i || 500;
13563
13564 clearTimeout( this.timer );
13565 this.timer = this._delay(function() {
13566 this._repeat( 40, steps, event );
13567 }, i );
13568
13569 this._spin( steps * this.options.step, event );
13570 },
13571
13572 _spin: function( step, event ) {
13573 var value = this.value() || 0;
13574
13575 if ( !this.counter ) {
13576 this.counter = 1;
13577 }
13578
13579 value = this._adjustValue( value + step * this._increment( this.counter ) );
13580
13581 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) {
13582 this._value( value );
13583 this.counter++;
13584 }
13585 },
13586
13587 _increment: function( i ) {
13588 var incremental = this.options.incremental;
13589
13590 if ( incremental ) {
13591 return $.isFunction( incremental ) ?
13592 incremental( i ) :
13593 Math.floor( i*i*i/50000 - i*i/500 + 17*i/200 + 1 );
13594 }
13595
13596 return 1;
13597 },
13598
13599 _precision: function() {
13600 var precision = this._precisionOf( this.options.step );
13601 if ( this.options.min !== null ) {
13602 precision = Math.max( precision, this._precisionOf( this.options.min ) );
13603 }
13604 return precision;
13605 },
13606
13607 _precisionOf: function( num ) {
13608 var str = num.toString(),
13609 decimal = str.indexOf( "." );
13610 return decimal === -1 ? 0 : str.length - decimal - 1;
13611 },
13612
13613 _adjustValue: function( value ) {
13614 var base, aboveMin,
13615 options = this.options;
13616
13617 // make sure we're at a valid step
13618 // - find out where we are relative to the base (min or 0)
13619 base = options.min !== null ? options.min : 0;
13620 aboveMin = value - base;
13621 // - round to the nearest step
13622 aboveMin = Math.round(aboveMin / options.step) * options.step;
13623 // - rounding is based on 0, so adjust back to our base
13624 value = base + aboveMin;
13625
13626 // fix precision from bad JS floating point math
13627 value = parseFloat( value.toFixed( this._precision() ) );
13628
13629 // clamp the value
13630 if ( options.max !== null && value > options.max) {
13631 return options.max;
13632 }
13633 if ( options.min !== null && value < options.min ) {
13634 return options.min;
13635 }
13636
13637 return value;
13638 },
13639
13640 _stop: function( event ) {
13641 if ( !this.spinning ) {
13642 return;
13643 }
13644
13645 clearTimeout( this.timer );
13646 clearTimeout( this.mousewheelTimer );
13647 this.counter = 0;
13648 this.spinning = false;
13649 this._trigger( "stop", event );
13650 },
13651
13652 _setOption: function( key, value ) {
13653 if ( key === "culture" || key === "numberFormat" ) {
13654 var prevValue = this._parse( this.element.val() );
13655 this.options[ key ] = value;
13656 this.element.val( this._format( prevValue ) );
13657 return;
13658 }
13659
13660 if ( key === "max" || key === "min" || key === "step" ) {
13661 if ( typeof value === "string" ) {
13662 value = this._parse( value );
13663 }
13664 }
13665 if ( key === "icons" ) {
13666 this.buttons.first().find( ".ui-icon" )
13667 .removeClass( this.options.icons.up )
13668 .addClass( value.up );
13669 this.buttons.last().find( ".ui-icon" )
13670 .removeClass( this.options.icons.down )
13671 .addClass( value.down );
13672 }
13673
13674 this._super( key, value );
13675
13676 if ( key === "disabled" ) {
13677 if ( value ) {
13678 this.element.prop( "disabled", true );
13679 this.buttons.button( "disable" );
13680 } else {
13681 this.element.prop( "disabled", false );
13682 this.buttons.button( "enable" );
13683 }
13684 }
13685 },
13686
13687 _setOptions: modifier(function( options ) {
13688 this._super( options );
13689 this._value( this.element.val() );
13690 }),
13691
13692 _parse: function( val ) {
13693 if ( typeof val === "string" && val !== "" ) {
13694 val = window.Globalize && this.options.numberFormat ?
13695 Globalize.parseFloat( val, 10, this.options.culture ) : +val;
13696 }
13697 return val === "" || isNaN( val ) ? null : val;
13698 },
13699
13700 _format: function( value ) {
13701 if ( value === "" ) {
13702 return "";
13703 }
13704 return window.Globalize && this.options.numberFormat ?
13705 Globalize.format( value, this.options.numberFormat, this.options.culture ) :
13706 value;
13707 },
13708
13709 _refresh: function() {
13710 this.element.attr({
13711 "aria-valuemin": this.options.min,
13712 "aria-valuemax": this.options.max,
13713 // TODO: what should we do with values that can't be parsed?
13714 "aria-valuenow": this._parse( this.element.val() )
13715 });
13716 },
13717
13718 // update the value without triggering change
13719 _value: function( value, allowAny ) {
13720 var parsed;
13721 if ( value !== "" ) {
13722 parsed = this._parse( value );
13723 if ( parsed !== null ) {
13724 if ( !allowAny ) {
13725 parsed = this._adjustValue( parsed );
13726 }
13727 value = this._format( parsed );
13728 }
13729 }
13730 this.element.val( value );
13731 this._refresh();
13732 },
13733
13734 _destroy: function() {
13735 this.element
13736 .removeClass( "ui-spinner-input" )
13737 .prop( "disabled", false )
13738 .removeAttr( "autocomplete" )
13739 .removeAttr( "role" )
13740 .removeAttr( "aria-valuemin" )
13741 .removeAttr( "aria-valuemax" )
13742 .removeAttr( "aria-valuenow" );
13743 this.uiSpinner.replaceWith( this.element );
13744 },
13745
13746 stepUp: modifier(function( steps ) {
13747 this._stepUp( steps );
13748 }),
13749 _stepUp: function( steps ) {
13750 if ( this._start() ) {
13751 this._spin( (steps || 1) * this.options.step );
13752 this._stop();
13753 }
13754 },
13755
13756 stepDown: modifier(function( steps ) {
13757 this._stepDown( steps );
13758 }),
13759 _stepDown: function( steps ) {
13760 if ( this._start() ) {
13761 this._spin( (steps || 1) * -this.options.step );
13762 this._stop();
13763 }
13764 },
13765
13766 pageUp: modifier(function( pages ) {
13767 this._stepUp( (pages || 1) * this.options.page );
13768 }),
13769
13770 pageDown: modifier(function( pages ) {
13771 this._stepDown( (pages || 1) * this.options.page );
13772 }),
13773
13774 value: function( newVal ) {
13775 if ( !arguments.length ) {
13776 return this._parse( this.element.val() );
13777 }
13778 modifier( this._value ).call( this, newVal );
13779 },
13780
13781 widget: function() {
13782 return this.uiSpinner;
13783 }
13784 });
13785
13786 }( jQuery ) );
13787 (function( $, undefined ) {
13788
13789 var tabId = 0,
13790 rhash = /#.*$/;
13791
13792 function getNextTabId() {
13793 return ++tabId;
13794 }
13795
13796 function isLocal( anchor ) {
13797 // support: IE7
13798 // IE7 doesn't normalize the href property when set via script (#9317)
13799 anchor = anchor.cloneNode( false );
13800
13801 return anchor.hash.length > 1 &&
13802 decodeURIComponent( anchor.href.replace( rhash, "" ) ) ===
13803 decodeURIComponent( location.href.replace( rhash, "" ) );
13804 }
13805
13806 $.widget( "ui.tabs", {
13807 version: "1.10.4",
13808 delay: 300,
13809 options: {
13810 active: null,
13811 collapsible: false,
13812 event: "click",
13813 heightStyle: "content",
13814 hide: null,
13815 show: null,
13816
13817 // callbacks
13818 activate: null,
13819 beforeActivate: null,
13820 beforeLoad: null,
13821 load: null
13822 },
13823
13824 _create: function() {
13825 var that = this,
13826 options = this.options;
13827
13828 this.running = false;
13829
13830 this.element
13831 .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" )
13832 .toggleClass( "ui-tabs-collapsible", options.collapsible )
13833 // Prevent users from focusing disabled tabs via click
13834 .delegate( ".ui-tabs-nav > li", "mousedown" + this.eventNamespace, function( event ) {
13835 if ( $( this ).is( ".ui-state-disabled" ) ) {
13836 event.preventDefault();
13837 }
13838 })
13839 // support: IE <9
13840 // Preventing the default action in mousedown doesn't prevent IE
13841 // from focusing the element, so if the anchor gets focused, blur.
13842 // We don't have to worry about focusing the previously focused
13843 // element since clicking on a non-focusable element should focus
13844 // the body anyway.
13845 .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() {
13846 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
13847 this.blur();
13848 }
13849 });
13850
13851 this._processTabs();
13852 options.active = this._initialActive();
13853
13854 // Take disabling tabs via class attribute from HTML
13855 // into account and update option properly.
13856 if ( $.isArray( options.disabled ) ) {
13857 options.disabled = $.unique( options.disabled.concat(
13858 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
13859 return that.tabs.index( li );
13860 })
13861 ) ).sort();
13862 }
13863
13864 // check for length avoids error when initializing empty list
13865 if ( this.options.active !== false && this.anchors.length ) {
13866 this.active = this._findActive( options.active );
13867 } else {
13868 this.active = $();
13869 }
13870
13871 this._refresh();
13872
13873 if ( this.active.length ) {
13874 this.load( options.active );
13875 }
13876 },
13877
13878 _initialActive: function() {
13879 var active = this.options.active,
13880 collapsible = this.options.collapsible,
13881 locationHash = location.hash.substring( 1 );
13882
13883 if ( active === null ) {
13884 // check the fragment identifier in the URL
13885 if ( locationHash ) {
13886 this.tabs.each(function( i, tab ) {
13887 if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
13888 active = i;
13889 return false;
13890 }
13891 });
13892 }
13893
13894 // check for a tab marked active via a class
13895 if ( active === null ) {
13896 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
13897 }
13898
13899 // no active tab, set to false
13900 if ( active === null || active === -1 ) {
13901 active = this.tabs.length ? 0 : false;
13902 }
13903 }
13904
13905 // handle numbers: negative, out of range
13906 if ( active !== false ) {
13907 active = this.tabs.index( this.tabs.eq( active ) );
13908 if ( active === -1 ) {
13909 active = collapsible ? false : 0;
13910 }
13911 }
13912
13913 // don't allow collapsible: false and active: false
13914 if ( !collapsible && active === false && this.anchors.length ) {
13915 active = 0;
13916 }
13917
13918 return active;
13919 },
13920
13921 _getCreateEventData: function() {
13922 return {
13923 tab: this.active,
13924 panel: !this.active.length ? $() : this._getPanelForTab( this.active )
13925 };
13926 },
13927
13928 _tabKeydown: function( event ) {
13929 var focusedTab = $( this.document[0].activeElement ).closest( "li" ),
13930 selectedIndex = this.tabs.index( focusedTab ),
13931 goingForward = true;
13932
13933 if ( this._handlePageNav( event ) ) {
13934 return;
13935 }
13936
13937 switch ( event.keyCode ) {
13938 case $.ui.keyCode.RIGHT:
13939 case $.ui.keyCode.DOWN:
13940 selectedIndex++;
13941 break;
13942 case $.ui.keyCode.UP:
13943 case $.ui.keyCode.LEFT:
13944 goingForward = false;
13945 selectedIndex--;
13946 break;
13947 case $.ui.keyCode.END:
13948 selectedIndex = this.anchors.length - 1;
13949 break;
13950 case $.ui.keyCode.HOME:
13951 selectedIndex = 0;
13952 break;
13953 case $.ui.keyCode.SPACE:
13954 // Activate only, no collapsing
13955 event.preventDefault();
13956 clearTimeout( this.activating );
13957 this._activate( selectedIndex );
13958 return;
13959 case $.ui.keyCode.ENTER:
13960 // Toggle (cancel delayed activation, allow collapsing)
13961 event.preventDefault();
13962 clearTimeout( this.activating );
13963 // Determine if we should collapse or activate
13964 this._activate( selectedIndex === this.options.active ? false : selectedIndex );
13965 return;
13966 default:
13967 return;
13968 }
13969
13970 // Focus the appropriate tab, based on which key was pressed
13971 event.preventDefault();
13972 clearTimeout( this.activating );
13973 selectedIndex = this._focusNextTab( selectedIndex, goingForward );
13974
13975 // Navigating with control key will prevent automatic activation
13976 if ( !event.ctrlKey ) {
13977 // Update aria-selected immediately so that AT think the tab is already selected.
13978 // Otherwise AT may confuse the user by stating that they need to activate the tab,
13979 // but the tab will already be activated by the time the announcement finishes.
13980 focusedTab.attr( "aria-selected", "false" );
13981 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
13982
13983 this.activating = this._delay(function() {
13984 this.option( "active", selectedIndex );
13985 }, this.delay );
13986 }
13987 },
13988
13989 _panelKeydown: function( event ) {
13990 if ( this._handlePageNav( event ) ) {
13991 return;
13992 }
13993
13994 // Ctrl+up moves focus to the current tab
13995 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
13996 event.preventDefault();
13997 this.active.focus();
13998 }
13999 },
14000
14001 // Alt+page up/down moves focus to the previous/next tab (and activates)
14002 _handlePageNav: function( event ) {
14003 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
14004 this._activate( this._focusNextTab( this.options.active - 1, false ) );
14005 return true;
14006 }
14007 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
14008 this._activate( this._focusNextTab( this.options.active + 1, true ) );
14009 return true;
14010 }
14011 },
14012
14013 _findNextTab: function( index, goingForward ) {
14014 var lastTabIndex = this.tabs.length - 1;
14015
14016 function constrain() {
14017 if ( index > lastTabIndex ) {
14018 index = 0;
14019 }
14020 if ( index < 0 ) {
14021 index = lastTabIndex;
14022 }
14023 return index;
14024 }
14025
14026 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
14027 index = goingForward ? index + 1 : index - 1;
14028 }
14029
14030 return index;
14031 },
14032
14033 _focusNextTab: function( index, goingForward ) {
14034 index = this._findNextTab( index, goingForward );
14035 this.tabs.eq( index ).focus();
14036 return index;
14037 },
14038
14039 _setOption: function( key, value ) {
14040 if ( key === "active" ) {
14041 // _activate() will handle invalid values and update this.options
14042 this._activate( value );
14043 return;
14044 }
14045
14046 if ( key === "disabled" ) {
14047 // don't use the widget factory's disabled handling
14048 this._setupDisabled( value );
14049 return;
14050 }
14051
14052 this._super( key, value);
14053
14054 if ( key === "collapsible" ) {
14055 this.element.toggleClass( "ui-tabs-collapsible", value );
14056 // Setting collapsible: false while collapsed; open first panel
14057 if ( !value && this.options.active === false ) {
14058 this._activate( 0 );
14059 }
14060 }
14061
14062 if ( key === "event" ) {
14063 this._setupEvents( value );
14064 }
14065
14066 if ( key === "heightStyle" ) {
14067 this._setupHeightStyle( value );
14068 }
14069 },
14070
14071 _tabId: function( tab ) {
14072 return tab.attr( "aria-controls" ) || "ui-tabs-" + getNextTabId();
14073 },
14074
14075 _sanitizeSelector: function( hash ) {
14076 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
14077 },
14078
14079 refresh: function() {
14080 var options = this.options,
14081 lis = this.tablist.children( ":has(a[href])" );
14082
14083 // get disabled tabs from class attribute from HTML
14084 // this will get converted to a boolean if needed in _refresh()
14085 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
14086 return lis.index( tab );
14087 });
14088
14089 this._processTabs();
14090
14091 // was collapsed or no tabs
14092 if ( options.active === false || !this.anchors.length ) {
14093 options.active = false;
14094 this.active = $();
14095 // was active, but active tab is gone
14096 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
14097 // all remaining tabs are disabled
14098 if ( this.tabs.length === options.disabled.length ) {
14099 options.active = false;
14100 this.active = $();
14101 // activate previous tab
14102 } else {
14103 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
14104 }
14105 // was active, active tab still exists
14106 } else {
14107 // make sure active index is correct
14108 options.active = this.tabs.index( this.active );
14109 }
14110
14111 this._refresh();
14112 },
14113
14114 _refresh: function() {
14115 this._setupDisabled( this.options.disabled );
14116 this._setupEvents( this.options.event );
14117 this._setupHeightStyle( this.options.heightStyle );
14118
14119 this.tabs.not( this.active ).attr({
14120 "aria-selected": "false",
14121 tabIndex: -1
14122 });
14123 this.panels.not( this._getPanelForTab( this.active ) )
14124 .hide()
14125 .attr({
14126 "aria-expanded": "false",
14127 "aria-hidden": "true"
14128 });
14129
14130 // Make sure one tab is in the tab order
14131 if ( !this.active.length ) {
14132 this.tabs.eq( 0 ).attr( "tabIndex", 0 );
14133 } else {
14134 this.active
14135 .addClass( "ui-tabs-active ui-state-active" )
14136 .attr({
14137 "aria-selected": "true",
14138 tabIndex: 0
14139 });
14140 this._getPanelForTab( this.active )
14141 .show()
14142 .attr({
14143 "aria-expanded": "true",
14144 "aria-hidden": "false"
14145 });
14146 }
14147 },
14148
14149 _processTabs: function() {
14150 var that = this;
14151
14152 this.tablist = this._getList()
14153 .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
14154 .attr( "role", "tablist" );
14155
14156 this.tabs = this.tablist.find( "> li:has(a[href])" )
14157 .addClass( "ui-state-default ui-corner-top" )
14158 .attr({
14159 role: "tab",
14160 tabIndex: -1
14161 });
14162
14163 this.anchors = this.tabs.map(function() {
14164 return $( "a", this )[ 0 ];
14165 })
14166 .addClass( "ui-tabs-anchor" )
14167 .attr({
14168 role: "presentation",
14169 tabIndex: -1
14170 });
14171
14172 this.panels = $();
14173
14174 this.anchors.each(function( i, anchor ) {
14175 var selector, panel, panelId,
14176 anchorId = $( anchor ).uniqueId().attr( "id" ),
14177 tab = $( anchor ).closest( "li" ),
14178 originalAriaControls = tab.attr( "aria-controls" );
14179
14180 // inline tab
14181 if ( isLocal( anchor ) ) {
14182 selector = anchor.hash;
14183 panel = that.element.find( that._sanitizeSelector( selector ) );
14184 // remote tab
14185 } else {
14186 panelId = that._tabId( tab );
14187 selector = "#" + panelId;
14188 panel = that.element.find( selector );
14189 if ( !panel.length ) {
14190 panel = that._createPanel( panelId );
14191 panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
14192 }
14193 panel.attr( "aria-live", "polite" );
14194 }
14195
14196 if ( panel.length) {
14197 that.panels = that.panels.add( panel );
14198 }
14199 if ( originalAriaControls ) {
14200 tab.data( "ui-tabs-aria-controls", originalAriaControls );
14201 }
14202 tab.attr({
14203 "aria-controls": selector.substring( 1 ),
14204 "aria-labelledby": anchorId
14205 });
14206 panel.attr( "aria-labelledby", anchorId );
14207 });
14208
14209 this.panels
14210 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
14211 .attr( "role", "tabpanel" );
14212 },
14213
14214 // allow overriding how to find the list for rare usage scenarios (#7715)
14215 _getList: function() {
14216 return this.tablist || this.element.find( "ol,ul" ).eq( 0 );
14217 },
14218
14219 _createPanel: function( id ) {
14220 return $( "<div>" )
14221 .attr( "id", id )
14222 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
14223 .data( "ui-tabs-destroy", true );
14224 },
14225
14226 _setupDisabled: function( disabled ) {
14227 if ( $.isArray( disabled ) ) {
14228 if ( !disabled.length ) {
14229 disabled = false;
14230 } else if ( disabled.length === this.anchors.length ) {
14231 disabled = true;
14232 }
14233 }
14234
14235 // disable tabs
14236 for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {
14237 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
14238 $( li )
14239 .addClass( "ui-state-disabled" )
14240 .attr( "aria-disabled", "true" );
14241 } else {
14242 $( li )
14243 .removeClass( "ui-state-disabled" )
14244 .removeAttr( "aria-disabled" );
14245 }
14246 }
14247
14248 this.options.disabled = disabled;
14249 },
14250
14251 _setupEvents: function( event ) {
14252 var events = {
14253 click: function( event ) {
14254 event.preventDefault();
14255 }
14256 };
14257 if ( event ) {
14258 $.each( event.split(" "), function( index, eventName ) {
14259 events[ eventName ] = "_eventHandler";
14260 });
14261 }
14262
14263 this._off( this.anchors.add( this.tabs ).add( this.panels ) );
14264 this._on( this.anchors, events );
14265 this._on( this.tabs, { keydown: "_tabKeydown" } );
14266 this._on( this.panels, { keydown: "_panelKeydown" } );
14267
14268 this._focusable( this.tabs );
14269 this._hoverable( this.tabs );
14270 },
14271
14272 _setupHeightStyle: function( heightStyle ) {
14273 var maxHeight,
14274 parent = this.element.parent();
14275
14276 if ( heightStyle === "fill" ) {
14277 maxHeight = parent.height();
14278 maxHeight -= this.element.outerHeight() - this.element.height();
14279
14280 this.element.siblings( ":visible" ).each(function() {
14281 var elem = $( this ),
14282 position = elem.css( "position" );
14283
14284 if ( position === "absolute" || position === "fixed" ) {
14285 return;
14286 }
14287 maxHeight -= elem.outerHeight( true );
14288 });
14289
14290 this.element.children().not( this.panels ).each(function() {
14291 maxHeight -= $( this ).outerHeight( true );
14292 });
14293
14294 this.panels.each(function() {
14295 $( this ).height( Math.max( 0, maxHeight -
14296 $( this ).innerHeight() + $( this ).height() ) );
14297 })
14298 .css( "overflow", "auto" );
14299 } else if ( heightStyle === "auto" ) {
14300 maxHeight = 0;
14301 this.panels.each(function() {
14302 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
14303 }).height( maxHeight );
14304 }
14305 },
14306
14307 _eventHandler: function( event ) {
14308 var options = this.options,
14309 active = this.active,
14310 anchor = $( event.currentTarget ),
14311 tab = anchor.closest( "li" ),
14312 clickedIsActive = tab[ 0 ] === active[ 0 ],
14313 collapsing = clickedIsActive && options.collapsible,
14314 toShow = collapsing ? $() : this._getPanelForTab( tab ),
14315 toHide = !active.length ? $() : this._getPanelForTab( active ),
14316 eventData = {
14317 oldTab: active,
14318 oldPanel: toHide,
14319 newTab: collapsing ? $() : tab,
14320 newPanel: toShow
14321 };
14322
14323 event.preventDefault();
14324
14325 if ( tab.hasClass( "ui-state-disabled" ) ||
14326 // tab is already loading
14327 tab.hasClass( "ui-tabs-loading" ) ||
14328 // can't switch durning an animation
14329 this.running ||
14330 // click on active header, but not collapsible
14331 ( clickedIsActive && !options.collapsible ) ||
14332 // allow canceling activation
14333 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
14334 return;
14335 }
14336
14337 options.active = collapsing ? false : this.tabs.index( tab );
14338
14339 this.active = clickedIsActive ? $() : tab;
14340 if ( this.xhr ) {
14341 this.xhr.abort();
14342 }
14343
14344 if ( !toHide.length && !toShow.length ) {
14345 $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
14346 }
14347
14348 if ( toShow.length ) {
14349 this.load( this.tabs.index( tab ), event );
14350 }
14351 this._toggle( event, eventData );
14352 },
14353
14354 // handles show/hide for selecting tabs
14355 _toggle: function( event, eventData ) {
14356 var that = this,
14357 toShow = eventData.newPanel,
14358 toHide = eventData.oldPanel;
14359
14360 this.running = true;
14361
14362 function complete() {
14363 that.running = false;
14364 that._trigger( "activate", event, eventData );
14365 }
14366
14367 function show() {
14368 eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
14369
14370 if ( toShow.length && that.options.show ) {
14371 that._show( toShow, that.options.show, complete );
14372 } else {
14373 toShow.show();
14374 complete();
14375 }
14376 }
14377
14378 // start out by hiding, then showing, then completing
14379 if ( toHide.length && this.options.hide ) {
14380 this._hide( toHide, this.options.hide, function() {
14381 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
14382 show();
14383 });
14384 } else {
14385 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
14386 toHide.hide();
14387 show();
14388 }
14389
14390 toHide.attr({
14391 "aria-expanded": "false",
14392 "aria-hidden": "true"
14393 });
14394 eventData.oldTab.attr( "aria-selected", "false" );
14395 // If we're switching tabs, remove the old tab from the tab order.
14396 // If we're opening from collapsed state, remove the previous tab from the tab order.
14397 // If we're collapsing, then keep the collapsing tab in the tab order.
14398 if ( toShow.length && toHide.length ) {
14399 eventData.oldTab.attr( "tabIndex", -1 );
14400 } else if ( toShow.length ) {
14401 this.tabs.filter(function() {
14402 return $( this ).attr( "tabIndex" ) === 0;
14403 })
14404 .attr( "tabIndex", -1 );
14405 }
14406
14407 toShow.attr({
14408 "aria-expanded": "true",
14409 "aria-hidden": "false"
14410 });
14411 eventData.newTab.attr({
14412 "aria-selected": "true",
14413 tabIndex: 0
14414 });
14415 },
14416
14417 _activate: function( index ) {
14418 var anchor,
14419 active = this._findActive( index );
14420
14421 // trying to activate the already active panel
14422 if ( active[ 0 ] === this.active[ 0 ] ) {
14423 return;
14424 }
14425
14426 // trying to collapse, simulate a click on the current active header
14427 if ( !active.length ) {
14428 active = this.active;
14429 }
14430
14431 anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
14432 this._eventHandler({
14433 target: anchor,
14434 currentTarget: anchor,
14435 preventDefault: $.noop
14436 });
14437 },
14438
14439 _findActive: function( index ) {
14440 return index === false ? $() : this.tabs.eq( index );
14441 },
14442
14443 _getIndex: function( index ) {
14444 // meta-function to give users option to provide a href string instead of a numerical index.
14445 if ( typeof index === "string" ) {
14446 index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) );
14447 }
14448
14449 return index;
14450 },
14451
14452 _destroy: function() {
14453 if ( this.xhr ) {
14454 this.xhr.abort();
14455 }
14456
14457 this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" );
14458
14459 this.tablist
14460 .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
14461 .removeAttr( "role" );
14462
14463 this.anchors
14464 .removeClass( "ui-tabs-anchor" )
14465 .removeAttr( "role" )
14466 .removeAttr( "tabIndex" )
14467 .removeUniqueId();
14468
14469 this.tabs.add( this.panels ).each(function() {
14470 if ( $.data( this, "ui-tabs-destroy" ) ) {
14471 $( this ).remove();
14472 } else {
14473 $( this )
14474 .removeClass( "ui-state-default ui-state-active ui-state-disabled " +
14475 "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" )
14476 .removeAttr( "tabIndex" )
14477 .removeAttr( "aria-live" )
14478 .removeAttr( "aria-busy" )
14479 .removeAttr( "aria-selected" )
14480 .removeAttr( "aria-labelledby" )
14481 .removeAttr( "aria-hidden" )
14482 .removeAttr( "aria-expanded" )
14483 .removeAttr( "role" );
14484 }
14485 });
14486
14487 this.tabs.each(function() {
14488 var li = $( this ),
14489 prev = li.data( "ui-tabs-aria-controls" );
14490 if ( prev ) {
14491 li
14492 .attr( "aria-controls", prev )
14493 .removeData( "ui-tabs-aria-controls" );
14494 } else {
14495 li.removeAttr( "aria-controls" );
14496 }
14497 });
14498
14499 this.panels.show();
14500
14501 if ( this.options.heightStyle !== "content" ) {
14502 this.panels.css( "height", "" );
14503 }
14504 },
14505
14506 enable: function( index ) {
14507 var disabled = this.options.disabled;
14508 if ( disabled === false ) {
14509 return;
14510 }
14511
14512 if ( index === undefined ) {
14513 disabled = false;
14514 } else {
14515 index = this._getIndex( index );
14516 if ( $.isArray( disabled ) ) {
14517 disabled = $.map( disabled, function( num ) {
14518 return num !== index ? num : null;
14519 });
14520 } else {
14521 disabled = $.map( this.tabs, function( li, num ) {
14522 return num !== index ? num : null;
14523 });
14524 }
14525 }
14526 this._setupDisabled( disabled );
14527 },
14528
14529 disable: function( index ) {
14530 var disabled = this.options.disabled;
14531 if ( disabled === true ) {
14532 return;
14533 }
14534
14535 if ( index === undefined ) {
14536 disabled = true;
14537 } else {
14538 index = this._getIndex( index );
14539 if ( $.inArray( index, disabled ) !== -1 ) {
14540 return;
14541 }
14542 if ( $.isArray( disabled ) ) {
14543 disabled = $.merge( [ index ], disabled ).sort();
14544 } else {
14545 disabled = [ index ];
14546 }
14547 }
14548 this._setupDisabled( disabled );
14549 },
14550
14551 load: function( index, event ) {
14552 index = this._getIndex( index );
14553 var that = this,
14554 tab = this.tabs.eq( index ),
14555 anchor = tab.find( ".ui-tabs-anchor" ),
14556 panel = this._getPanelForTab( tab ),
14557 eventData = {
14558 tab: tab,
14559 panel: panel
14560 };
14561
14562 // not remote
14563 if ( isLocal( anchor[ 0 ] ) ) {
14564 return;
14565 }
14566
14567 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
14568
14569 // support: jQuery <1.8
14570 // jQuery <1.8 returns false if the request is canceled in beforeSend,
14571 // but as of 1.8, $.ajax() always returns a jqXHR object.
14572 if ( this.xhr && this.xhr.statusText !== "canceled" ) {
14573 tab.addClass( "ui-tabs-loading" );
14574 panel.attr( "aria-busy", "true" );
14575
14576 this.xhr
14577 .success(function( response ) {
14578 // support: jQuery <1.8
14579 // http://bugs.jquery.com/ticket/11778
14580 setTimeout(function() {
14581 panel.html( response );
14582 that._trigger( "load", event, eventData );
14583 }, 1 );
14584 })
14585 .complete(function( jqXHR, status ) {
14586 // support: jQuery <1.8
14587 // http://bugs.jquery.com/ticket/11778
14588 setTimeout(function() {
14589 if ( status === "abort" ) {
14590 that.panels.stop( false, true );
14591 }
14592
14593 tab.removeClass( "ui-tabs-loading" );
14594 panel.removeAttr( "aria-busy" );
14595
14596 if ( jqXHR === that.xhr ) {
14597 delete that.xhr;
14598 }
14599 }, 1 );
14600 });
14601 }
14602 },
14603
14604 _ajaxSettings: function( anchor, event, eventData ) {
14605 var that = this;
14606 return {
14607 url: anchor.attr( "href" ),
14608 beforeSend: function( jqXHR, settings ) {
14609 return that._trigger( "beforeLoad", event,
14610 $.extend( { jqXHR : jqXHR, ajaxSettings: settings }, eventData ) );
14611 }
14612 };
14613 },
14614
14615 _getPanelForTab: function( tab ) {
14616 var id = $( tab ).attr( "aria-controls" );
14617 return this.element.find( this._sanitizeSelector( "#" + id ) );
14618 }
14619 });
14620
14621 })( jQuery );
14622 (function( $ ) {
14623
14624 var increments = 0;
14625
14626 function addDescribedBy( elem, id ) {
14627 var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ );
14628 describedby.push( id );
14629 elem
14630 .data( "ui-tooltip-id", id )
14631 .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
14632 }
14633
14634 function removeDescribedBy( elem ) {
14635 var id = elem.data( "ui-tooltip-id" ),
14636 describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ),
14637 index = $.inArray( id, describedby );
14638 if ( index !== -1 ) {
14639 describedby.splice( index, 1 );
14640 }
14641
14642 elem.removeData( "ui-tooltip-id" );
14643 describedby = $.trim( describedby.join( " " ) );
14644 if ( describedby ) {
14645 elem.attr( "aria-describedby", describedby );
14646 } else {
14647 elem.removeAttr( "aria-describedby" );
14648 }
14649 }
14650
14651 $.widget( "ui.tooltip", {
14652 version: "1.10.4",
14653 options: {
14654 content: function() {
14655 // support: IE<9, Opera in jQuery <1.7
14656 // .text() can't accept undefined, so coerce to a string
14657 var title = $( this ).attr( "title" ) || "";
14658 // Escape title, since we're going from an attribute to raw HTML
14659 return $( "<a>" ).text( title ).html();
14660 },
14661 hide: true,
14662 // Disabled elements have inconsistent behavior across browsers (#8661)
14663 items: "[title]:not([disabled])",
14664 position: {
14665 my: "left top+15",
14666 at: "left bottom",
14667 collision: "flipfit flip"
14668 },
14669 show: true,
14670 tooltipClass: null,
14671 track: false,
14672
14673 // callbacks
14674 close: null,
14675 open: null
14676 },
14677
14678 _create: function() {
14679 this._on({
14680 mouseover: "open",
14681 focusin: "open"
14682 });
14683
14684 // IDs of generated tooltips, needed for destroy
14685 this.tooltips = {};
14686 // IDs of parent tooltips where we removed the title attribute
14687 this.parents = {};
14688
14689 if ( this.options.disabled ) {
14690 this._disable();
14691 }
14692 },
14693
14694 _setOption: function( key, value ) {
14695 var that = this;
14696
14697 if ( key === "disabled" ) {
14698 this[ value ? "_disable" : "_enable" ]();
14699 this.options[ key ] = value;
14700 // disable element style changes
14701 return;
14702 }
14703
14704 this._super( key, value );
14705
14706 if ( key === "content" ) {
14707 $.each( this.tooltips, function( id, element ) {
14708 that._updateContent( element );
14709 });
14710 }
14711 },
14712
14713 _disable: function() {
14714 var that = this;
14715
14716 // close open tooltips
14717 $.each( this.tooltips, function( id, element ) {
14718 var event = $.Event( "blur" );
14719 event.target = event.currentTarget = element[0];
14720 that.close( event, true );
14721 });
14722
14723 // remove title attributes to prevent native tooltips
14724 this.element.find( this.options.items ).addBack().each(function() {
14725 var element = $( this );
14726 if ( element.is( "[title]" ) ) {
14727 element
14728 .data( "ui-tooltip-title", element.attr( "title" ) )
14729 .attr( "title", "" );
14730 }
14731 });
14732 },
14733
14734 _enable: function() {
14735 // restore title attributes
14736 this.element.find( this.options.items ).addBack().each(function() {
14737 var element = $( this );
14738 if ( element.data( "ui-tooltip-title" ) ) {
14739 element.attr( "title", element.data( "ui-tooltip-title" ) );
14740 }
14741 });
14742 },
14743
14744 open: function( event ) {
14745 var that = this,
14746 target = $( event ? event.target : this.element )
14747 // we need closest here due to mouseover bubbling,
14748 // but always pointing at the same event target
14749 .closest( this.options.items );
14750
14751 // No element to show a tooltip for or the tooltip is already open
14752 if ( !target.length || target.data( "ui-tooltip-id" ) ) {
14753 return;
14754 }
14755
14756 if ( target.attr( "title" ) ) {
14757 target.data( "ui-tooltip-title", target.attr( "title" ) );
14758 }
14759
14760 target.data( "ui-tooltip-open", true );
14761
14762 // kill parent tooltips, custom or native, for hover
14763 if ( event && event.type === "mouseover" ) {
14764 target.parents().each(function() {
14765 var parent = $( this ),
14766 blurEvent;
14767 if ( parent.data( "ui-tooltip-open" ) ) {
14768 blurEvent = $.Event( "blur" );
14769 blurEvent.target = blurEvent.currentTarget = this;
14770 that.close( blurEvent, true );
14771 }
14772 if ( parent.attr( "title" ) ) {
14773 parent.uniqueId();
14774 that.parents[ this.id ] = {
14775 element: this,
14776 title: parent.attr( "title" )
14777 };
14778 parent.attr( "title", "" );
14779 }
14780 });
14781 }
14782
14783 this._updateContent( target, event );
14784 },
14785
14786 _updateContent: function( target, event ) {
14787 var content,
14788 contentOption = this.options.content,
14789 that = this,
14790 eventType = event ? event.type : null;
14791
14792 if ( typeof contentOption === "string" ) {
14793 return this._open( event, target, contentOption );
14794 }
14795
14796 content = contentOption.call( target[0], function( response ) {
14797 // ignore async response if tooltip was closed already
14798 if ( !target.data( "ui-tooltip-open" ) ) {
14799 return;
14800 }
14801 // IE may instantly serve a cached response for ajax requests
14802 // delay this call to _open so the other call to _open runs first
14803 that._delay(function() {
14804 // jQuery creates a special event for focusin when it doesn't
14805 // exist natively. To improve performance, the native event
14806 // object is reused and the type is changed. Therefore, we can't
14807 // rely on the type being correct after the event finished
14808 // bubbling, so we set it back to the previous value. (#8740)
14809 if ( event ) {
14810 event.type = eventType;
14811 }
14812 this._open( event, target, response );
14813 });
14814 });
14815 if ( content ) {
14816 this._open( event, target, content );
14817 }
14818 },
14819
14820 _open: function( event, target, content ) {
14821 var tooltip, events, delayedShow,
14822 positionOption = $.extend( {}, this.options.position );
14823
14824 if ( !content ) {
14825 return;
14826 }
14827
14828 // Content can be updated multiple times. If the tooltip already
14829 // exists, then just update the content and bail.
14830 tooltip = this._find( target );
14831 if ( tooltip.length ) {
14832 tooltip.find( ".ui-tooltip-content" ).html( content );
14833 return;
14834 }
14835
14836 // if we have a title, clear it to prevent the native tooltip
14837 // we have to check first to avoid defining a title if none exists
14838 // (we don't want to cause an element to start matching [title])
14839 //
14840 // We use removeAttr only for key events, to allow IE to export the correct
14841 // accessible attributes. For mouse events, set to empty string to avoid
14842 // native tooltip showing up (happens only when removing inside mouseover).
14843 if ( target.is( "[title]" ) ) {
14844 if ( event && event.type === "mouseover" ) {
14845 target.attr( "title", "" );
14846 } else {
14847 target.removeAttr( "title" );
14848 }
14849 }
14850
14851 tooltip = this._tooltip( target );
14852 addDescribedBy( target, tooltip.attr( "id" ) );
14853 tooltip.find( ".ui-tooltip-content" ).html( content );
14854
14855 function position( event ) {
14856 positionOption.of = event;
14857 if ( tooltip.is( ":hidden" ) ) {
14858 return;
14859 }
14860 tooltip.position( positionOption );
14861 }
14862 if ( this.options.track && event && /^mouse/.test( event.type ) ) {
14863 this._on( this.document, {
14864 mousemove: position
14865 });
14866 // trigger once to override element-relative positioning
14867 position( event );
14868 } else {
14869 tooltip.position( $.extend({
14870 of: target
14871 }, this.options.position ) );
14872 }
14873
14874 tooltip.hide();
14875
14876 this._show( tooltip, this.options.show );
14877 // Handle tracking tooltips that are shown with a delay (#8644). As soon
14878 // as the tooltip is visible, position the tooltip using the most recent
14879 // event.
14880 if ( this.options.show && this.options.show.delay ) {
14881 delayedShow = this.delayedShow = setInterval(function() {
14882 if ( tooltip.is( ":visible" ) ) {
14883 position( positionOption.of );
14884 clearInterval( delayedShow );
14885 }
14886 }, $.fx.interval );
14887 }
14888
14889 this._trigger( "open", event, { tooltip: tooltip } );
14890
14891 events = {
14892 keyup: function( event ) {
14893 if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
14894 var fakeEvent = $.Event(event);
14895 fakeEvent.currentTarget = target[0];
14896 this.close( fakeEvent, true );
14897 }
14898 },
14899 remove: function() {
14900 this._removeTooltip( tooltip );
14901 }
14902 };
14903 if ( !event || event.type === "mouseover" ) {
14904 events.mouseleave = "close";
14905 }
14906 if ( !event || event.type === "focusin" ) {
14907 events.focusout = "close";
14908 }
14909 this._on( true, target, events );
14910 },
14911
14912 close: function( event ) {
14913 var that = this,
14914 target = $( event ? event.currentTarget : this.element ),
14915 tooltip = this._find( target );
14916
14917 // disabling closes the tooltip, so we need to track when we're closing
14918 // to avoid an infinite loop in case the tooltip becomes disabled on close
14919 if ( this.closing ) {
14920 return;
14921 }
14922
14923 // Clear the interval for delayed tracking tooltips
14924 clearInterval( this.delayedShow );
14925
14926 // only set title if we had one before (see comment in _open())
14927 if ( target.data( "ui-tooltip-title" ) ) {
14928 target.attr( "title", target.data( "ui-tooltip-title" ) );
14929 }
14930
14931 removeDescribedBy( target );
14932
14933 tooltip.stop( true );
14934 this._hide( tooltip, this.options.hide, function() {
14935 that._removeTooltip( $( this ) );
14936 });
14937
14938 target.removeData( "ui-tooltip-open" );
14939 this._off( target, "mouseleave focusout keyup" );
14940 // Remove 'remove' binding only on delegated targets
14941 if ( target[0] !== this.element[0] ) {
14942 this._off( target, "remove" );
14943 }
14944 this._off( this.document, "mousemove" );
14945
14946 if ( event && event.type === "mouseleave" ) {
14947 $.each( this.parents, function( id, parent ) {
14948 $( parent.element ).attr( "title", parent.title );
14949 delete that.parents[ id ];
14950 });
14951 }
14952
14953 this.closing = true;
14954 this._trigger( "close", event, { tooltip: tooltip } );
14955 this.closing = false;
14956 },
14957
14958 _tooltip: function( element ) {
14959 var id = "ui-tooltip-" + increments++,
14960 tooltip = $( "<div>" )
14961 .attr({
14962 id: id,
14963 role: "tooltip"
14964 })
14965 .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " +
14966 ( this.options.tooltipClass || "" ) );
14967 $( "<div>" )
14968 .addClass( "ui-tooltip-content" )
14969 .appendTo( tooltip );
14970 tooltip.appendTo( this.document[0].body );
14971 this.tooltips[ id ] = element;
14972 return tooltip;
14973 },
14974
14975 _find: function( target ) {
14976 var id = target.data( "ui-tooltip-id" );
14977 return id ? $( "#" + id ) : $();
14978 },
14979
14980 _removeTooltip: function( tooltip ) {
14981 tooltip.remove();
14982 delete this.tooltips[ tooltip.attr( "id" ) ];
14983 },
14984
14985 _destroy: function() {
14986 var that = this;
14987
14988 // close open tooltips
14989 $.each( this.tooltips, function( id, element ) {
14990 // Delegate to close method to handle common cleanup
14991 var event = $.Event( "blur" );
14992 event.target = event.currentTarget = element[0];
14993 that.close( event, true );
14994
14995 // Remove immediately; destroying an open tooltip doesn't use the
14996 // hide animation
14997 $( "#" + id ).remove();
14998
14999 // Restore the title
15000 if ( element.data( "ui-tooltip-title" ) ) {
15001 element.attr( "title", element.data( "ui-tooltip-title" ) );
15002 element.removeData( "ui-tooltip-title" );
15003 }
15004 });
15005 }
15006 });
15007
15008 }( jQuery ) );