6 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
7 * Dual licensed under the MIT or GPL Version 2 licenses.
8 * http://jquery.org/license
10 * http://docs.jquery.com/UI
12 (function( $, undefined ) {
14 // prevent duplicate loading
15 // this is only a problem because we proxy existing functions
16 // and we don't want to double proxy them
22 //Helper functions and ui object
26 // $.ui.plugin is deprecated. Use the proxy pattern instead.
28 add: function( module, option, set ) {
29 var proto = $.ui[ moduleĀ ].prototype;
30 for ( var i in set ) {
31 proto.plugins[ i ] = proto.plugins[ i ] || [];
32 proto.plugins[ i ].push( [ option, set[ i ] ] );
35 call: function( instance, name, args ) {
36 var set = instance.plugins[ name ];
37 if ( !set || !instance.element[ 0 ].parentNode ) {
41 for ( var i = 0; i < set.length; i++ ) {
42 if ( instance.options[ set[ i ][ 0 ] ] ) {
43 set[ i ][ 1 ].apply( instance.element, args );
49 contains: function( a, b ) {
50 return document.compareDocumentPosition ?
51 a.compareDocumentPosition( b ) & 16 :
52 a !== b && a.contains( b );
55 hasScroll: function( el, a ) {
57 //If overflow is hidden, the element might have extra content, but the user wants to hide it
58 if ( $( el ).css( "overflow" ) === "hidden") {
62 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
65 if ( el[ scroll ] > 0 ) {
69 // TODO: determine which cases actually cause this to happen
70 // if the element doesn't have the scroll set, see if it's possible to
73 has = ( el[ scroll ] > 0 );
78 isOverAxis: function( x, reference, size ) {
79 //Determines when x coordinate is over "b" element axis
80 return ( x > reference ) && ( x < ( reference + size ) );
83 isOver: function( y, x, top, left, height, width ) {
84 //Determines when x, y coordinates is over "b" element
85 return $.ui.isOverAxis( y, top, height ) && $.ui.isOverAxis( x, left, width );
94 COMMAND_LEFT: 91, // COMMAND
105 MENU: 93, // COMMAND_RIGHT
110 NUMPAD_MULTIPLY: 106,
111 NUMPAD_SUBTRACT: 109,
120 WINDOWS: 91 // COMMAND
127 focus: function( delay, fn ) {
128 return typeof delay === "number" ?
129 this.each(function() {
131 setTimeout(function() {
138 this._focus.apply( this, arguments );
141 enableSelection: function() {
143 .attr( "unselectable", "off" )
144 .css( "MozUserSelect", "" );
147 disableSelection: function() {
149 .attr( "unselectable", "on" )
150 .css( "MozUserSelect", "none" );
153 scrollParent: function() {
155 if (($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) {
156 scrollParent = this.parents().filter(function() {
157 return (/(relative|absolute|fixed)/).test($.curCSS(this,'position',1)) && (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
160 scrollParent = this.parents().filter(function() {
161 return (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
165 return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent;
168 zIndex: function( zIndex ) {
169 if ( zIndex !== undefined ) {
170 return this.css( "zIndex", zIndex );
174 var elem = $( this[ 0 ] ), position, value;
175 while ( elem.length && elem[ 0 ] !== document ) {
176 // Ignore z-index if position is set to a value where z-index is ignored by the browser
177 // This makes behavior of this function consistent across browsers
178 // WebKit always returns auto if the element is positioned
179 position = elem.css( "position" );
180 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
181 // IE returns 0 when zIndex is not specified
182 // other browsers return a string
183 // we ignore the case of nested elements with an explicit value of 0
184 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
185 value = parseInt( elem.css( "zIndex" ) );
186 if ( !isNaN( value ) && value != 0 ) {
190 elem = elem.parent();
198 $.each( [ "Width", "Height" ], function( i, name ) {
199 var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
200 type = name.toLowerCase(),
202 innerWidth: $.fn.innerWidth,
203 innerHeight: $.fn.innerHeight,
204 outerWidth: $.fn.outerWidth,
205 outerHeight: $.fn.outerHeight
208 function reduce( elem, size, border, margin ) {
209 $.each( side, function() {
210 size -= parseFloat( $.curCSS( elem, "padding" + this, true) ) || 0;
212 size -= parseFloat( $.curCSS( elem, "border" + this + "Width", true) ) || 0;
215 size -= parseFloat( $.curCSS( elem, "margin" + this, true) ) || 0;
221 $.fn[ "inner" + name ] = function( size ) {
222 if ( size === undefined ) {
223 return orig[ "inner" + name ].call( this );
226 return this.each(function() {
227 $.style( this, type, reduce( this, size ) + "px" );
231 $.fn[ "outer" + name] = function( size, margin ) {
232 if ( typeof size !== "number" ) {
233 return orig[ "outer" + name ].call( this, size );
236 return this.each(function() {
237 $.style( this, type, reduce( this, size, true, margin ) + "px" );
242 //Additional selectors
243 function visible( element ) {
244 return !$( element ).parents().andSelf().filter(function() {
245 return $.curCSS( this, "visibility" ) === "hidden" ||
246 $.expr.filters.hidden( this );
250 $.extend( $.expr[ ":" ], {
251 data: function( elem, i, match ) {
252 return !!$.data( elem, match[ 3 ] );
255 focusable: function( element ) {
256 var nodeName = element.nodeName.toLowerCase(),
257 tabIndex = $.attr( element, "tabindex" );
258 if ( "area" === nodeName ) {
259 var map = element.parentNode,
262 if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
265 img = $( "img[usemap=#" + mapName + "]" )[0];
266 return !!img && visible( img );
268 return ( /input|select|textarea|button|object/.test( nodeName )
271 ? element.href || !isNaN( tabIndex )
272 : !isNaN( tabIndex ))
273 // the element and all of its ancestors must be visible
274 && visible( element );
277 tabbable: function( element ) {
278 var tabIndex = $.attr( element, "tabindex" );
279 return ( isNaN( tabIndex ) || tabIndex >= 0 ) && $( element ).is( ":focusable" );
285 * jQuery UI Widget 1.8.4
287 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
288 * Dual licensed under the MIT or GPL Version 2 licenses.
289 * http://jquery.org/license
291 * http://docs.jquery.com/UI/Widget
293 (function( $, undefined ) {
295 var _remove = $.fn.remove;
297 $.fn.remove = function( selector, keepData ) {
298 return this.each(function() {
300 if ( !selector || $.filter( selector, [ this ] ).length ) {
301 $( "*", this ).add( [ this ] ).each(function() {
302 $( this ).triggerHandler( "remove" );
306 return _remove.call( $(this), selector, keepData );
310 $.widget = function( name, base, prototype ) {
311 var namespace = name.split( "." )[ 0 ],
313 name = name.split( "." )[ 1 ];
314 fullName = namespace + "-" + name;
321 // create selector for plugin
322 $.expr[ ":" ][ fullName ] = function( elem ) {
323 return !!$.data( elem, name );
326 $[ namespace ] = $[ namespace ] || {};
327 $[ namespace ][ name ] = function( options, element ) {
328 // allow instantiation without initializing for simple inheritance
329 if ( arguments.length ) {
330 this._createWidget( options, element );
334 var basePrototype = new base();
335 // we need to make the options hash a property directly on the new instance
336 // otherwise we'll modify the options hash on the prototype that we're
338 // $.each( basePrototype, function( key, val ) {
339 // if ( $.isPlainObject(val) ) {
340 // basePrototype[ key ] = $.extend( {}, val );
343 basePrototype.options = $.extend( true, {}, basePrototype.options );
344 $[ namespace ][ name ].prototype = $.extend( true, basePrototype, {
345 namespace: namespace,
347 widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name,
348 widgetBaseClass: fullName
351 $.widget.bridge( name, $[ namespace ][ name ] );
354 $.widget.bridge = function( name, object ) {
355 $.fn[ name ] = function( options ) {
356 var isMethodCall = typeof options === "string",
357 args = Array.prototype.slice.call( arguments, 1 ),
360 // allow multiple hashes to be passed on init
361 options = !isMethodCall && args.length ?
362 $.extend.apply( null, [ true, options ].concat(args) ) :
365 // prevent calls to internal methods
366 if ( isMethodCall && options.substring( 0, 1 ) === "_" ) {
370 if ( isMethodCall ) {
371 this.each(function() {
372 var instance = $.data( this, name ),
373 methodValue = instance && $.isFunction( instance[options] ) ?
374 instance[ options ].apply( instance, args ) :
376 if ( methodValue !== instance && methodValue !== undefined ) {
377 returnValue = methodValue;
382 this.each(function() {
383 var instance = $.data( this, name );
386 instance.option( options );
390 $.data( this, name, new object( options, this ) );
399 $.Widget = function( options, element ) {
400 // allow instantiation without initializing for simple inheritance
401 if ( arguments.length ) {
402 this._createWidget( options, element );
406 $.Widget.prototype = {
407 widgetName: "widget",
408 widgetEventPrefix: "",
412 _createWidget: function( options, element ) {
413 // $.widget.bridge stores the plugin instance, but we do it anyway
414 // so that it's stored even before the _create function runs
415 $.data( element, this.widgetName, this );
416 this.element = $( element );
417 this.options = $.extend( true, {},
419 $.metadata && $.metadata.get( element )[ this.widgetName ],
423 this.element.bind( "remove." + this.widgetName, function() {
430 _create: function() {},
431 _init: function() {},
433 destroy: function() {
435 .unbind( "." + this.widgetName )
436 .removeData( this.widgetName );
438 .unbind( "." + this.widgetName )
439 .removeAttr( "aria-disabled" )
441 this.widgetBaseClass + "-disabled " +
442 "ui-state-disabled" );
449 option: function( key, value ) {
453 if ( arguments.length === 0 ) {
454 // don't return a reference to the internal hash
455 return $.extend( {}, self.options );
458 if (typeof key === "string" ) {
459 if ( value === undefined ) {
460 return this.options[ key ];
463 options[ key ] = value;
466 $.each( options, function( key, value ) {
467 self._setOption( key, value );
472 _setOption: function( key, value ) {
473 this.options[ key ] = value;
475 if ( key === "disabled" ) {
477 [ value ? "addClass" : "removeClass"](
478 this.widgetBaseClass + "-disabled" + " " +
479 "ui-state-disabled" )
480 .attr( "aria-disabled", value );
487 return this._setOption( "disabled", false );
489 disable: function() {
490 return this._setOption( "disabled", true );
493 _trigger: function( type, event, data ) {
494 var callback = this.options[ type ];
496 event = $.Event( event );
497 event.type = ( type === this.widgetEventPrefix ?
499 this.widgetEventPrefix + type ).toLowerCase();
502 // copy original event properties over to the new event
503 // this would happen if we could call $.event.fix instead of $.Event
504 // but we don't have a way to force an event to be fixed multiple times
505 if ( event.originalEvent ) {
506 for ( var i = $.event.props.length, prop; i; ) {
507 prop = $.event.props[ --i ];
508 event[ prop ] = event.originalEvent[ prop ];
512 this.element.trigger( event, data );
514 return !( $.isFunction(callback) &&
515 callback.call( this.element[0], event, data ) === false ||
516 event.isDefaultPrevented() );
522 * jQuery UI Mouse 1.8.4
524 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
525 * Dual licensed under the MIT or GPL Version 2 licenses.
526 * http://jquery.org/license
528 * http://docs.jquery.com/UI/Mouse
531 * jquery.ui.widget.js
533 (function( $, undefined ) {
535 $.widget("ui.mouse", {
537 cancel: ':input,option',
541 _mouseInit: function() {
545 .bind('mousedown.'+this.widgetName, function(event) {
546 return self._mouseDown(event);
548 .bind('click.'+this.widgetName, function(event) {
549 if(self._preventClickEvent) {
550 self._preventClickEvent = false;
551 event.stopImmediatePropagation();
556 this.started = false;
559 // TODO: make sure destroying one instance of mouse doesn't mess with
560 // other instances of mouse
561 _mouseDestroy: function() {
562 this.element.unbind('.'+this.widgetName);
565 _mouseDown: function(event) {
566 // don't let more than one widget handle mouseStart
567 // TODO: figure out why we have to use originalEvent
568 event.originalEvent = event.originalEvent || {};
569 if (event.originalEvent.mouseHandled) { return; }
571 // we may have missed mouseup (out of window)
572 (this._mouseStarted && this._mouseUp(event));
574 this._mouseDownEvent = event;
577 btnIsLeft = (event.which == 1),
578 elIsCancel = (typeof this.options.cancel == "string" ? $(event.target).parents().add(event.target).filter(this.options.cancel).length : false);
579 if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
583 this.mouseDelayMet = !this.options.delay;
584 if (!this.mouseDelayMet) {
585 this._mouseDelayTimer = setTimeout(function() {
586 self.mouseDelayMet = true;
587 }, this.options.delay);
590 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
591 this._mouseStarted = (this._mouseStart(event) !== false);
592 if (!this._mouseStarted) {
593 event.preventDefault();
598 // these delegates are required to keep context
599 this._mouseMoveDelegate = function(event) {
600 return self._mouseMove(event);
602 this._mouseUpDelegate = function(event) {
603 return self._mouseUp(event);
606 .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
607 .bind('mouseup.'+this.widgetName, this._mouseUpDelegate);
609 // preventDefault() is used to prevent the selection of text here -
610 // however, in Safari, this causes select boxes not to be selectable
611 // anymore, so this fix is needed
612 ($.browser.safari || event.preventDefault());
614 event.originalEvent.mouseHandled = true;
618 _mouseMove: function(event) {
619 // IE mouseup check - mouseup happened when mouse was out of window
620 if ($.browser.msie && !event.button) {
621 return this._mouseUp(event);
624 if (this._mouseStarted) {
625 this._mouseDrag(event);
626 return event.preventDefault();
629 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
631 (this._mouseStart(this._mouseDownEvent, event) !== false);
632 (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
635 return !this._mouseStarted;
638 _mouseUp: function(event) {
640 .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
641 .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
643 if (this._mouseStarted) {
644 this._mouseStarted = false;
645 this._preventClickEvent = (event.target == this._mouseDownEvent.target);
646 this._mouseStop(event);
652 _mouseDistanceMet: function(event) {
654 Math.abs(this._mouseDownEvent.pageX - event.pageX),
655 Math.abs(this._mouseDownEvent.pageY - event.pageY)
656 ) >= this.options.distance
660 _mouseDelayMet: function(event) {
661 return this.mouseDelayMet;
664 // These are placeholder methods, to be overriden by extending plugin
665 _mouseStart: function(event) {},
666 _mouseDrag: function(event) {},
667 _mouseStop: function(event) {},
668 _mouseCapture: function(event) { return true; }
673 * jQuery UI Position 1.8.4
675 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
676 * Dual licensed under the MIT or GPL Version 2 licenses.
677 * http://jquery.org/license
679 * http://docs.jquery.com/UI/Position
681 (function( $, undefined ) {
685 var horizontalPositions = /left|center|right/,
686 horizontalDefault = "center",
687 verticalPositions = /top|center|bottom/,
688 verticalDefault = "center",
689 _position = $.fn.position,
690 _offset = $.fn.offset;
692 $.fn.position = function( options ) {
693 if ( !options || !options.of ) {
694 return _position.apply( this, arguments );
697 // make a copy, we don't want to modify arguments
698 options = $.extend( {}, options );
700 var target = $( options.of ),
701 collision = ( options.collision || "flip" ).split( " " ),
702 offset = options.offset ? options.offset.split( " " ) : [ 0, 0 ],
707 if ( options.of.nodeType === 9 ) {
708 targetWidth = target.width();
709 targetHeight = target.height();
710 basePosition = { top: 0, left: 0 };
711 } else if ( options.of.scrollTo && options.of.document ) {
712 targetWidth = target.width();
713 targetHeight = target.height();
714 basePosition = { top: target.scrollTop(), left: target.scrollLeft() };
715 } else if ( options.of.preventDefault ) {
716 // force left top to allow flipping
717 options.at = "left top";
718 targetWidth = targetHeight = 0;
719 basePosition = { top: options.of.pageY, left: options.of.pageX };
721 targetWidth = target.outerWidth();
722 targetHeight = target.outerHeight();
723 basePosition = target.offset();
726 // force my and at to have valid horizontal and veritcal positions
727 // if a value is missing or invalid, it will be converted to center
728 $.each( [ "my", "at" ], function() {
729 var pos = ( options[this] || "" ).split( " " );
730 if ( pos.length === 1) {
731 pos = horizontalPositions.test( pos[0] ) ?
732 pos.concat( [verticalDefault] ) :
733 verticalPositions.test( pos[0] ) ?
734 [ horizontalDefault ].concat( pos ) :
735 [ horizontalDefault, verticalDefault ];
737 pos[ 0 ] = horizontalPositions.test( pos[0] ) ? pos[ 0 ] : horizontalDefault;
738 pos[ 1 ] = verticalPositions.test( pos[1] ) ? pos[ 1 ] : verticalDefault;
739 options[ this ] = pos;
742 // normalize collision option
743 if ( collision.length === 1 ) {
744 collision[ 1 ] = collision[ 0 ];
747 // normalize offset option
748 offset[ 0 ] = parseInt( offset[0], 10 ) || 0;
749 if ( offset.length === 1 ) {
750 offset[ 1 ] = offset[ 0 ];
752 offset[ 1 ] = parseInt( offset[1], 10 ) || 0;
754 if ( options.at[0] === "right" ) {
755 basePosition.left += targetWidth;
756 } else if (options.at[0] === horizontalDefault ) {
757 basePosition.left += targetWidth / 2;
760 if ( options.at[1] === "bottom" ) {
761 basePosition.top += targetHeight;
762 } else if ( options.at[1] === verticalDefault ) {
763 basePosition.top += targetHeight / 2;
766 basePosition.left += offset[ 0 ];
767 basePosition.top += offset[ 1 ];
769 return this.each(function() {
770 var elem = $( this ),
771 elemWidth = elem.outerWidth(),
772 elemHeight = elem.outerHeight(),
773 position = $.extend( {}, basePosition );
775 if ( options.my[0] === "right" ) {
776 position.left -= elemWidth;
777 } else if ( options.my[0] === horizontalDefault ) {
778 position.left -= elemWidth / 2;
781 if ( options.my[1] === "bottom" ) {
782 position.top -= elemHeight;
783 } else if ( options.my[1] === verticalDefault ) {
784 position.top -= elemHeight / 2;
787 // prevent fractions (see #5280)
788 position.left = parseInt( position.left );
789 position.top = parseInt( position.top );
791 $.each( [ "left", "top" ], function( i, dir ) {
792 if ( $.ui.position[ collision[i] ] ) {
793 $.ui.position[ collision[i] ][ dir ]( position, {
794 targetWidth: targetWidth,
795 targetHeight: targetHeight,
796 elemWidth: elemWidth,
797 elemHeight: elemHeight,
805 if ( $.fn.bgiframe ) {
808 elem.offset( $.extend( position, { using: options.using } ) );
814 left: function( position, data ) {
815 var win = $( window ),
816 over = position.left + data.elemWidth - win.width() - win.scrollLeft();
817 position.left = over > 0 ? position.left - over : Math.max( 0, position.left );
819 top: function( position, data ) {
820 var win = $( window ),
821 over = position.top + data.elemHeight - win.height() - win.scrollTop();
822 position.top = over > 0 ? position.top - over : Math.max( 0, position.top );
827 left: function( position, data ) {
828 if ( data.at[0] === "center" ) {
831 var win = $( window ),
832 over = position.left + data.elemWidth - win.width() - win.scrollLeft(),
833 myOffset = data.my[ 0 ] === "left" ?
835 data.my[ 0 ] === "right" ?
838 offset = -2 * data.offset[ 0 ];
839 position.left += position.left < 0 ?
840 myOffset + data.targetWidth + offset :
842 myOffset - data.targetWidth + offset :
845 top: function( position, data ) {
846 if ( data.at[1] === "center" ) {
849 var win = $( window ),
850 over = position.top + data.elemHeight - win.height() - win.scrollTop(),
851 myOffset = data.my[ 1 ] === "top" ?
853 data.my[ 1 ] === "bottom" ?
856 atOffset = data.at[ 1 ] === "top" ?
859 offset = -2 * data.offset[ 1 ];
860 position.top += position.top < 0 ?
861 myOffset + data.targetHeight + offset :
863 myOffset + atOffset + offset :
869 // offset setter from jQuery 1.4
870 if ( !$.offset.setOffset ) {
871 $.offset.setOffset = function( elem, options ) {
872 // set position first, in-case top/left are set even on static elem
873 if ( /static/.test( $.curCSS( elem, "position" ) ) ) {
874 elem.style.position = "relative";
876 var curElem = $( elem ),
877 curOffset = curElem.offset(),
878 curTop = parseInt( $.curCSS( elem, "top", true ), 10 ) || 0,
879 curLeft = parseInt( $.curCSS( elem, "left", true ), 10) || 0,
881 top: (options.top - curOffset.top) + curTop,
882 left: (options.left - curOffset.left) + curLeft
885 if ( 'using' in options ) {
886 options.using.call( elem, props );
888 curElem.css( props );
892 $.fn.offset = function( options ) {
893 var elem = this[ 0 ];
894 if ( !elem || !elem.ownerDocument ) { return null; }
896 return this.each(function() {
897 $.offset.setOffset( this, options );
900 return _offset.call( this );
906 * jQuery UI Draggable 1.8.4
908 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
909 * Dual licensed under the MIT or GPL Version 2 licenses.
910 * http://jquery.org/license
912 * http://docs.jquery.com/UI/Draggables
917 * jquery.ui.widget.js
919 (function( $, undefined ) {
921 $.widget("ui.draggable", $.ui.mouse, {
922 widgetEventPrefix: "drag",
927 connectToSortable: false,
936 refreshPositions: false,
941 scrollSensitivity: 20,
949 _create: function() {
951 if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position")))
952 this.element[0].style.position = 'relative';
954 (this.options.addClasses && this.element.addClass("ui-draggable"));
955 (this.options.disabled && this.element.addClass("ui-draggable-disabled"));
961 destroy: function() {
962 if(!this.element.data('draggable')) return;
964 .removeData("draggable")
965 .unbind(".draggable")
966 .removeClass("ui-draggable"
967 + " ui-draggable-dragging"
968 + " ui-draggable-disabled");
969 this._mouseDestroy();
974 _mouseCapture: function(event) {
976 var o = this.options;
978 // among others, prevent a drag on a resizable-handle
979 if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle'))
982 //Quit if we're not on a valid handle
983 this.handle = this._getHandle(event);
991 _mouseStart: function(event) {
993 var o = this.options;
995 //Create and append the visible helper
996 this.helper = this._createHelper(event);
998 //Cache the helper size
999 this._cacheHelperProportions();
1001 //If ddmanager is used for droppables, set the global draggable
1003 $.ui.ddmanager.current = this;
1006 * - Position generation -
1007 * This block generates everything position related - it's the core of draggables.
1010 //Cache the margins of the original element
1011 this._cacheMargins();
1013 //Store the helper's css position
1014 this.cssPosition = this.helper.css("position");
1015 this.scrollParent = this.helper.scrollParent();
1017 //The element's absolute position on the page minus margins
1018 this.offset = this.positionAbs = this.element.offset();
1020 top: this.offset.top - this.margins.top,
1021 left: this.offset.left - this.margins.left
1024 $.extend(this.offset, {
1025 click: { //Where the click happened, relative to the element
1026 left: event.pageX - this.offset.left,
1027 top: event.pageY - this.offset.top
1029 parent: this._getParentOffset(),
1030 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
1033 //Generate the original position
1034 this.originalPosition = this.position = this._generatePosition(event);
1035 this.originalPageX = event.pageX;
1036 this.originalPageY = event.pageY;
1038 //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
1039 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
1041 //Set a containment if given in the options
1043 this._setContainment();
1045 //Trigger event + callbacks
1046 if(this._trigger("start", event) === false) {
1051 //Recache the helper size
1052 this._cacheHelperProportions();
1054 //Prepare the droppable offsets
1055 if ($.ui.ddmanager && !o.dropBehaviour)
1056 $.ui.ddmanager.prepareOffsets(this, event);
1058 this.helper.addClass("ui-draggable-dragging");
1059 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
1063 _mouseDrag: function(event, noPropagation) {
1065 //Compute the helpers position
1066 this.position = this._generatePosition(event);
1067 this.positionAbs = this._convertPositionTo("absolute");
1069 //Call plugins and callbacks and use the resulting position if something is returned
1070 if (!noPropagation) {
1071 var ui = this._uiHash();
1072 if(this._trigger('drag', event, ui) === false) {
1076 this.position = ui.position;
1079 if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
1080 if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
1081 if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
1086 _mouseStop: function(event) {
1088 //If we are using droppables, inform the manager about the drop
1089 var dropped = false;
1090 if ($.ui.ddmanager && !this.options.dropBehaviour)
1091 dropped = $.ui.ddmanager.drop(this, event);
1093 //if a drop comes from outside (a sortable)
1095 dropped = this.dropped;
1096 this.dropped = false;
1099 //if the original element is removed, don't bother to continue
1100 if(!this.element[0] || !this.element[0].parentNode)
1103 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))) {
1105 $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
1106 if(self._trigger("stop", event) !== false) {
1111 if(this._trigger("stop", event) !== false) {
1119 cancel: function() {
1121 if(this.helper.is(".ui-draggable-dragging")) {
1131 _getHandle: function(event) {
1133 var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false;
1134 $(this.options.handle, this.element)
1138 if(this == event.target) handle = true;
1145 _createHelper: function(event) {
1147 var o = this.options;
1148 var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone() : this.element);
1150 if(!helper.parents('body').length)
1151 helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo));
1153 if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position")))
1154 helper.css("position", "absolute");
1160 _adjustOffsetFromHelper: function(obj) {
1161 if (typeof obj == 'string') {
1162 obj = obj.split(' ');
1164 if ($.isArray(obj)) {
1165 obj = {left: +obj[0], top: +obj[1] || 0};
1167 if ('left' in obj) {
1168 this.offset.click.left = obj.left + this.margins.left;
1170 if ('right' in obj) {
1171 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
1174 this.offset.click.top = obj.top + this.margins.top;
1176 if ('bottom' in obj) {
1177 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
1181 _getParentOffset: function() {
1183 //Get the offsetParent and cache its position
1184 this.offsetParent = this.helper.offsetParent();
1185 var po = this.offsetParent.offset();
1187 // This is a special case where we need to modify a offset calculated on start, since the following happened:
1188 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
1189 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
1190 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
1191 if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) {
1192 po.left += this.scrollParent.scrollLeft();
1193 po.top += this.scrollParent.scrollTop();
1196 if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information
1197 || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix
1198 po = { top: 0, left: 0 };
1201 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
1202 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
1207 _getRelativeOffset: function() {
1209 if(this.cssPosition == "relative") {
1210 var p = this.element.position();
1212 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
1213 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
1216 return { top: 0, left: 0 };
1221 _cacheMargins: function() {
1223 left: (parseInt(this.element.css("marginLeft"),10) || 0),
1224 top: (parseInt(this.element.css("marginTop"),10) || 0)
1228 _cacheHelperProportions: function() {
1229 this.helperProportions = {
1230 width: this.helper.outerWidth(),
1231 height: this.helper.outerHeight()
1235 _setContainment: function() {
1237 var o = this.options;
1238 if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
1239 if(o.containment == 'document' || o.containment == 'window') this.containment = [
1240 0 - this.offset.relative.left - this.offset.parent.left,
1241 0 - this.offset.relative.top - this.offset.parent.top,
1242 $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left,
1243 ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
1246 if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) {
1247 var ce = $(o.containment)[0]; if(!ce) return;
1248 var co = $(o.containment).offset();
1249 var over = ($(ce).css("overflow") != 'hidden');
1251 this.containment = [
1252 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
1253 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
1254 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,
1255 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
1257 } else if(o.containment.constructor == Array) {
1258 this.containment = o.containment;
1263 _convertPositionTo: function(d, pos) {
1265 if(!pos) pos = this.position;
1266 var mod = d == "absolute" ? 1 : -1;
1267 var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
1271 pos.top // The absolute mouse position
1272 + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent
1273 + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border)
1274 - ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
1277 pos.left // The absolute mouse position
1278 + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent
1279 + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border)
1280 - ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
1286 _generatePosition: function(event) {
1288 var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
1289 var pageX = event.pageX;
1290 var pageY = event.pageY;
1293 * - Position constraining -
1294 * Constrain the position to a mix of grid, containment.
1297 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
1299 if(this.containment) {
1300 if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left;
1301 if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top;
1302 if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left;
1303 if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top;
1307 var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
1308 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;
1310 var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
1311 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;
1318 pageY // The absolute mouse position
1319 - this.offset.click.top // Click offset (relative to the element)
1320 - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent
1321 - this.offset.parent.top // The offsetParent's offset without borders (offset + border)
1322 + ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
1325 pageX // The absolute mouse position
1326 - this.offset.click.left // Click offset (relative to the element)
1327 - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent
1328 - this.offset.parent.left // The offsetParent's offset without borders (offset + border)
1329 + ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
1335 _clear: function() {
1336 this.helper.removeClass("ui-draggable-dragging");
1337 if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove();
1338 //if($.ui.ddmanager) $.ui.ddmanager.current = null;
1340 this.cancelHelperRemoval = false;
1343 // From now on bulk stuff - mainly helpers
1345 _trigger: function(type, event, ui) {
1346 ui = ui || this._uiHash();
1347 $.ui.plugin.call(this, type, [event, ui]);
1348 if(type == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins
1349 return $.Widget.prototype._trigger.call(this, type, event, ui);
1354 _uiHash: function(event) {
1356 helper: this.helper,
1357 position: this.position,
1358 originalPosition: this.originalPosition,
1359 offset: this.positionAbs
1365 $.extend($.ui.draggable, {
1369 $.ui.plugin.add("draggable", "connectToSortable", {
1370 start: function(event, ui) {
1372 var inst = $(this).data("draggable"), o = inst.options,
1373 uiSortable = $.extend({}, ui, { item: inst.element });
1374 inst.sortables = [];
1375 $(o.connectToSortable).each(function() {
1376 var sortable = $.data(this, 'sortable');
1377 if (sortable && !sortable.options.disabled) {
1378 inst.sortables.push({
1380 shouldRevert: sortable.options.revert
1382 sortable._refreshItems(); //Do a one-time refresh at start to refresh the containerCache
1383 sortable._trigger("activate", event, uiSortable);
1388 stop: function(event, ui) {
1390 //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
1391 var inst = $(this).data("draggable"),
1392 uiSortable = $.extend({}, ui, { item: inst.element });
1394 $.each(inst.sortables, function() {
1395 if(this.instance.isOver) {
1397 this.instance.isOver = 0;
1399 inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
1400 this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
1402 //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid'
1403 if(this.shouldRevert) this.instance.options.revert = true;
1405 //Trigger the stop of the sortable
1406 this.instance._mouseStop(event);
1408 this.instance.options.helper = this.instance.options._helper;
1410 //If the helper has been the original item, restore properties in the sortable
1411 if(inst.options.helper == 'original')
1412 this.instance.currentItem.css({ top: 'auto', left: 'auto' });
1415 this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
1416 this.instance._trigger("deactivate", event, uiSortable);
1422 drag: function(event, ui) {
1424 var inst = $(this).data("draggable"), self = this;
1426 var checkPos = function(o) {
1427 var dyClick = this.offset.click.top, dxClick = this.offset.click.left;
1428 var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left;
1429 var itemHeight = o.height, itemWidth = o.width;
1430 var itemTop = o.top, itemLeft = o.left;
1432 return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth);
1435 $.each(inst.sortables, function(i) {
1437 //Copy over some variables to allow calling the sortable's native _intersectsWith
1438 this.instance.positionAbs = inst.positionAbs;
1439 this.instance.helperProportions = inst.helperProportions;
1440 this.instance.offset.click = inst.offset.click;
1442 if(this.instance._intersectsWith(this.instance.containerCache)) {
1444 //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
1445 if(!this.instance.isOver) {
1447 this.instance.isOver = 1;
1448 //Now we fake the start of dragging for the sortable instance,
1449 //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
1450 //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)
1451 this.instance.currentItem = $(self).clone().appendTo(this.instance.element).data("sortable-item", true);
1452 this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
1453 this.instance.options.helper = function() { return ui.helper[0]; };
1455 event.target = this.instance.currentItem[0];
1456 this.instance._mouseCapture(event, true);
1457 this.instance._mouseStart(event, true, true);
1459 //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
1460 this.instance.offset.click.top = inst.offset.click.top;
1461 this.instance.offset.click.left = inst.offset.click.left;
1462 this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
1463 this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
1465 inst._trigger("toSortable", event);
1466 inst.dropped = this.instance.element; //draggable revert needs that
1467 //hack so receive/update callbacks work (mostly)
1468 inst.currentItem = inst.element;
1469 this.instance.fromOutside = inst;
1473 //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
1474 if(this.instance.currentItem) this.instance._mouseDrag(event);
1478 //If it doesn't intersect with the sortable, and it intersected before,
1479 //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
1480 if(this.instance.isOver) {
1482 this.instance.isOver = 0;
1483 this.instance.cancelHelperRemoval = true;
1485 //Prevent reverting on this forced stop
1486 this.instance.options.revert = false;
1488 // The out event needs to be triggered independently
1489 this.instance._trigger('out', event, this.instance._uiHash(this.instance));
1491 this.instance._mouseStop(event, true);
1492 this.instance.options.helper = this.instance.options._helper;
1494 //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
1495 this.instance.currentItem.remove();
1496 if(this.instance.placeholder) this.instance.placeholder.remove();
1498 inst._trigger("fromSortable", event);
1499 inst.dropped = false; //draggable revert needs that
1509 $.ui.plugin.add("draggable", "cursor", {
1510 start: function(event, ui) {
1511 var t = $('body'), o = $(this).data('draggable').options;
1512 if (t.css("cursor")) o._cursor = t.css("cursor");
1513 t.css("cursor", o.cursor);
1515 stop: function(event, ui) {
1516 var o = $(this).data('draggable').options;
1517 if (o._cursor) $('body').css("cursor", o._cursor);
1521 $.ui.plugin.add("draggable", "iframeFix", {
1522 start: function(event, ui) {
1523 var o = $(this).data('draggable').options;
1524 $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
1525 $('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>')
1527 width: this.offsetWidth+"px", height: this.offsetHeight+"px",
1528 position: "absolute", opacity: "0.001", zIndex: 1000
1530 .css($(this).offset())
1534 stop: function(event, ui) {
1535 $("div.ui-draggable-iframeFix").each(function() { this.parentNode.removeChild(this); }); //Remove frame helpers
1539 $.ui.plugin.add("draggable", "opacity", {
1540 start: function(event, ui) {
1541 var t = $(ui.helper), o = $(this).data('draggable').options;
1542 if(t.css("opacity")) o._opacity = t.css("opacity");
1543 t.css('opacity', o.opacity);
1545 stop: function(event, ui) {
1546 var o = $(this).data('draggable').options;
1547 if(o._opacity) $(ui.helper).css('opacity', o._opacity);
1551 $.ui.plugin.add("draggable", "scroll", {
1552 start: function(event, ui) {
1553 var i = $(this).data("draggable");
1554 if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset();
1556 drag: function(event, ui) {
1558 var i = $(this).data("draggable"), o = i.options, scrolled = false;
1560 if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') {
1562 if(!o.axis || o.axis != 'x') {
1563 if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
1564 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
1565 else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity)
1566 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
1569 if(!o.axis || o.axis != 'y') {
1570 if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
1571 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
1572 else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity)
1573 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
1578 if(!o.axis || o.axis != 'x') {
1579 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
1580 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
1581 else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
1582 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
1585 if(!o.axis || o.axis != 'y') {
1586 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
1587 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
1588 else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
1589 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
1594 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
1595 $.ui.ddmanager.prepareOffsets(i, event);
1600 $.ui.plugin.add("draggable", "snap", {
1601 start: function(event, ui) {
1603 var i = $(this).data("draggable"), o = i.options;
1604 i.snapElements = [];
1606 $(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) : o.snap).each(function() {
1607 var $t = $(this); var $o = $t.offset();
1608 if(this != i.element[0]) i.snapElements.push({
1610 width: $t.outerWidth(), height: $t.outerHeight(),
1611 top: $o.top, left: $o.left
1616 drag: function(event, ui) {
1618 var inst = $(this).data("draggable"), o = inst.options;
1619 var d = o.snapTolerance;
1621 var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
1622 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
1624 for (var i = inst.snapElements.length - 1; i >= 0; i--){
1626 var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width,
1627 t = inst.snapElements[i].top, b = t + inst.snapElements[i].height;
1629 //Yes, I know, this is insane ;)
1630 if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) {
1631 if(inst.snapElements[i].snapping) (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
1632 inst.snapElements[i].snapping = false;
1636 if(o.snapMode != 'inner') {
1637 var ts = Math.abs(t - y2) <= d;
1638 var bs = Math.abs(b - y1) <= d;
1639 var ls = Math.abs(l - x2) <= d;
1640 var rs = Math.abs(r - x1) <= d;
1641 if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
1642 if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
1643 if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
1644 if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
1647 var first = (ts || bs || ls || rs);
1649 if(o.snapMode != 'outer') {
1650 var ts = Math.abs(t - y1) <= d;
1651 var bs = Math.abs(b - y2) <= d;
1652 var ls = Math.abs(l - x1) <= d;
1653 var rs = Math.abs(r - x2) <= d;
1654 if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
1655 if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
1656 if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
1657 if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
1660 if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first))
1661 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
1662 inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
1669 $.ui.plugin.add("draggable", "stack", {
1670 start: function(event, ui) {
1672 var o = $(this).data("draggable").options;
1674 var group = $.makeArray($(o.stack)).sort(function(a,b) {
1675 return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0);
1677 if (!group.length) { return; }
1679 var min = parseInt(group[0].style.zIndex) || 0;
1680 $(group).each(function(i) {
1681 this.style.zIndex = min + i;
1684 this[0].style.zIndex = min + group.length;
1689 $.ui.plugin.add("draggable", "zIndex", {
1690 start: function(event, ui) {
1691 var t = $(ui.helper), o = $(this).data("draggable").options;
1692 if(t.css("zIndex")) o._zIndex = t.css("zIndex");
1693 t.css('zIndex', o.zIndex);
1695 stop: function(event, ui) {
1696 var o = $(this).data("draggable").options;
1697 if(o._zIndex) $(ui.helper).css('zIndex', o._zIndex);
1703 * jQuery UI Droppable 1.8.4
1705 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
1706 * Dual licensed under the MIT or GPL Version 2 licenses.
1707 * http://jquery.org/license
1709 * http://docs.jquery.com/UI/Droppables
1713 * jquery.ui.widget.js
1714 * jquery.ui.mouse.js
1715 * jquery.ui.draggable.js
1717 (function( $, undefined ) {
1719 $.widget("ui.droppable", {
1720 widgetEventPrefix: "drop",
1728 tolerance: 'intersect'
1730 _create: function() {
1732 var o = this.options, accept = o.accept;
1733 this.isover = 0; this.isout = 1;
1735 this.accept = $.isFunction(accept) ? accept : function(d) {
1736 return d.is(accept);
1739 //Store the droppable's proportions
1740 this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight };
1742 // Add the reference and positions to the manager
1743 $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || [];
1744 $.ui.ddmanager.droppables[o.scope].push(this);
1746 (o.addClasses && this.element.addClass("ui-droppable"));
1750 destroy: function() {
1751 var drop = $.ui.ddmanager.droppables[this.options.scope];
1752 for ( var i = 0; i < drop.length; i++ )
1753 if ( drop[i] == this )
1757 .removeClass("ui-droppable ui-droppable-disabled")
1758 .removeData("droppable")
1759 .unbind(".droppable");
1764 _setOption: function(key, value) {
1766 if(key == 'accept') {
1767 this.accept = $.isFunction(value) ? value : function(d) {
1771 $.Widget.prototype._setOption.apply(this, arguments);
1774 _activate: function(event) {
1775 var draggable = $.ui.ddmanager.current;
1776 if(this.options.activeClass) this.element.addClass(this.options.activeClass);
1777 (draggable && this._trigger('activate', event, this.ui(draggable)));
1780 _deactivate: function(event) {
1781 var draggable = $.ui.ddmanager.current;
1782 if(this.options.activeClass) this.element.removeClass(this.options.activeClass);
1783 (draggable && this._trigger('deactivate', event, this.ui(draggable)));
1786 _over: function(event) {
1788 var draggable = $.ui.ddmanager.current;
1789 if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element
1791 if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
1792 if(this.options.hoverClass) this.element.addClass(this.options.hoverClass);
1793 this._trigger('over', event, this.ui(draggable));
1798 _out: function(event) {
1800 var draggable = $.ui.ddmanager.current;
1801 if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element
1803 if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
1804 if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass);
1805 this._trigger('out', event, this.ui(draggable));
1810 _drop: function(event,custom) {
1812 var draggable = custom || $.ui.ddmanager.current;
1813 if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element
1815 var childrenIntersection = false;
1816 this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function() {
1817 var inst = $.data(this, 'droppable');
1820 && !inst.options.disabled
1821 && inst.options.scope == draggable.options.scope
1822 && inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element))
1823 && $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)
1824 ) { childrenIntersection = true; return false; }
1826 if(childrenIntersection) return false;
1828 if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
1829 if(this.options.activeClass) this.element.removeClass(this.options.activeClass);
1830 if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass);
1831 this._trigger('drop', event, this.ui(draggable));
1832 return this.element;
1841 draggable: (c.currentItem || c.element),
1843 position: c.position,
1844 offset: c.positionAbs
1850 $.extend($.ui.droppable, {
1854 $.ui.intersect = function(draggable, droppable, toleranceMode) {
1856 if (!droppable.offset) return false;
1858 var x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width,
1859 y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height;
1860 var l = droppable.offset.left, r = l + droppable.proportions.width,
1861 t = droppable.offset.top, b = t + droppable.proportions.height;
1863 switch (toleranceMode) {
1865 return (l <= x1 && x2 <= r
1866 && t <= y1 && y2 <= b);
1869 return (l < x1 + (draggable.helperProportions.width / 2) // Right Half
1870 && x2 - (draggable.helperProportions.width / 2) < r // Left Half
1871 && t < y1 + (draggable.helperProportions.height / 2) // Bottom Half
1872 && y2 - (draggable.helperProportions.height / 2) < b ); // Top Half
1875 var draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left),
1876 draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top),
1877 isOver = $.ui.isOver(draggableTop, draggableLeft, t, l, droppable.proportions.height, droppable.proportions.width);
1882 (y1 >= t && y1 <= b) || // Top edge touching
1883 (y2 >= t && y2 <= b) || // Bottom edge touching
1884 (y1 < t && y2 > b) // Surrounded vertically
1886 (x1 >= l && x1 <= r) || // Left edge touching
1887 (x2 >= l && x2 <= r) || // Right edge touching
1888 (x1 < l && x2 > r) // Surrounded horizontally
1899 This manager tracks offsets of draggables and droppables
1903 droppables: { 'default': [] },
1904 prepareOffsets: function(t, event) {
1906 var m = $.ui.ddmanager.droppables[t.options.scope] || [];
1907 var type = event ? event.type : null; // workaround for #2317
1908 var list = (t.currentItem || t.element).find(":data(droppable)").andSelf();
1910 droppablesLoop: for (var i = 0; i < m.length; i++) {
1912 if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) continue; //No disabled and non-accepted
1913 for (var j=0; j < list.length; j++) { if(list[j] == m[i].element[0]) { m[i].proportions.height = 0; continue droppablesLoop; } }; //Filter out elements in the current dragged item
1914 m[i].visible = m[i].element.css("display") != "none"; if(!m[i].visible) continue; //If the element is not visible, continue
1916 m[i].offset = m[i].element.offset();
1917 m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight };
1919 if(type == "mousedown") m[i]._activate.call(m[i], event); //Activate the droppable if used directly from draggables
1924 drop: function(draggable, event) {
1926 var dropped = false;
1927 $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
1929 if(!this.options) return;
1930 if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance))
1931 dropped = dropped || this._drop.call(this, event);
1933 if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
1934 this.isout = 1; this.isover = 0;
1935 this._deactivate.call(this, event);
1942 drag: function(draggable, event) {
1944 //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
1945 if(draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event);
1947 //Run through all droppables and check their positions based on specific tolerance options
1948 $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
1950 if(this.options.disabled || this.greedyChild || !this.visible) return;
1951 var intersects = $.ui.intersect(draggable, this, this.options.tolerance);
1953 var c = !intersects && this.isover == 1 ? 'isout' : (intersects && this.isover == 0 ? 'isover' : null);
1957 if (this.options.greedy) {
1958 var parent = this.element.parents(':data(droppable):eq(0)');
1959 if (parent.length) {
1960 parentInstance = $.data(parent[0], 'droppable');
1961 parentInstance.greedyChild = (c == 'isover' ? 1 : 0);
1965 // we just moved into a greedy child
1966 if (parentInstance && c == 'isover') {
1967 parentInstance['isover'] = 0;
1968 parentInstance['isout'] = 1;
1969 parentInstance._out.call(parentInstance, event);
1972 this[c] = 1; this[c == 'isout' ? 'isover' : 'isout'] = 0;
1973 this[c == "isover" ? "_over" : "_out"].call(this, event);
1975 // we just moved out of a greedy child
1976 if (parentInstance && c == 'isout') {
1977 parentInstance['isout'] = 0;
1978 parentInstance['isover'] = 1;
1979 parentInstance._over.call(parentInstance, event);
1988 * jQuery UI Resizable 1.8.4
1990 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
1991 * Dual licensed under the MIT or GPL Version 2 licenses.
1992 * http://jquery.org/license
1994 * http://docs.jquery.com/UI/Resizables
1998 * jquery.ui.mouse.js
1999 * jquery.ui.widget.js
2001 (function( $, undefined ) {
2003 $.widget("ui.resizable", $.ui.mouse, {
2004 widgetEventPrefix: "resize",
2008 animateDuration: "slow",
2009 animateEasing: "swing",
2023 _create: function() {
2025 var self = this, o = this.options;
2026 this.element.addClass("ui-resizable");
2029 _aspectRatio: !!(o.aspectRatio),
2030 aspectRatio: o.aspectRatio,
2031 originalElement: this.element,
2032 _proportionallyResizeElements: [],
2033 _helper: o.helper || o.ghost || o.animate ? o.helper || 'ui-resizable-helper' : null
2036 //Wrap the element if it cannot hold child nodes
2037 if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {
2039 //Opera fix for relative positioning
2040 if (/relative/.test(this.element.css('position')) && $.browser.opera)
2041 this.element.css({ position: 'relative', top: 'auto', left: 'auto' });
2043 //Create a wrapper element and set the wrapper to the new current internal element
2045 $('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({
2046 position: this.element.css('position'),
2047 width: this.element.outerWidth(),
2048 height: this.element.outerHeight(),
2049 top: this.element.css('top'),
2050 left: this.element.css('left')
2054 //Overwrite the original this.element
2055 this.element = this.element.parent().data(
2056 "resizable", this.element.data('resizable')
2059 this.elementIsWrapper = true;
2061 //Move margins to the wrapper
2062 this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") });
2063 this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});
2065 //Prevent Safari textarea resize
2066 this.originalResizeStyle = this.originalElement.css('resize');
2067 this.originalElement.css('resize', 'none');
2069 //Push the actual element to our proportionallyResize internal array
2070 this._proportionallyResizeElements.push(this.originalElement.css({ position: 'static', zoom: 1, display: 'block' }));
2072 // avoid IE jump (hard set the margin)
2073 this.originalElement.css({ margin: this.originalElement.css('margin') });
2075 // fix handlers offset
2076 this._proportionallyResize();
2080 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' });
2081 if(this.handles.constructor == String) {
2083 if(this.handles == 'all') this.handles = 'n,e,s,w,se,sw,ne,nw';
2084 var n = this.handles.split(","); this.handles = {};
2086 for(var i = 0; i < n.length; i++) {
2088 var handle = $.trim(n[i]), hname = 'ui-resizable-'+handle;
2089 var axis = $('<div class="ui-resizable-handle ' + hname + '"></div>');
2091 // increase zIndex of sw, se, ne, nw axis
2092 //TODO : this modifies original option
2093 if(/sw|se|ne|nw/.test(handle)) axis.css({ zIndex: ++o.zIndex });
2095 //TODO : What's going on here?
2096 if ('se' == handle) {
2097 axis.addClass('ui-icon ui-icon-gripsmall-diagonal-se');
2100 //Insert into internal handles object and append to element
2101 this.handles[handle] = '.ui-resizable-'+handle;
2102 this.element.append(axis);
2107 this._renderAxis = function(target) {
2109 target = target || this.element;
2111 for(var i in this.handles) {
2113 if(this.handles[i].constructor == String)
2114 this.handles[i] = $(this.handles[i], this.element).show();
2116 //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)
2117 if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {
2119 var axis = $(this.handles[i], this.element), padWrapper = 0;
2121 //Checking the correct pad and border
2122 padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
2124 //The padding type i have to apply...
2125 var padPos = [ 'padding',
2126 /ne|nw|n/.test(i) ? 'Top' :
2127 /se|sw|s/.test(i) ? 'Bottom' :
2128 /^e$/.test(i) ? 'Right' : 'Left' ].join("");
2130 target.css(padPos, padWrapper);
2132 this._proportionallyResize();
2136 //TODO: What's that good for? There's not anything to be executed left
2137 if(!$(this.handles[i]).length)
2143 //TODO: make renderAxis a prototype function
2144 this._renderAxis(this.element);
2146 this._handles = $('.ui-resizable-handle', this.element)
2147 .disableSelection();
2149 //Matching axis name
2150 this._handles.mouseover(function() {
2151 if (!self.resizing) {
2153 var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
2154 //Axis, default = se
2155 self.axis = axis && axis[1] ? axis[1] : 'se';
2159 //If we want to auto hide the elements
2161 this._handles.hide();
2163 .addClass("ui-resizable-autohide")
2165 $(this).removeClass("ui-resizable-autohide");
2166 self._handles.show();
2169 if (!self.resizing) {
2170 $(this).addClass("ui-resizable-autohide");
2171 self._handles.hide();
2176 //Initialize the mouse interaction
2181 destroy: function() {
2183 this._mouseDestroy();
2185 var _destroy = function(exp) {
2186 $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
2187 .removeData("resizable").unbind(".resizable").find('.ui-resizable-handle').remove();
2190 //TODO: Unwrap at same DOM position
2191 if (this.elementIsWrapper) {
2192 _destroy(this.element);
2193 var wrapper = this.element;
2195 this.originalElement.css({
2196 position: wrapper.css('position'),
2197 width: wrapper.outerWidth(),
2198 height: wrapper.outerHeight(),
2199 top: wrapper.css('top'),
2200 left: wrapper.css('left')
2205 this.originalElement.css('resize', this.originalResizeStyle);
2206 _destroy(this.originalElement);
2211 _mouseCapture: function(event) {
2213 for (var i in this.handles) {
2214 if ($(this.handles[i])[0] == event.target) {
2219 return !this.options.disabled && handle;
2222 _mouseStart: function(event) {
2224 var o = this.options, iniPos = this.element.position(), el = this.element;
2226 this.resizing = true;
2227 this.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() };
2229 // bugfix for http://dev.jquery.com/ticket/1749
2230 if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) {
2231 el.css({ position: 'absolute', top: iniPos.top, left: iniPos.left });
2234 //Opera fixing relative position
2235 if ($.browser.opera && (/relative/).test(el.css('position')))
2236 el.css({ position: 'relative', top: 'auto', left: 'auto' });
2238 this._renderProxy();
2240 var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top'));
2242 if (o.containment) {
2243 curleft += $(o.containment).scrollLeft() || 0;
2244 curtop += $(o.containment).scrollTop() || 0;
2247 //Store needed variables
2248 this.offset = this.helper.offset();
2249 this.position = { left: curleft, top: curtop };
2250 this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
2251 this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
2252 this.originalPosition = { left: curleft, top: curtop };
2253 this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };
2254 this.originalMousePosition = { left: event.pageX, top: event.pageY };
2257 this.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1);
2259 var cursor = $('.ui-resizable-' + this.axis).css('cursor');
2260 $('body').css('cursor', cursor == 'auto' ? this.axis + '-resize' : cursor);
2262 el.addClass("ui-resizable-resizing");
2263 this._propagate("start", event);
2267 _mouseDrag: function(event) {
2269 //Increase performance, avoid regex
2270 var el = this.helper, o = this.options, props = {},
2271 self = this, smp = this.originalMousePosition, a = this.axis;
2273 var dx = (event.pageX-smp.left)||0, dy = (event.pageY-smp.top)||0;
2274 var trigger = this._change[a];
2275 if (!trigger) return false;
2277 // Calculate the attrs that will be change
2278 var data = trigger.apply(this, [event, dx, dy]), ie6 = $.browser.msie && $.browser.version < 7, csdif = this.sizeDiff;
2280 if (this._aspectRatio || event.shiftKey)
2281 data = this._updateRatio(data, event);
2283 data = this._respectSize(data, event);
2285 // plugins callbacks need to be called first
2286 this._propagate("resize", event);
2289 top: this.position.top + "px", left: this.position.left + "px",
2290 width: this.size.width + "px", height: this.size.height + "px"
2293 if (!this._helper && this._proportionallyResizeElements.length)
2294 this._proportionallyResize();
2296 this._updateCache(data);
2298 // calling the user callback at the end
2299 this._trigger('resize', event, this.ui());
2304 _mouseStop: function(event) {
2306 this.resizing = false;
2307 var o = this.options, self = this;
2310 var pr = this._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName),
2311 soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height,
2312 soffsetw = ista ? 0 : self.sizeDiff.width;
2314 var s = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) },
2315 left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null,
2316 top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null;
2319 this.element.css($.extend(s, { top: top, left: left }));
2321 self.helper.height(self.size.height);
2322 self.helper.width(self.size.width);
2324 if (this._helper && !o.animate) this._proportionallyResize();
2327 $('body').css('cursor', 'auto');
2329 this.element.removeClass("ui-resizable-resizing");
2331 this._propagate("stop", event);
2333 if (this._helper) this.helper.remove();
2338 _updateCache: function(data) {
2339 var o = this.options;
2340 this.offset = this.helper.offset();
2341 if (isNumber(data.left)) this.position.left = data.left;
2342 if (isNumber(data.top)) this.position.top = data.top;
2343 if (isNumber(data.height)) this.size.height = data.height;
2344 if (isNumber(data.width)) this.size.width = data.width;
2347 _updateRatio: function(data, event) {
2349 var o = this.options, cpos = this.position, csize = this.size, a = this.axis;
2351 if (data.height) data.width = (csize.height * this.aspectRatio);
2352 else if (data.width) data.height = (csize.width / this.aspectRatio);
2355 data.left = cpos.left + (csize.width - data.width);
2359 data.top = cpos.top + (csize.height - data.height);
2360 data.left = cpos.left + (csize.width - data.width);
2366 _respectSize: function(data, event) {
2368 var el = this.helper, o = this.options, pRatio = this._aspectRatio || event.shiftKey, a = this.axis,
2369 ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
2370 isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height);
2372 if (isminw) data.width = o.minWidth;
2373 if (isminh) data.height = o.minHeight;
2374 if (ismaxw) data.width = o.maxWidth;
2375 if (ismaxh) data.height = o.maxHeight;
2377 var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height;
2378 var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
2380 if (isminw && cw) data.left = dw - o.minWidth;
2381 if (ismaxw && cw) data.left = dw - o.maxWidth;
2382 if (isminh && ch) data.top = dh - o.minHeight;
2383 if (ismaxh && ch) data.top = dh - o.maxHeight;
2385 // fixing jump error on top/left - bug #2330
2386 var isNotwh = !data.width && !data.height;
2387 if (isNotwh && !data.left && data.top) data.top = null;
2388 else if (isNotwh && !data.top && data.left) data.left = null;
2393 _proportionallyResize: function() {
2395 var o = this.options;
2396 if (!this._proportionallyResizeElements.length) return;
2397 var element = this.helper || this.element;
2399 for (var i=0; i < this._proportionallyResizeElements.length; i++) {
2401 var prel = this._proportionallyResizeElements[i];
2403 if (!this.borderDif) {
2404 var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')],
2405 p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')];
2407 this.borderDif = $.map(b, function(v, i) {
2408 var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0;
2409 return border + padding;
2413 if ($.browser.msie && !(!($(element).is(':hidden') || $(element).parents(':hidden').length)))
2417 height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0,
2418 width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0
2425 _renderProxy: function() {
2427 var el = this.element, o = this.options;
2428 this.elementOffset = el.offset();
2432 this.helper = this.helper || $('<div style="overflow:hidden;"></div>');
2434 // fix ie6 offset TODO: This seems broken
2435 var ie6 = $.browser.msie && $.browser.version < 7, ie6offset = (ie6 ? 1 : 0),
2436 pxyoffset = ( ie6 ? 2 : -1 );
2438 this.helper.addClass(this._helper).css({
2439 width: this.element.outerWidth() + pxyoffset,
2440 height: this.element.outerHeight() + pxyoffset,
2441 position: 'absolute',
2442 left: this.elementOffset.left - ie6offset +'px',
2443 top: this.elementOffset.top - ie6offset +'px',
2444 zIndex: ++o.zIndex //TODO: Don't modify option
2449 .disableSelection();
2452 this.helper = this.element;
2458 e: function(event, dx, dy) {
2459 return { width: this.originalSize.width + dx };
2461 w: function(event, dx, dy) {
2462 var o = this.options, cs = this.originalSize, sp = this.originalPosition;
2463 return { left: sp.left + dx, width: cs.width - dx };
2465 n: function(event, dx, dy) {
2466 var o = this.options, cs = this.originalSize, sp = this.originalPosition;
2467 return { top: sp.top + dy, height: cs.height - dy };
2469 s: function(event, dx, dy) {
2470 return { height: this.originalSize.height + dy };
2472 se: function(event, dx, dy) {
2473 return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
2475 sw: function(event, dx, dy) {
2476 return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
2478 ne: function(event, dx, dy) {
2479 return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
2481 nw: function(event, dx, dy) {
2482 return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
2486 _propagate: function(n, event) {
2487 $.ui.plugin.call(this, n, [event, this.ui()]);
2488 (n != "resize" && this._trigger(n, event, this.ui()));
2495 originalElement: this.originalElement,
2496 element: this.element,
2497 helper: this.helper,
2498 position: this.position,
2500 originalSize: this.originalSize,
2501 originalPosition: this.originalPosition
2507 $.extend($.ui.resizable, {
2512 * Resizable Extensions
2515 $.ui.plugin.add("resizable", "alsoResize", {
2517 start: function (event, ui) {
2518 var self = $(this).data("resizable"), o = self.options;
2520 var _store = function (exp) {
2521 $(exp).each(function() {
2523 el.data("resizable-alsoresize", {
2524 width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
2525 left: parseInt(el.css('left'), 10), top: parseInt(el.css('top'), 10),
2526 position: el.css('position') // to reset Opera on stop()
2531 if (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) {
2532 if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); }
2533 else { $.each(o.alsoResize, function (exp) { _store(exp); }); }
2535 _store(o.alsoResize);
2539 resize: function (event, ui) {
2540 var self = $(this).data("resizable"), o = self.options, os = self.originalSize, op = self.originalPosition;
2543 height: (self.size.height - os.height) || 0, width: (self.size.width - os.width) || 0,
2544 top: (self.position.top - op.top) || 0, left: (self.position.left - op.left) || 0
2547 _alsoResize = function (exp, c) {
2548 $(exp).each(function() {
2549 var el = $(this), start = $(this).data("resizable-alsoresize"), style = {},
2550 css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ['width', 'height'] : ['width', 'height', 'top', 'left'];
2552 $.each(css, function (i, prop) {
2553 var sum = (start[prop]||0) + (delta[prop]||0);
2554 if (sum && sum >= 0)
2555 style[prop] = sum || null;
2558 // Opera fixing relative position
2559 if ($.browser.opera && /relative/.test(el.css('position'))) {
2560 self._revertToRelativePosition = true;
2561 el.css({ position: 'absolute', top: 'auto', left: 'auto' });
2568 if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) {
2569 $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); });
2571 _alsoResize(o.alsoResize);
2575 stop: function (event, ui) {
2576 var self = $(this).data("resizable"), o = self.options;
2578 var _reset = function (exp) {
2579 $(exp).each(function() {
2581 // reset position for Opera - no need to verify it was changed
2582 el.css({ position: el.data("resizable-alsoresize").position });
2586 if (self._revertToRelativePosition) {
2587 self._revertToRelativePosition = false;
2588 if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) {
2589 $.each(o.alsoResize, function (exp) { _reset(exp); });
2591 _reset(o.alsoResize);
2595 $(this).removeData("resizable-alsoresize");
2599 $.ui.plugin.add("resizable", "animate", {
2601 stop: function(event, ui) {
2602 var self = $(this).data("resizable"), o = self.options;
2604 var pr = self._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName),
2605 soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height,
2606 soffsetw = ista ? 0 : self.sizeDiff.width;
2608 var style = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) },
2609 left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null,
2610 top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null;
2612 self.element.animate(
2613 $.extend(style, top && left ? { top: top, left: left } : {}), {
2614 duration: o.animateDuration,
2615 easing: o.animateEasing,
2619 width: parseInt(self.element.css('width'), 10),
2620 height: parseInt(self.element.css('height'), 10),
2621 top: parseInt(self.element.css('top'), 10),
2622 left: parseInt(self.element.css('left'), 10)
2625 if (pr && pr.length) $(pr[0]).css({ width: data.width, height: data.height });
2627 // propagating resize, and updating values for each animation step
2628 self._updateCache(data);
2629 self._propagate("resize", event);
2638 $.ui.plugin.add("resizable", "containment", {
2640 start: function(event, ui) {
2641 var self = $(this).data("resizable"), o = self.options, el = self.element;
2642 var oc = o.containment, ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc;
2645 self.containerElement = $(ce);
2647 if (/document/.test(oc) || oc == document) {
2648 self.containerOffset = { left: 0, top: 0 };
2649 self.containerPosition = { left: 0, top: 0 };
2652 element: $(document), left: 0, top: 0,
2653 width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight
2657 // i'm a node, so compute top, left, right, bottom
2659 var element = $(ce), p = [];
2660 $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); });
2662 self.containerOffset = element.offset();
2663 self.containerPosition = element.position();
2664 self.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) };
2666 var co = self.containerOffset, ch = self.containerSize.height, cw = self.containerSize.width,
2667 width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch);
2670 element: ce, left: co.left, top: co.top, width: width, height: height
2675 resize: function(event, ui) {
2676 var self = $(this).data("resizable"), o = self.options,
2677 ps = self.containerSize, co = self.containerOffset, cs = self.size, cp = self.position,
2678 pRatio = self._aspectRatio || event.shiftKey, cop = { top:0, left:0 }, ce = self.containerElement;
2680 if (ce[0] != document && (/static/).test(ce.css('position'))) cop = co;
2682 if (cp.left < (self._helper ? co.left : 0)) {
2683 self.size.width = self.size.width + (self._helper ? (self.position.left - co.left) : (self.position.left - cop.left));
2684 if (pRatio) self.size.height = self.size.width / o.aspectRatio;
2685 self.position.left = o.helper ? co.left : 0;
2688 if (cp.top < (self._helper ? co.top : 0)) {
2689 self.size.height = self.size.height + (self._helper ? (self.position.top - co.top) : self.position.top);
2690 if (pRatio) self.size.width = self.size.height * o.aspectRatio;
2691 self.position.top = self._helper ? co.top : 0;
2694 self.offset.left = self.parentData.left+self.position.left;
2695 self.offset.top = self.parentData.top+self.position.top;
2697 var woset = Math.abs( (self._helper ? self.offset.left - cop.left : (self.offset.left - cop.left)) + self.sizeDiff.width ),
2698 hoset = Math.abs( (self._helper ? self.offset.top - cop.top : (self.offset.top - co.top)) + self.sizeDiff.height );
2700 var isParent = self.containerElement.get(0) == self.element.parent().get(0),
2701 isOffsetRelative = /relative|absolute/.test(self.containerElement.css('position'));
2703 if(isParent && isOffsetRelative) woset -= self.parentData.left;
2705 if (woset + self.size.width >= self.parentData.width) {
2706 self.size.width = self.parentData.width - woset;
2707 if (pRatio) self.size.height = self.size.width / self.aspectRatio;
2710 if (hoset + self.size.height >= self.parentData.height) {
2711 self.size.height = self.parentData.height - hoset;
2712 if (pRatio) self.size.width = self.size.height * self.aspectRatio;
2716 stop: function(event, ui){
2717 var self = $(this).data("resizable"), o = self.options, cp = self.position,
2718 co = self.containerOffset, cop = self.containerPosition, ce = self.containerElement;
2720 var helper = $(self.helper), ho = helper.offset(), w = helper.outerWidth() - self.sizeDiff.width, h = helper.outerHeight() - self.sizeDiff.height;
2722 if (self._helper && !o.animate && (/relative/).test(ce.css('position')))
2723 $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
2725 if (self._helper && !o.animate && (/static/).test(ce.css('position')))
2726 $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
2731 $.ui.plugin.add("resizable", "ghost", {
2733 start: function(event, ui) {
2735 var self = $(this).data("resizable"), o = self.options, cs = self.size;
2737 self.ghost = self.originalElement.clone();
2739 .css({ opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 })
2740 .addClass('ui-resizable-ghost')
2741 .addClass(typeof o.ghost == 'string' ? o.ghost : '');
2743 self.ghost.appendTo(self.helper);
2747 resize: function(event, ui){
2748 var self = $(this).data("resizable"), o = self.options;
2749 if (self.ghost) self.ghost.css({ position: 'relative', height: self.size.height, width: self.size.width });
2752 stop: function(event, ui){
2753 var self = $(this).data("resizable"), o = self.options;
2754 if (self.ghost && self.helper) self.helper.get(0).removeChild(self.ghost.get(0));
2759 $.ui.plugin.add("resizable", "grid", {
2761 resize: function(event, ui) {
2762 var self = $(this).data("resizable"), o = self.options, cs = self.size, os = self.originalSize, op = self.originalPosition, a = self.axis, ratio = o._aspectRatio || event.shiftKey;
2763 o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid;
2764 var ox = Math.round((cs.width - os.width) / (o.grid[0]||1)) * (o.grid[0]||1), oy = Math.round((cs.height - os.height) / (o.grid[1]||1)) * (o.grid[1]||1);
2766 if (/^(se|s|e)$/.test(a)) {
2767 self.size.width = os.width + ox;
2768 self.size.height = os.height + oy;
2770 else if (/^(ne)$/.test(a)) {
2771 self.size.width = os.width + ox;
2772 self.size.height = os.height + oy;
2773 self.position.top = op.top - oy;
2775 else if (/^(sw)$/.test(a)) {
2776 self.size.width = os.width + ox;
2777 self.size.height = os.height + oy;
2778 self.position.left = op.left - ox;
2781 self.size.width = os.width + ox;
2782 self.size.height = os.height + oy;
2783 self.position.top = op.top - oy;
2784 self.position.left = op.left - ox;
2790 var num = function(v) {
2791 return parseInt(v, 10) || 0;
2794 var isNumber = function(value) {
2795 return !isNaN(parseInt(value, 10));
2800 * jQuery UI Selectable 1.8.4
2802 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
2803 * Dual licensed under the MIT or GPL Version 2 licenses.
2804 * http://jquery.org/license
2806 * http://docs.jquery.com/UI/Selectables
2810 * jquery.ui.mouse.js
2811 * jquery.ui.widget.js
2813 (function( $, undefined ) {
2815 $.widget("ui.selectable", $.ui.mouse, {
2823 _create: function() {
2826 this.element.addClass("ui-selectable");
2828 this.dragged = false;
2830 // cache selectee children based on filter
2832 this.refresh = function() {
2833 selectees = $(self.options.filter, self.element[0]);
2834 selectees.each(function() {
2835 var $this = $(this);
2836 var pos = $this.offset();
2837 $.data(this, "selectable-item", {
2842 right: pos.left + $this.outerWidth(),
2843 bottom: pos.top + $this.outerHeight(),
2844 startselected: false,
2845 selected: $this.hasClass('ui-selected'),
2846 selecting: $this.hasClass('ui-selecting'),
2847 unselecting: $this.hasClass('ui-unselecting')
2853 this.selectees = selectees.addClass("ui-selectee");
2857 this.helper = $("<div class='ui-selectable-helper'></div>");
2860 destroy: function() {
2862 .removeClass("ui-selectee")
2863 .removeData("selectable-item");
2865 .removeClass("ui-selectable ui-selectable-disabled")
2866 .removeData("selectable")
2867 .unbind(".selectable");
2868 this._mouseDestroy();
2873 _mouseStart: function(event) {
2876 this.opos = [event.pageX, event.pageY];
2878 if (this.options.disabled)
2881 var options = this.options;
2883 this.selectees = $(options.filter, this.element[0]);
2885 this._trigger("start", event);
2887 $(options.appendTo).append(this.helper);
2888 // position helper (lasso)
2890 "left": event.clientX,
2891 "top": event.clientY,
2896 if (options.autoRefresh) {
2900 this.selectees.filter('.ui-selected').each(function() {
2901 var selectee = $.data(this, "selectable-item");
2902 selectee.startselected = true;
2903 if (!event.metaKey) {
2904 selectee.$element.removeClass('ui-selected');
2905 selectee.selected = false;
2906 selectee.$element.addClass('ui-unselecting');
2907 selectee.unselecting = true;
2908 // selectable UNSELECTING callback
2909 self._trigger("unselecting", event, {
2910 unselecting: selectee.element
2915 $(event.target).parents().andSelf().each(function() {
2916 var selectee = $.data(this, "selectable-item");
2918 var doSelect = !event.metaKey || !selectee.$element.hasClass('ui-selected');
2920 .removeClass(doSelect ? "ui-unselecting" : "ui-selected")
2921 .addClass(doSelect ? "ui-selecting" : "ui-unselecting");
2922 selectee.unselecting = !doSelect;
2923 selectee.selecting = doSelect;
2924 selectee.selected = doSelect;
2925 // selectable (UN)SELECTING callback
2927 self._trigger("selecting", event, {
2928 selecting: selectee.element
2931 self._trigger("unselecting", event, {
2932 unselecting: selectee.element
2941 _mouseDrag: function(event) {
2943 this.dragged = true;
2945 if (this.options.disabled)
2948 var options = this.options;
2950 var x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY;
2951 if (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; }
2952 if (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; }
2953 this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1});
2955 this.selectees.each(function() {
2956 var selectee = $.data(this, "selectable-item");
2957 //prevent helper from being selected if appendTo: selectable
2958 if (!selectee || selectee.element == self.element[0])
2961 if (options.tolerance == 'touch') {
2962 hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
2963 } else if (options.tolerance == 'fit') {
2964 hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
2969 if (selectee.selected) {
2970 selectee.$element.removeClass('ui-selected');
2971 selectee.selected = false;
2973 if (selectee.unselecting) {
2974 selectee.$element.removeClass('ui-unselecting');
2975 selectee.unselecting = false;
2977 if (!selectee.selecting) {
2978 selectee.$element.addClass('ui-selecting');
2979 selectee.selecting = true;
2980 // selectable SELECTING callback
2981 self._trigger("selecting", event, {
2982 selecting: selectee.element
2987 if (selectee.selecting) {
2988 if (event.metaKey && selectee.startselected) {
2989 selectee.$element.removeClass('ui-selecting');
2990 selectee.selecting = false;
2991 selectee.$element.addClass('ui-selected');
2992 selectee.selected = true;
2994 selectee.$element.removeClass('ui-selecting');
2995 selectee.selecting = false;
2996 if (selectee.startselected) {
2997 selectee.$element.addClass('ui-unselecting');
2998 selectee.unselecting = true;
3000 // selectable UNSELECTING callback
3001 self._trigger("unselecting", event, {
3002 unselecting: selectee.element
3006 if (selectee.selected) {
3007 if (!event.metaKey && !selectee.startselected) {
3008 selectee.$element.removeClass('ui-selected');
3009 selectee.selected = false;
3011 selectee.$element.addClass('ui-unselecting');
3012 selectee.unselecting = true;
3013 // selectable UNSELECTING callback
3014 self._trigger("unselecting", event, {
3015 unselecting: selectee.element
3025 _mouseStop: function(event) {
3028 this.dragged = false;
3030 var options = this.options;
3032 $('.ui-unselecting', this.element[0]).each(function() {
3033 var selectee = $.data(this, "selectable-item");
3034 selectee.$element.removeClass('ui-unselecting');
3035 selectee.unselecting = false;
3036 selectee.startselected = false;
3037 self._trigger("unselected", event, {
3038 unselected: selectee.element
3041 $('.ui-selecting', this.element[0]).each(function() {
3042 var selectee = $.data(this, "selectable-item");
3043 selectee.$element.removeClass('ui-selecting').addClass('ui-selected');
3044 selectee.selecting = false;
3045 selectee.selected = true;
3046 selectee.startselected = true;
3047 self._trigger("selected", event, {
3048 selected: selectee.element
3051 this._trigger("stop", event);
3053 this.helper.remove();
3060 $.extend($.ui.selectable, {
3066 * jQuery UI Sortable 1.8.4
3068 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
3069 * Dual licensed under the MIT or GPL Version 2 licenses.
3070 * http://jquery.org/license
3072 * http://docs.jquery.com/UI/Sortables
3076 * jquery.ui.mouse.js
3077 * jquery.ui.widget.js
3079 (function( $, undefined ) {
3081 $.widget("ui.sortable", $.ui.mouse, {
3082 widgetEventPrefix: "sort",
3091 forcePlaceholderSize: false,
3092 forceHelperSize: false,
3101 scrollSensitivity: 20,
3104 tolerance: "intersect",
3107 _create: function() {
3109 var o = this.options;
3110 this.containerCache = {};
3111 this.element.addClass("ui-sortable");
3116 //Let's determine if the items are floating
3117 this.floating = this.items.length ? (/left|right/).test(this.items[0].item.css('float')) : false;
3119 //Let's determine the parent's offset
3120 this.offset = this.element.offset();
3122 //Initialize mouse events for interaction
3127 destroy: function() {
3129 .removeClass("ui-sortable ui-sortable-disabled")
3130 .removeData("sortable")
3131 .unbind(".sortable");
3132 this._mouseDestroy();
3134 for ( var i = this.items.length - 1; i >= 0; i-- )
3135 this.items[i].item.removeData("sortable-item");
3140 _setOption: function(key, value){
3141 if ( key === "disabled" ) {
3142 this.options[ key ] = value;
3145 [ value ? "addClass" : "removeClass"]( "ui-sortable-disabled" );
3147 // Don't call widget base _setOption for disable as it adds ui-state-disabled class
3148 $.Widget.prototype._setOption.apply(this, arguments);
3152 _mouseCapture: function(event, overrideHandle) {
3154 if (this.reverting) {
3158 if(this.options.disabled || this.options.type == 'static') return false;
3160 //We have to refresh the items data once first
3161 this._refreshItems(event);
3163 //Find out if the clicked node (or one of its parents) is a actual item in this.items
3164 var currentItem = null, self = this, nodes = $(event.target).parents().each(function() {
3165 if($.data(this, 'sortable-item') == self) {
3166 currentItem = $(this);
3170 if($.data(event.target, 'sortable-item') == self) currentItem = $(event.target);
3172 if(!currentItem) return false;
3173 if(this.options.handle && !overrideHandle) {
3174 var validHandle = false;
3176 $(this.options.handle, currentItem).find("*").andSelf().each(function() { if(this == event.target) validHandle = true; });
3177 if(!validHandle) return false;
3180 this.currentItem = currentItem;
3181 this._removeCurrentsFromItems();
3186 _mouseStart: function(event, overrideHandle, noActivation) {
3188 var o = this.options, self = this;
3189 this.currentContainer = this;
3191 //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
3192 this.refreshPositions();
3194 //Create and append the visible helper
3195 this.helper = this._createHelper(event);
3197 //Cache the helper size
3198 this._cacheHelperProportions();
3201 * - Position generation -
3202 * This block generates everything position related - it's the core of draggables.
3205 //Cache the margins of the original element
3206 this._cacheMargins();
3208 //Get the next scrolling parent
3209 this.scrollParent = this.helper.scrollParent();
3211 //The element's absolute position on the page minus margins
3212 this.offset = this.currentItem.offset();
3214 top: this.offset.top - this.margins.top,
3215 left: this.offset.left - this.margins.left
3218 // Only after we got the offset, we can change the helper's position to absolute
3219 // TODO: Still need to figure out a way to make relative sorting possible
3220 this.helper.css("position", "absolute");
3221 this.cssPosition = this.helper.css("position");
3223 $.extend(this.offset, {
3224 click: { //Where the click happened, relative to the element
3225 left: event.pageX - this.offset.left,
3226 top: event.pageY - this.offset.top
3228 parent: this._getParentOffset(),
3229 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
3232 //Generate the original position
3233 this.originalPosition = this._generatePosition(event);
3234 this.originalPageX = event.pageX;
3235 this.originalPageY = event.pageY;
3237 //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
3238 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
3240 //Cache the former DOM position
3241 this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
3243 //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
3244 if(this.helper[0] != this.currentItem[0]) {
3245 this.currentItem.hide();
3248 //Create the placeholder
3249 this._createPlaceholder();
3251 //Set a containment if given in the options
3253 this._setContainment();
3255 if(o.cursor) { // cursor option
3256 if ($('body').css("cursor")) this._storedCursor = $('body').css("cursor");
3257 $('body').css("cursor", o.cursor);
3260 if(o.opacity) { // opacity option
3261 if (this.helper.css("opacity")) this._storedOpacity = this.helper.css("opacity");
3262 this.helper.css("opacity", o.opacity);
3265 if(o.zIndex) { // zIndex option
3266 if (this.helper.css("zIndex")) this._storedZIndex = this.helper.css("zIndex");
3267 this.helper.css("zIndex", o.zIndex);
3271 if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML')
3272 this.overflowOffset = this.scrollParent.offset();
3275 this._trigger("start", event, this._uiHash());
3277 //Recache the helper size
3278 if(!this._preserveHelperProportions)
3279 this._cacheHelperProportions();
3282 //Post 'activate' events to possible containers
3284 for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i]._trigger("activate", event, self._uiHash(this)); }
3287 //Prepare possible droppables
3289 $.ui.ddmanager.current = this;
3291 if ($.ui.ddmanager && !o.dropBehaviour)
3292 $.ui.ddmanager.prepareOffsets(this, event);
3294 this.dragging = true;
3296 this.helper.addClass("ui-sortable-helper");
3297 this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
3302 _mouseDrag: function(event) {
3304 //Compute the helpers position
3305 this.position = this._generatePosition(event);
3306 this.positionAbs = this._convertPositionTo("absolute");
3308 if (!this.lastPositionAbs) {
3309 this.lastPositionAbs = this.positionAbs;
3313 if(this.options.scroll) {
3314 var o = this.options, scrolled = false;
3315 if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') {
3317 if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
3318 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
3319 else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity)
3320 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
3322 if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
3323 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
3324 else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity)
3325 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
3329 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
3330 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
3331 else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
3332 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
3334 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
3335 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
3336 else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
3337 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
3341 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
3342 $.ui.ddmanager.prepareOffsets(this, event);
3345 //Regenerate the absolute position used for position checks
3346 this.positionAbs = this._convertPositionTo("absolute");
3348 //Set the helper position
3349 if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
3350 if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
3353 for (var i = this.items.length - 1; i >= 0; i--) {
3355 //Cache variables and intersection, continue if no intersection
3356 var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item);
3357 if (!intersection) continue;
3359 if(itemElement != this.currentItem[0] //cannot intersect with itself
3360 && this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before
3361 && !$.ui.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked
3362 && (this.options.type == 'semi-dynamic' ? !$.ui.contains(this.element[0], itemElement) : true)
3363 //&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container
3366 this.direction = intersection == 1 ? "down" : "up";
3368 if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) {
3369 this._rearrange(event, item);
3374 this._trigger("change", event, this._uiHash());
3379 //Post events to containers
3380 this._contactContainers(event);
3382 //Interconnect with droppables
3383 if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
3386 this._trigger('sort', event, this._uiHash());
3388 this.lastPositionAbs = this.positionAbs;
3393 _mouseStop: function(event, noPropagation) {
3397 //If we are using droppables, inform the manager about the drop
3398 if ($.ui.ddmanager && !this.options.dropBehaviour)
3399 $.ui.ddmanager.drop(this, event);
3401 if(this.options.revert) {
3403 var cur = self.placeholder.offset();
3405 self.reverting = true;
3407 $(this.helper).animate({
3408 left: cur.left - this.offset.parent.left - self.margins.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft),
3409 top: cur.top - this.offset.parent.top - self.margins.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop)
3410 }, parseInt(this.options.revert, 10) || 500, function() {
3414 this._clear(event, noPropagation);
3421 cancel: function() {
3429 if(this.options.helper == "original")
3430 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
3432 this.currentItem.show();
3434 //Post deactivating events to containers
3435 for (var i = this.containers.length - 1; i >= 0; i--){
3436 this.containers[i]._trigger("deactivate", null, self._uiHash(this));
3437 if(this.containers[i].containerCache.over) {
3438 this.containers[i]._trigger("out", null, self._uiHash(this));
3439 this.containers[i].containerCache.over = 0;
3445 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
3446 if(this.placeholder[0].parentNode) this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
3447 if(this.options.helper != "original" && this.helper && this.helper[0].parentNode) this.helper.remove();
3456 if(this.domPosition.prev) {
3457 $(this.domPosition.prev).after(this.currentItem);
3459 $(this.domPosition.parent).prepend(this.currentItem);
3466 serialize: function(o) {
3468 var items = this._getItemsAsjQuery(o && o.connected);
3469 var str = []; o = o || {};
3471 $(items).each(function() {
3472 var res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
3473 if(res) str.push((o.key || res[1]+'[]')+'='+(o.key && o.expression ? res[1] : res[2]));
3476 if(!str.length && o.key) {
3477 str.push(o.key + '=');
3480 return str.join('&');
3484 toArray: function(o) {
3486 var items = this._getItemsAsjQuery(o && o.connected);
3487 var ret = []; o = o || {};
3489 items.each(function() { ret.push($(o.item || this).attr(o.attribute || 'id') || ''); });
3494 /* Be careful with the following core functions */
3495 _intersectsWith: function(item) {
3497 var x1 = this.positionAbs.left,
3498 x2 = x1 + this.helperProportions.width,
3499 y1 = this.positionAbs.top,
3500 y2 = y1 + this.helperProportions.height;
3505 b = t + item.height;
3507 var dyClick = this.offset.click.top,
3508 dxClick = this.offset.click.left;
3510 var isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r;
3512 if( this.options.tolerance == "pointer"
3513 || this.options.forcePointerForContainers
3514 || (this.options.tolerance != "pointer" && this.helperProportions[this.floating ? 'width' : 'height'] > item[this.floating ? 'width' : 'height'])
3516 return isOverElement;
3519 return (l < x1 + (this.helperProportions.width / 2) // Right Half
3520 && x2 - (this.helperProportions.width / 2) < r // Left Half
3521 && t < y1 + (this.helperProportions.height / 2) // Bottom Half
3522 && y2 - (this.helperProportions.height / 2) < b ); // Top Half
3527 _intersectsWithPointer: function(item) {
3529 var isOverElementHeight = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
3530 isOverElementWidth = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
3531 isOverElement = isOverElementHeight && isOverElementWidth,
3532 verticalDirection = this._getDragVerticalDirection(),
3533 horizontalDirection = this._getDragHorizontalDirection();
3538 return this.floating ?
3539 ( ((horizontalDirection && horizontalDirection == "right") || verticalDirection == "down") ? 2 : 1 )
3540 : ( verticalDirection && (verticalDirection == "down" ? 2 : 1) );
3544 _intersectsWithSides: function(item) {
3546 var isOverBottomHalf = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
3547 isOverRightHalf = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
3548 verticalDirection = this._getDragVerticalDirection(),
3549 horizontalDirection = this._getDragHorizontalDirection();
3551 if (this.floating && horizontalDirection) {
3552 return ((horizontalDirection == "right" && isOverRightHalf) || (horizontalDirection == "left" && !isOverRightHalf));
3554 return verticalDirection && ((verticalDirection == "down" && isOverBottomHalf) || (verticalDirection == "up" && !isOverBottomHalf));
3559 _getDragVerticalDirection: function() {
3560 var delta = this.positionAbs.top - this.lastPositionAbs.top;
3561 return delta != 0 && (delta > 0 ? "down" : "up");
3564 _getDragHorizontalDirection: function() {
3565 var delta = this.positionAbs.left - this.lastPositionAbs.left;
3566 return delta != 0 && (delta > 0 ? "right" : "left");
3569 refresh: function(event) {
3570 this._refreshItems(event);
3571 this.refreshPositions();
3575 _connectWith: function() {
3576 var options = this.options;
3577 return options.connectWith.constructor == String
3578 ? [options.connectWith]
3579 : options.connectWith;
3582 _getItemsAsjQuery: function(connected) {
3587 var connectWith = this._connectWith();
3589 if(connectWith && connected) {
3590 for (var i = connectWith.length - 1; i >= 0; i--){
3591 var cur = $(connectWith[i]);
3592 for (var j = cur.length - 1; j >= 0; j--){
3593 var inst = $.data(cur[j], 'sortable');
3594 if(inst && inst != this && !inst.options.disabled) {
3595 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]);
3601 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]);
3603 for (var i = queries.length - 1; i >= 0; i--){
3604 queries[i][0].each(function() {
3613 _removeCurrentsFromItems: function() {
3615 var list = this.currentItem.find(":data(sortable-item)");
3617 for (var i=0; i < this.items.length; i++) {
3619 for (var j=0; j < list.length; j++) {
3620 if(list[j] == this.items[i].item[0])
3621 this.items.splice(i,1);
3628 _refreshItems: function(event) {
3631 this.containers = [this];
3632 var items = this.items;
3634 var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]];
3635 var connectWith = this._connectWith();
3638 for (var i = connectWith.length - 1; i >= 0; i--){
3639 var cur = $(connectWith[i]);
3640 for (var j = cur.length - 1; j >= 0; j--){
3641 var inst = $.data(cur[j], 'sortable');
3642 if(inst && inst != this && !inst.options.disabled) {
3643 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
3644 this.containers.push(inst);
3650 for (var i = queries.length - 1; i >= 0; i--) {
3651 var targetData = queries[i][1];
3652 var _queries = queries[i][0];
3654 for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) {
3655 var item = $(_queries[j]);
3657 item.data('sortable-item', targetData); // Data for target checking (mouse manager)
3661 instance: targetData,
3662 width: 0, height: 0,
3670 refreshPositions: function(fast) {
3672 //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
3673 if(this.offsetParent && this.helper) {
3674 this.offset.parent = this._getParentOffset();
3677 for (var i = this.items.length - 1; i >= 0; i--){
3678 var item = this.items[i];
3680 var t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
3683 item.width = t.outerWidth();
3684 item.height = t.outerHeight();
3692 if(this.options.custom && this.options.custom.refreshContainers) {
3693 this.options.custom.refreshContainers.call(this);
3695 for (var i = this.containers.length - 1; i >= 0; i--){
3696 var p = this.containers[i].element.offset();
3697 this.containers[i].containerCache.left = p.left;
3698 this.containers[i].containerCache.top = p.top;
3699 this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
3700 this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
3707 _createPlaceholder: function(that) {
3709 var self = that || this, o = self.options;
3711 if(!o.placeholder || o.placeholder.constructor == String) {
3712 var className = o.placeholder;
3714 element: function() {
3716 var el = $(document.createElement(self.currentItem[0].nodeName))
3717 .addClass(className || self.currentItem[0].className+" ui-sortable-placeholder")
3718 .removeClass("ui-sortable-helper")[0];
3721 el.style.visibility = "hidden";
3725 update: function(container, p) {
3727 // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
3728 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
3729 if(className && !o.forcePlaceholderSize) return;
3731 //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
3732 if(!p.height()) { p.height(self.currentItem.innerHeight() - parseInt(self.currentItem.css('paddingTop')||0, 10) - parseInt(self.currentItem.css('paddingBottom')||0, 10)); };
3733 if(!p.width()) { p.width(self.currentItem.innerWidth() - parseInt(self.currentItem.css('paddingLeft')||0, 10) - parseInt(self.currentItem.css('paddingRight')||0, 10)); };
3738 //Create the placeholder
3739 self.placeholder = $(o.placeholder.element.call(self.element, self.currentItem));
3741 //Append it after the actual current item
3742 self.currentItem.after(self.placeholder);
3744 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
3745 o.placeholder.update(self, self.placeholder);
3749 _contactContainers: function(event) {
3751 // get innermost container that intersects with item
3752 var innermostContainer = null, innermostIndex = null;
3755 for (var i = this.containers.length - 1; i >= 0; i--){
3757 // never consider a container that's located within the item itself
3758 if($.ui.contains(this.currentItem[0], this.containers[i].element[0]))
3761 if(this._intersectsWith(this.containers[i].containerCache)) {
3763 // if we've already found a container and it's more "inner" than this, then continue
3764 if(innermostContainer && $.ui.contains(this.containers[i].element[0], innermostContainer.element[0]))
3767 innermostContainer = this.containers[i];
3771 // container doesn't intersect. trigger "out" event if necessary
3772 if(this.containers[i].containerCache.over) {
3773 this.containers[i]._trigger("out", event, this._uiHash(this));
3774 this.containers[i].containerCache.over = 0;
3780 // if no intersecting containers found, return
3781 if(!innermostContainer) return;
3783 // move the item into the container if it's not there already
3784 if(this.containers.length === 1) {
3785 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
3786 this.containers[innermostIndex].containerCache.over = 1;
3787 } else if(this.currentContainer != this.containers[innermostIndex]) {
3789 //When entering a new container, we will find the item with the least distance and append our item near it
3790 var dist = 10000; var itemWithLeastDistance = null; var base = this.positionAbs[this.containers[innermostIndex].floating ? 'left' : 'top'];
3791 for (var j = this.items.length - 1; j >= 0; j--) {
3792 if(!$.ui.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) continue;
3793 var cur = this.items[j][this.containers[innermostIndex].floating ? 'left' : 'top'];
3794 if(Math.abs(cur - base) < dist) {
3795 dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j];
3799 if(!itemWithLeastDistance && !this.options.dropOnEmpty) //Check if dropOnEmpty is enabled
3802 this.currentContainer = this.containers[innermostIndex];
3803 itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
3804 this._trigger("change", event, this._uiHash());
3805 this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
3807 //Update the placeholder
3808 this.options.placeholder.update(this.currentContainer, this.placeholder);
3810 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
3811 this.containers[innermostIndex].containerCache.over = 1;
3817 _createHelper: function(event) {
3819 var o = this.options;
3820 var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper == 'clone' ? this.currentItem.clone() : this.currentItem);
3822 if(!helper.parents('body').length) //Add the helper to the DOM if that didn't happen already
3823 $(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
3825 if(helper[0] == this.currentItem[0])
3826 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") };
3828 if(helper[0].style.width == '' || o.forceHelperSize) helper.width(this.currentItem.width());
3829 if(helper[0].style.height == '' || o.forceHelperSize) helper.height(this.currentItem.height());
3835 _adjustOffsetFromHelper: function(obj) {
3836 if (typeof obj == 'string') {
3837 obj = obj.split(' ');
3839 if ($.isArray(obj)) {
3840 obj = {left: +obj[0], top: +obj[1] || 0};
3842 if ('left' in obj) {
3843 this.offset.click.left = obj.left + this.margins.left;
3845 if ('right' in obj) {
3846 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
3849 this.offset.click.top = obj.top + this.margins.top;
3851 if ('bottom' in obj) {
3852 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
3856 _getParentOffset: function() {
3859 //Get the offsetParent and cache its position
3860 this.offsetParent = this.helper.offsetParent();
3861 var po = this.offsetParent.offset();
3863 // This is a special case where we need to modify a offset calculated on start, since the following happened:
3864 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
3865 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
3866 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
3867 if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) {
3868 po.left += this.scrollParent.scrollLeft();
3869 po.top += this.scrollParent.scrollTop();
3872 if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information
3873 || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix
3874 po = { top: 0, left: 0 };
3877 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
3878 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
3883 _getRelativeOffset: function() {
3885 if(this.cssPosition == "relative") {
3886 var p = this.currentItem.position();
3888 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
3889 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
3892 return { top: 0, left: 0 };
3897 _cacheMargins: function() {
3899 left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
3900 top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
3904 _cacheHelperProportions: function() {
3905 this.helperProportions = {
3906 width: this.helper.outerWidth(),
3907 height: this.helper.outerHeight()
3911 _setContainment: function() {
3913 var o = this.options;
3914 if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
3915 if(o.containment == 'document' || o.containment == 'window') this.containment = [
3916 0 - this.offset.relative.left - this.offset.parent.left,
3917 0 - this.offset.relative.top - this.offset.parent.top,
3918 $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left,
3919 ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
3922 if(!(/^(document|window|parent)$/).test(o.containment)) {
3923 var ce = $(o.containment)[0];
3924 var co = $(o.containment).offset();
3925 var over = ($(ce).css("overflow") != 'hidden');
3927 this.containment = [
3928 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
3929 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
3930 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,
3931 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
3937 _convertPositionTo: function(d, pos) {
3939 if(!pos) pos = this.position;
3940 var mod = d == "absolute" ? 1 : -1;
3941 var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
3945 pos.top // The absolute mouse position
3946 + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent
3947 + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border)
3948 - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
3951 pos.left // The absolute mouse position
3952 + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent
3953 + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border)
3954 - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
3960 _generatePosition: function(event) {
3962 var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
3964 // This is another very weird special case that only happens for relative elements:
3965 // 1. If the css position is relative
3966 // 2. and the scroll parent is the document or similar to the offset parent
3967 // we have to refresh the relative offset during the scroll so there are no jumps
3968 if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) {
3969 this.offset.relative = this._getRelativeOffset();
3972 var pageX = event.pageX;
3973 var pageY = event.pageY;
3976 * - Position constraining -
3977 * Constrain the position to a mix of grid, containment.
3980 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
3982 if(this.containment) {
3983 if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left;
3984 if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top;
3985 if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left;
3986 if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top;
3990 var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
3991 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;
3993 var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
3994 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;
4001 pageY // The absolute mouse position
4002 - this.offset.click.top // Click offset (relative to the element)
4003 - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent
4004 - this.offset.parent.top // The offsetParent's offset without borders (offset + border)
4005 + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
4008 pageX // The absolute mouse position
4009 - this.offset.click.left // Click offset (relative to the element)
4010 - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent
4011 - this.offset.parent.left // The offsetParent's offset without borders (offset + border)
4012 + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
4018 _rearrange: function(event, i, a, hardRefresh) {
4020 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));
4022 //Various things done here to improve the performance:
4023 // 1. we create a setTimeout, that calls refreshPositions
4024 // 2. on the instance, we have a counter variable, that get's higher after every append
4025 // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
4026 // 4. this lets only the last addition to the timeout stack through
4027 this.counter = this.counter ? ++this.counter : 1;
4028 var self = this, counter = this.counter;
4030 window.setTimeout(function() {
4031 if(counter == self.counter) self.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
4036 _clear: function(event, noPropagation) {
4038 this.reverting = false;
4039 // We delay all events that have to be triggered to after the point where the placeholder has been removed and
4040 // everything else normalized again
4041 var delayedTriggers = [], self = this;
4043 // We first have to update the dom position of the actual currentItem
4044 // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
4045 if(!this._noFinalSort && this.currentItem[0].parentNode) this.placeholder.before(this.currentItem);
4046 this._noFinalSort = null;
4048 if(this.helper[0] == this.currentItem[0]) {
4049 for(var i in this._storedCSS) {
4050 if(this._storedCSS[i] == 'auto' || this._storedCSS[i] == 'static') this._storedCSS[i] = '';
4052 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
4054 this.currentItem.show();
4057 if(this.fromOutside && !noPropagation) delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
4058 if((this.fromOutside || this.domPosition.prev != this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent != this.currentItem.parent()[0]) && !noPropagation) delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
4059 if(!$.ui.contains(this.element[0], this.currentItem[0])) { //Node was moved out of the current element
4060 if(!noPropagation) delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
4061 for (var i = this.containers.length - 1; i >= 0; i--){
4062 if($.ui.contains(this.containers[i].element[0], this.currentItem[0]) && !noPropagation) {
4063 delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
4064 delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
4069 //Post events to containers
4070 for (var i = this.containers.length - 1; i >= 0; i--){
4071 if(!noPropagation) delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
4072 if(this.containers[i].containerCache.over) {
4073 delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
4074 this.containers[i].containerCache.over = 0;
4078 //Do what was originally in plugins
4079 if(this._storedCursor) $('body').css("cursor", this._storedCursor); //Reset cursor
4080 if(this._storedOpacity) this.helper.css("opacity", this._storedOpacity); //Reset opacity
4081 if(this._storedZIndex) this.helper.css("zIndex", this._storedZIndex == 'auto' ? '' : this._storedZIndex); //Reset z-index
4083 this.dragging = false;
4084 if(this.cancelHelperRemoval) {
4085 if(!noPropagation) {
4086 this._trigger("beforeStop", event, this._uiHash());
4087 for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events
4088 this._trigger("stop", event, this._uiHash());
4093 if(!noPropagation) this._trigger("beforeStop", event, this._uiHash());
4095 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
4096 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
4098 if(this.helper[0] != this.currentItem[0]) this.helper.remove(); this.helper = null;
4100 if(!noPropagation) {
4101 for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events
4102 this._trigger("stop", event, this._uiHash());
4105 this.fromOutside = false;
4110 _trigger: function() {
4111 if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
4116 _uiHash: function(inst) {
4117 var self = inst || this;
4119 helper: self.helper,
4120 placeholder: self.placeholder || $([]),
4121 position: self.position,
4122 originalPosition: self.originalPosition,
4123 offset: self.positionAbs,
4124 item: self.currentItem,
4125 sender: inst ? inst.element : null
4131 $.extend($.ui.sortable, {
4137 * jQuery UI Accordion 1.8.4
4139 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
4140 * Dual licensed under the MIT or GPL Version 2 licenses.
4141 * http://jquery.org/license
4143 * http://docs.jquery.com/UI/Accordion
4147 * jquery.ui.widget.js
4149 (function( $, undefined ) {
4151 $.widget( "ui.accordion", {
4160 header: "> li > :first-child,> :not(li):even",
4162 header: "ui-icon-triangle-1-e",
4163 headerSelected: "ui-icon-triangle-1-s"
4166 navigationFilter: function() {
4167 return this.href.toLowerCase() === location.href.toLowerCase();
4171 _create: function() {
4173 options = self.options;
4178 .addClass( "ui-accordion ui-widget ui-helper-reset" )
4179 // in lack of child-selectors in CSS
4180 // we need to mark top-LIs in a UL-accordion for some IE-fix
4182 .addClass( "ui-accordion-li-fix" );
4184 self.headers = self.element.find( options.header )
4185 .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" )
4186 .bind( "mouseenter.accordion", function() {
4187 if ( options.disabled ) {
4190 $( this ).addClass( "ui-state-hover" );
4192 .bind( "mouseleave.accordion", function() {
4193 if ( options.disabled ) {
4196 $( this ).removeClass( "ui-state-hover" );
4198 .bind( "focus.accordion", function() {
4199 if ( options.disabled ) {
4202 $( this ).addClass( "ui-state-focus" );
4204 .bind( "blur.accordion", function() {
4205 if ( options.disabled ) {
4208 $( this ).removeClass( "ui-state-focus" );
4212 .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" );
4214 if ( options.navigation ) {
4215 var current = self.element.find( "a" ).filter( options.navigationFilter ).eq( 0 );
4216 if ( current.length ) {
4217 var header = current.closest( ".ui-accordion-header" );
4218 if ( header.length ) {
4219 // anchor within header
4220 self.active = header;
4222 // anchor within content
4223 self.active = current.closest( ".ui-accordion-content" ).prev();
4228 self.active = self._findActive( self.active || options.active )
4229 .addClass( "ui-state-default ui-state-active" )
4230 .toggleClass( "ui-corner-all ui-corner-top" );
4231 self.active.next().addClass( "ui-accordion-content-active" );
4233 self._createIcons();
4237 self.element.attr( "role", "tablist" );
4240 .attr( "role", "tab" )
4241 .bind( "keydown.accordion", function( event ) {
4242 return self._keydown( event );
4245 .attr( "role", "tabpanel" );
4248 .not( self.active || "" )
4250 "aria-expanded": "false",
4256 // make sure at least one header is in the tab order
4257 if ( !self.active.length ) {
4258 self.headers.eq( 0 ).attr( "tabIndex", 0 );
4262 "aria-expanded": "true",
4267 // only need links in tab order for Safari
4268 if ( !$.browser.safari ) {
4269 self.headers.find( "a" ).attr( "tabIndex", -1 );
4272 if ( options.event ) {
4273 self.headers.bind( options.event.split(" ").join(".accordion ") + ".accordion", function(event) {
4274 self._clickHandler.call( self, event, this );
4275 event.preventDefault();
4280 _createIcons: function() {
4281 var options = this.options;
4282 if ( options.icons ) {
4283 $( "<span></span>" )
4284 .addClass( "ui-icon " + options.icons.header )
4285 .prependTo( this.headers );
4286 this.active.children( ".ui-icon" )
4287 .toggleClass(options.icons.header)
4288 .toggleClass(options.icons.headerSelected);
4289 this.element.addClass( "ui-accordion-icons" );
4293 _destroyIcons: function() {
4294 this.headers.children( ".ui-icon" ).remove();
4295 this.element.removeClass( "ui-accordion-icons" );
4298 destroy: function() {
4299 var options = this.options;
4302 .removeClass( "ui-accordion ui-widget ui-helper-reset" )
4303 .removeAttr( "role" );
4306 .unbind( ".accordion" )
4307 .removeClass( "ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" )
4308 .removeAttr( "role" )
4309 .removeAttr( "aria-expanded" )
4310 .removeAttr( "tabIndex" );
4312 this.headers.find( "a" ).removeAttr( "tabIndex" );
4313 this._destroyIcons();
4314 var contents = this.headers.next()
4315 .css( "display", "" )
4316 .removeAttr( "role" )
4317 .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled" );
4318 if ( options.autoHeight || options.fillHeight ) {
4319 contents.css( "height", "" );
4322 return $.Widget.prototype.destroy.call( this );
4325 _setOption: function( key, value ) {
4326 $.Widget.prototype._setOption.apply( this, arguments );
4328 if ( key == "active" ) {
4329 this.activate( value );
4331 if ( key == "icons" ) {
4332 this._destroyIcons();
4334 this._createIcons();
4337 // #5332 - opacity doesn't cascade to positioned elements in IE
4338 // so we need to add the disabled class to the headers and panels
4339 if ( key == "disabled" ) {
4340 this.headers.add(this.headers.next())
4341 [ value ? "addClass" : "removeClass" ](
4342 "ui-accordion-disabled ui-state-disabled" );
4346 _keydown: function( event ) {
4347 if ( this.options.disabled || event.altKey || event.ctrlKey ) {
4351 var keyCode = $.ui.keyCode,
4352 length = this.headers.length,
4353 currentIndex = this.headers.index( event.target ),
4356 switch ( event.keyCode ) {
4359 toFocus = this.headers[ ( currentIndex + 1 ) % length ];
4363 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
4367 this._clickHandler( { target: event.target }, event.target );
4368 event.preventDefault();
4372 $( event.target ).attr( "tabIndex", -1 );
4373 $( toFocus ).attr( "tabIndex", 0 );
4381 resize: function() {
4382 var options = this.options,
4385 if ( options.fillSpace ) {
4386 if ( $.browser.msie ) {
4387 var defOverflow = this.element.parent().css( "overflow" );
4388 this.element.parent().css( "overflow", "hidden");
4390 maxHeight = this.element.parent().height();
4391 if ($.browser.msie) {
4392 this.element.parent().css( "overflow", defOverflow );
4395 this.headers.each(function() {
4396 maxHeight -= $( this ).outerHeight( true );
4401 $( this ).height( Math.max( 0, maxHeight -
4402 $( this ).innerHeight() + $( this ).height() ) );
4404 .css( "overflow", "auto" );
4405 } else if ( options.autoHeight ) {
4409 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
4411 .height( maxHeight );
4417 activate: function( index ) {
4418 // TODO this gets called on init, changing the option without an explicit call for that
4419 this.options.active = index;
4420 // call clickHandler with custom event
4421 var active = this._findActive( index )[ 0 ];
4422 this._clickHandler( { target: active }, active );
4427 _findActive: function( selector ) {
4429 ? typeof selector === "number"
4430 ? this.headers.filter( ":eq(" + selector + ")" )
4431 : this.headers.not( this.headers.not( selector ) )
4432 : selector === false
4434 : this.headers.filter( ":eq(0)" );
4437 // TODO isn't event.target enough? why the separate target argument?
4438 _clickHandler: function( event, target ) {
4439 var options = this.options;
4440 if ( options.disabled ) {
4444 // called only when using activate(false) to close all parts programmatically
4445 if ( !event.target ) {
4446 if ( !options.collapsible ) {
4450 .removeClass( "ui-state-active ui-corner-top" )
4451 .addClass( "ui-state-default ui-corner-all" )
4452 .children( ".ui-icon" )
4453 .removeClass( options.icons.headerSelected )
4454 .addClass( options.icons.header );
4455 this.active.next().addClass( "ui-accordion-content-active" );
4456 var toHide = this.active.next(),
4460 oldHeader: options.active,
4461 newContent: $( [] ),
4464 toShow = ( this.active = $( [] ) );
4465 this._toggle( toShow, toHide, data );
4469 // get the click target
4470 var clicked = $( event.currentTarget || target ),
4471 clickedIsActive = clicked[0] === this.active[0];
4473 // TODO the option is changed, is that correct?
4474 // TODO if it is correct, shouldn't that happen after determining that the click is valid?
4475 options.active = options.collapsible && clickedIsActive ?
4477 this.headers.index( clicked );
4479 // if animations are still active, or the active header is the target, ignore click
4480 if ( this.running || ( !options.collapsible && clickedIsActive ) ) {
4486 .removeClass( "ui-state-active ui-corner-top" )
4487 .addClass( "ui-state-default ui-corner-all" )
4488 .children( ".ui-icon" )
4489 .removeClass( options.icons.headerSelected )
4490 .addClass( options.icons.header );
4491 if ( !clickedIsActive ) {
4493 .removeClass( "ui-state-default ui-corner-all" )
4494 .addClass( "ui-state-active ui-corner-top" )
4495 .children( ".ui-icon" )
4496 .removeClass( options.icons.header )
4497 .addClass( options.icons.headerSelected );
4500 .addClass( "ui-accordion-content-active" );
4503 // find elements to show and hide
4504 var toShow = clicked.next(),
4505 toHide = this.active.next(),
4508 newHeader: clickedIsActive && options.collapsible ? $([]) : clicked,
4509 oldHeader: this.active,
4510 newContent: clickedIsActive && options.collapsible ? $([]) : toShow,
4513 down = this.headers.index( this.active[0] ) > this.headers.index( clicked[0] );
4515 this.active = clickedIsActive ? $([]) : clicked;
4516 this._toggle( toShow, toHide, data, clickedIsActive, down );
4521 _toggle: function( toShow, toHide, data, clickedIsActive, down ) {
4523 options = self.options;
4525 self.toShow = toShow;
4526 self.toHide = toHide;
4529 var complete = function() {
4533 return self._completed.apply( self, arguments );
4536 // trigger changestart event
4537 self._trigger( "changestart", null, self.data );
4539 // count elements to animate
4540 self.running = toHide.size() === 0 ? toShow.size() : toHide.size();
4542 if ( options.animated ) {
4543 var animOptions = {};
4545 if ( options.collapsible && clickedIsActive ) {
4551 autoHeight: options.autoHeight || options.fillSpace
4559 autoHeight: options.autoHeight || options.fillSpace
4563 if ( !options.proxied ) {
4564 options.proxied = options.animated;
4567 if ( !options.proxiedDuration ) {
4568 options.proxiedDuration = options.duration;
4571 options.animated = $.isFunction( options.proxied ) ?
4572 options.proxied( animOptions ) :
4575 options.duration = $.isFunction( options.proxiedDuration ) ?
4576 options.proxiedDuration( animOptions ) :
4577 options.proxiedDuration;
4579 var animations = $.ui.accordion.animations,
4580 duration = options.duration,
4581 easing = options.animated;
4583 if ( easing && !animations[ easing ] && !$.easing[ easing ] ) {
4586 if ( !animations[ easing ] ) {
4587 animations[ easing ] = function( options ) {
4588 this.slide( options, {
4590 duration: duration || 700
4595 animations[ easing ]( animOptions );
4597 if ( options.collapsible && clickedIsActive ) {
4607 // TODO assert that the blur and focus triggers are really necessary, remove otherwise
4610 "aria-expanded": "false",
4616 "aria-expanded": "true",
4622 _completed: function( cancel ) {
4623 this.running = cancel ? 0 : --this.running;
4624 if ( this.running ) {
4628 if ( this.options.clearStyle ) {
4629 this.toShow.add( this.toHide ).css({
4635 // other classes are removed before the animation; this one needs to stay until completed
4636 this.toHide.removeClass( "ui-accordion-content-active" );
4638 this._trigger( "change", null, this.data );
4642 $.extend( $.ui.accordion, {
4645 slide: function( options, additions ) {
4646 options = $.extend({
4649 }, options, additions );
4650 if ( !options.toHide.size() ) {
4651 options.toShow.animate({
4654 paddingBottom: "show"
4658 if ( !options.toShow.size() ) {
4659 options.toHide.animate({
4662 paddingBottom: "hide"
4666 var overflow = options.toShow.css( "overflow" ),
4670 fxAttrs = [ "height", "paddingTop", "paddingBottom" ],
4672 // fix width before calculating height of hidden element
4673 var s = options.toShow;
4674 originalWidth = s[0].style.width;
4675 s.width( parseInt( s.parent().width(), 10 )
4676 - parseInt( s.css( "paddingLeft" ), 10 )
4677 - parseInt( s.css( "paddingRight" ), 10 )
4678 - ( parseInt( s.css( "borderLeftWidth" ), 10 ) || 0 )
4679 - ( parseInt( s.css( "borderRightWidth" ), 10) || 0 ) );
4681 $.each( fxAttrs, function( i, prop ) {
4682 hideProps[ prop ] = "hide";
4684 var parts = ( "" + $.css( options.toShow[0], prop ) ).match( /^([\d+-.]+)(.*)$/ );
4685 showProps[ prop ] = {
4687 unit: parts[ 2 ] || "px"
4690 options.toShow.css({ height: 0, overflow: "hidden" }).show();
4692 .filter( ":hidden" )
4693 .each( options.complete )
4695 .filter( ":visible" )
4696 .animate( hideProps, {
4697 step: function( now, settings ) {
4698 // only calculate the percent when animating height
4699 // IE gets very inconsistent results when animating elements
4700 // with small values, which is common for padding
4701 if ( settings.prop == "height" ) {
4702 percentDone = ( settings.end - settings.start === 0 ) ? 0 :
4703 ( settings.now - settings.start ) / ( settings.end - settings.start );
4706 options.toShow[ 0 ].style[ settings.prop ] =
4707 ( percentDone * showProps[ settings.prop ].value )
4708 + showProps[ settings.prop ].unit;
4710 duration: options.duration,
4711 easing: options.easing,
4712 complete: function() {
4713 if ( !options.autoHeight ) {
4714 options.toShow.css( "height", "" );
4716 options.toShow.css({
4717 width: originalWidth,
4724 bounceslide: function( options ) {
4725 this.slide( options, {
4726 easing: options.down ? "easeOutBounce" : "swing",
4727 duration: options.down ? 1000 : 200
4735 * jQuery UI Autocomplete 1.8.4
4737 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
4738 * Dual licensed under the MIT or GPL Version 2 licenses.
4739 * http://jquery.org/license
4741 * http://docs.jquery.com/UI/Autocomplete
4745 * jquery.ui.widget.js
4746 * jquery.ui.position.js
4748 (function( $, undefined ) {
4750 $.widget( "ui.autocomplete", {
4762 _create: function() {
4764 doc = this.element[ 0 ].ownerDocument;
4766 .addClass( "ui-autocomplete-input" )
4767 .attr( "autocomplete", "off" )
4768 // TODO verify these actually work as intended
4771 "aria-autocomplete": "list",
4772 "aria-haspopup": "true"
4774 .bind( "keydown.autocomplete", function( event ) {
4775 if ( self.options.disabled ) {
4779 var keyCode = $.ui.keyCode;
4780 switch( event.keyCode ) {
4781 case keyCode.PAGE_UP:
4782 self._move( "previousPage", event );
4784 case keyCode.PAGE_DOWN:
4785 self._move( "nextPage", event );
4788 self._move( "previous", event );
4789 // prevent moving cursor to beginning of text field in some browsers
4790 event.preventDefault();
4793 self._move( "next", event );
4794 // prevent moving cursor to end of text field in some browsers
4795 event.preventDefault();
4798 case keyCode.NUMPAD_ENTER:
4799 // when menu is open or has focus
4800 if ( self.menu.element.is( ":visible" ) ) {
4801 event.preventDefault();
4803 //passthrough - ENTER and TAB both select the current element
4805 if ( !self.menu.active ) {
4808 self.menu.select( event );
4810 case keyCode.ESCAPE:
4811 self.element.val( self.term );
4812 self.close( event );
4815 // keypress is triggered before the input value is changed
4816 clearTimeout( self.searching );
4817 self.searching = setTimeout(function() {
4818 // only search if the value has changed
4819 if ( self.term != self.element.val() ) {
4820 self.selectedItem = null;
4821 self.search( null, event );
4823 }, self.options.delay );
4827 .bind( "focus.autocomplete", function() {
4828 if ( self.options.disabled ) {
4832 self.selectedItem = null;
4833 self.previous = self.element.val();
4835 .bind( "blur.autocomplete", function( event ) {
4836 if ( self.options.disabled ) {
4840 clearTimeout( self.searching );
4841 // clicks on the menu (or a button to trigger a search) will cause a blur event
4842 self.closing = setTimeout(function() {
4843 self.close( event );
4844 self._change( event );
4848 this.response = function() {
4849 return self._response.apply( self, arguments );
4851 this.menu = $( "<ul></ul>" )
4852 .addClass( "ui-autocomplete" )
4853 .appendTo( $( this.options.appendTo || "body", doc )[0] )
4854 // prevent the close-on-blur in case of a "slow" click on the menu (long mousedown)
4855 .mousedown(function( event ) {
4856 // clicking on the scrollbar causes focus to shift to the body
4857 // but we can't detect a mouseup or a click immediately afterward
4858 // so we have to track the next mousedown and close the menu if
4859 // the user clicks somewhere outside of the autocomplete
4860 var menuElement = self.menu.element[ 0 ];
4861 if ( event.target === menuElement ) {
4862 setTimeout(function() {
4863 $( document ).one( 'mousedown', function( event ) {
4864 if ( event.target !== self.element[ 0 ] &&
4865 event.target !== menuElement &&
4866 !$.ui.contains( menuElement, event.target ) ) {
4873 // use another timeout to make sure the blur-event-handler on the input was already triggered
4874 setTimeout(function() {
4875 clearTimeout( self.closing );
4879 focus: function( event, ui ) {
4880 var item = ui.item.data( "item.autocomplete" );
4881 if ( false !== self._trigger( "focus", null, { item: item } ) ) {
4882 // use value to match what will end up in the input, if it was a key event
4883 if ( /^key/.test(event.originalEvent.type) ) {
4884 self.element.val( item.value );
4888 selected: function( event, ui ) {
4889 var item = ui.item.data( "item.autocomplete" ),
4890 previous = self.previous;
4892 // only trigger when focus was lost (click on menu)
4893 if ( self.element[0] !== doc.activeElement ) {
4894 self.element.focus();
4895 self.previous = previous;
4898 if ( false !== self._trigger( "select", event, { item: item } ) ) {
4899 self.element.val( item.value );
4902 self.close( event );
4903 self.selectedItem = item;
4905 blur: function( event, ui ) {
4906 // don't set the value of the text field if it's already correct
4907 // this prevents moving the cursor unnecessarily
4908 if ( self.menu.element.is(":visible") &&
4909 ( self.element.val() !== self.term ) ) {
4910 self.element.val( self.term );
4914 .zIndex( this.element.zIndex() + 1 )
4915 // workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781
4916 .css({ top: 0, left: 0 })
4919 if ( $.fn.bgiframe ) {
4920 this.menu.element.bgiframe();
4924 destroy: function() {
4926 .removeClass( "ui-autocomplete-input" )
4927 .removeAttr( "autocomplete" )
4928 .removeAttr( "role" )
4929 .removeAttr( "aria-autocomplete" )
4930 .removeAttr( "aria-haspopup" );
4931 this.menu.element.remove();
4932 $.Widget.prototype.destroy.call( this );
4935 _setOption: function( key, value ) {
4936 $.Widget.prototype._setOption.apply( this, arguments );
4937 if ( key === "source" ) {
4940 if ( key === "appendTo" ) {
4941 this.menu.element.appendTo( $( value || "body", this.element[0].ownerDocument )[0] )
4945 _initSource: function() {
4948 if ( $.isArray(this.options.source) ) {
4949 array = this.options.source;
4950 this.source = function( request, response ) {
4951 response( $.ui.autocomplete.filter(array, request.term) );
4953 } else if ( typeof this.options.source === "string" ) {
4954 url = this.options.source;
4955 this.source = function( request, response ) {
4956 $.getJSON( url, request, response );
4959 this.source = this.options.source;
4963 search: function( value, event ) {
4964 value = value != null ? value : this.element.val();
4965 if ( value.length < this.options.minLength ) {
4966 return this.close( event );
4969 clearTimeout( this.closing );
4970 if ( this._trigger("search") === false ) {
4974 return this._search( value );
4977 _search: function( value ) {
4978 this.term = this.element
4979 .addClass( "ui-autocomplete-loading" )
4980 // always save the actual value, not the one passed as an argument
4983 this.source( { term: value }, this.response );
4986 _response: function( content ) {
4987 if ( content.length ) {
4988 content = this._normalize( content );
4989 this._suggest( content );
4990 this._trigger( "open" );
4994 this.element.removeClass( "ui-autocomplete-loading" );
4997 close: function( event ) {
4998 clearTimeout( this.closing );
4999 if ( this.menu.element.is(":visible") ) {
5000 this._trigger( "close", event );
5001 this.menu.element.hide();
5002 this.menu.deactivate();
5006 _change: function( event ) {
5007 if ( this.previous !== this.element.val() ) {
5008 this._trigger( "change", event, { item: this.selectedItem } );
5012 _normalize: function( items ) {
5013 // assume all items have the right format when the first item is complete
5014 if ( items.length && items[0].label && items[0].value ) {
5017 return $.map( items, function(item) {
5018 if ( typeof item === "string" ) {
5025 label: item.label || item.value,
5026 value: item.value || item.label
5031 _suggest: function( items ) {
5032 var ul = this.menu.element
5034 .zIndex( this.element.zIndex() + 1 ),
5037 this._renderMenu( ul, items );
5038 // TODO refresh should check if the active item is still in the dom, removing the need for a manual deactivate
5039 this.menu.deactivate();
5040 this.menu.refresh();
5041 this.menu.element.show().position( $.extend({
5043 }, this.options.position ));
5045 menuWidth = ul.width( "" ).outerWidth();
5046 textWidth = this.element.outerWidth();
5047 ul.outerWidth( Math.max( menuWidth, textWidth ) );
5050 _renderMenu: function( ul, items ) {
5052 $.each( items, function( index, item ) {
5053 self._renderItem( ul, item );
5057 _renderItem: function( ul, item) {
5058 return $( "<li></li>" )
5059 .data( "item.autocomplete", item )
5060 .append( $( "<a></a>" ).text( item.label ) )
5064 _move: function( direction, event ) {
5065 if ( !this.menu.element.is(":visible") ) {
5066 this.search( null, event );
5069 if ( this.menu.first() && /^previous/.test(direction) ||
5070 this.menu.last() && /^next/.test(direction) ) {
5071 this.element.val( this.term );
5072 this.menu.deactivate();
5075 this.menu[ direction ]( event );
5078 widget: function() {
5079 return this.menu.element;
5083 $.extend( $.ui.autocomplete, {
5084 escapeRegex: function( value ) {
5085 return value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
5087 filter: function(array, term) {
5088 var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
5089 return $.grep( array, function(value) {
5090 return matcher.test( value.label || value.value || value );
5098 * jQuery UI Menu (not officially released)
5100 * This widget isn't yet finished and the API is subject to change. We plan to finish
5101 * it for the next release. You're welcome to give it a try anyway and give us feedback,
5102 * as long as you're okay with migrating your code later on. We can help with that, too.
5104 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
5105 * Dual licensed under the MIT or GPL Version 2 licenses.
5106 * http://jquery.org/license
5108 * http://docs.jquery.com/UI/Menu
5112 * jquery.ui.widget.js
5116 $.widget("ui.menu", {
5117 _create: function() {
5120 .addClass("ui-menu ui-widget ui-widget-content ui-corner-all")
5123 "aria-activedescendant": "ui-active-menuitem"
5125 .click(function( event ) {
5126 if ( !$( event.target ).closest( ".ui-menu-item a" ).length ) {
5130 event.preventDefault();
5131 self.select( event );
5136 refresh: function() {
5139 // don't refresh list items that are already adapted
5140 var items = this.element.children("li:not(.ui-menu-item):has(a)")
5141 .addClass("ui-menu-item")
5142 .attr("role", "menuitem");
5145 .addClass("ui-corner-all")
5146 .attr("tabindex", -1)
5147 // mouseenter doesn't work with event delegation
5148 .mouseenter(function( event ) {
5149 self.activate( event, $(this).parent() );
5151 .mouseleave(function() {
5156 activate: function( event, item ) {
5158 if (this.hasScroll()) {
5159 var offset = item.offset().top - this.element.offset().top,
5160 scroll = this.element.attr("scrollTop"),
5161 elementHeight = this.element.height();
5163 this.element.attr("scrollTop", scroll + offset);
5164 } else if (offset > elementHeight) {
5165 this.element.attr("scrollTop", scroll + offset - elementHeight + item.height());
5168 this.active = item.eq(0)
5170 .addClass("ui-state-hover")
5171 .attr("id", "ui-active-menuitem")
5173 this._trigger("focus", event, { item: item });
5176 deactivate: function() {
5177 if (!this.active) { return; }
5179 this.active.children("a")
5180 .removeClass("ui-state-hover")
5182 this._trigger("blur");
5186 next: function(event) {
5187 this.move("next", ".ui-menu-item:first", event);
5190 previous: function(event) {
5191 this.move("prev", ".ui-menu-item:last", event);
5195 return this.active && !this.active.prevAll(".ui-menu-item").length;
5199 return this.active && !this.active.nextAll(".ui-menu-item").length;
5202 move: function(direction, edge, event) {
5204 this.activate(event, this.element.children(edge));
5207 var next = this.active[direction + "All"](".ui-menu-item").eq(0);
5209 this.activate(event, next);
5211 this.activate(event, this.element.children(edge));
5215 // TODO merge with previousPage
5216 nextPage: function(event) {
5217 if (this.hasScroll()) {
5218 // TODO merge with no-scroll-else
5219 if (!this.active || this.last()) {
5220 this.activate(event, this.element.children(":first"));
5223 var base = this.active.offset().top,
5224 height = this.element.height(),
5225 result = this.element.children("li").filter(function() {
5226 var close = $(this).offset().top - base - height + $(this).height();
5227 // TODO improve approximation
5228 return close < 10 && close > -10;
5231 // TODO try to catch this earlier when scrollTop indicates the last page anyway
5232 if (!result.length) {
5233 result = this.element.children(":last");
5235 this.activate(event, result);
5237 this.activate(event, this.element.children(!this.active || this.last() ? ":first" : ":last"));
5241 // TODO merge with nextPage
5242 previousPage: function(event) {
5243 if (this.hasScroll()) {
5244 // TODO merge with no-scroll-else
5245 if (!this.active || this.first()) {
5246 this.activate(event, this.element.children(":last"));
5250 var base = this.active.offset().top,
5251 height = this.element.height();
5252 result = this.element.children("li").filter(function() {
5253 var close = $(this).offset().top - base + height - $(this).height();
5254 // TODO improve approximation
5255 return close < 10 && close > -10;
5258 // TODO try to catch this earlier when scrollTop indicates the last page anyway
5259 if (!result.length) {
5260 result = this.element.children(":first");
5262 this.activate(event, result);
5264 this.activate(event, this.element.children(!this.active || this.first() ? ":last" : ":first"));
5268 hasScroll: function() {
5269 return this.element.height() < this.element.attr("scrollHeight");
5272 select: function( event ) {
5273 this._trigger("selected", event, { item: this.active });
5279 * jQuery UI Button 1.8.4
5281 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
5282 * Dual licensed under the MIT or GPL Version 2 licenses.
5283 * http://jquery.org/license
5285 * http://docs.jquery.com/UI/Button
5289 * jquery.ui.widget.js
5291 (function( $, undefined ) {
5294 baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
5295 stateClasses = "ui-state-hover ui-state-active ",
5296 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",
5297 formResetHandler = function( event ) {
5298 $( ":ui-button", event.target.form ).each(function() {
5299 var inst = $( this ).data( "button" );
5300 setTimeout(function() {
5305 radioGroup = function( radio ) {
5306 var name = radio.name,
5311 radios = $( form ).find( "[name='" + name + "']" );
5313 radios = $( "[name='" + name + "']", radio.ownerDocument )
5314 .filter(function() {
5322 $.widget( "ui.button", {
5331 _create: function() {
5332 this.element.closest( "form" )
5333 .unbind( "reset.button" )
5334 .bind( "reset.button", formResetHandler );
5336 this._determineButtonType();
5337 this.hasTitle = !!this.buttonElement.attr( "title" );
5340 options = this.options,
5341 toggleButton = this.type === "checkbox" || this.type === "radio",
5342 hoverClass = "ui-state-hover" + ( !toggleButton ? " ui-state-active" : "" ),
5343 focusClass = "ui-state-focus";
5345 if ( options.label === null ) {
5346 options.label = this.buttonElement.html();
5349 if ( this.element.is( ":disabled" ) ) {
5350 options.disabled = true;
5354 .addClass( baseClasses )
5355 .attr( "role", "button" )
5356 .bind( "mouseenter.button", function() {
5357 if ( options.disabled ) {
5360 $( this ).addClass( "ui-state-hover" );
5361 if ( this === lastActive ) {
5362 $( this ).addClass( "ui-state-active" );
5365 .bind( "mouseleave.button", function() {
5366 if ( options.disabled ) {
5369 $( this ).removeClass( hoverClass );
5371 .bind( "focus.button", function() {
5372 // no need to check disabled, focus won't be triggered anyway
5373 $( this ).addClass( focusClass );
5375 .bind( "blur.button", function() {
5376 $( this ).removeClass( focusClass );
5379 if ( toggleButton ) {
5380 this.element.bind( "change.button", function() {
5385 if ( this.type === "checkbox" ) {
5386 this.buttonElement.bind( "click.button", function() {
5387 if ( options.disabled ) {
5390 $( this ).toggleClass( "ui-state-active" );
5391 self.buttonElement.attr( "aria-pressed", self.element[0].checked );
5393 } else if ( this.type === "radio" ) {
5394 this.buttonElement.bind( "click.button", function() {
5395 if ( options.disabled ) {
5398 $( this ).addClass( "ui-state-active" );
5399 self.buttonElement.attr( "aria-pressed", true );
5401 var radio = self.element[ 0 ];
5405 return $( this ).button( "widget" )[ 0 ];
5407 .removeClass( "ui-state-active" )
5408 .attr( "aria-pressed", false );
5412 .bind( "mousedown.button", function() {
5413 if ( options.disabled ) {
5416 $( this ).addClass( "ui-state-active" );
5418 $( document ).one( "mouseup", function() {
5422 .bind( "mouseup.button", function() {
5423 if ( options.disabled ) {
5426 $( this ).removeClass( "ui-state-active" );
5428 .bind( "keydown.button", function(event) {
5429 if ( options.disabled ) {
5432 if ( event.keyCode == $.ui.keyCode.SPACE || event.keyCode == $.ui.keyCode.ENTER ) {
5433 $( this ).addClass( "ui-state-active" );
5436 .bind( "keyup.button", function() {
5437 $( this ).removeClass( "ui-state-active" );
5440 if ( this.buttonElement.is("a") ) {
5441 this.buttonElement.keyup(function(event) {
5442 if ( event.keyCode === $.ui.keyCode.SPACE ) {
5443 // TODO pass through original event correctly (just as 2nd argument doesn't work)
5450 // TODO: pull out $.Widget's handling for the disabled option into
5451 // $.Widget.prototype._setOptionDisabled so it's easy to proxy and can
5452 // be overridden by individual plugins
5453 this._setOption( "disabled", options.disabled );
5456 _determineButtonType: function() {
5458 if ( this.element.is(":checkbox") ) {
5459 this.type = "checkbox";
5461 if ( this.element.is(":radio") ) {
5462 this.type = "radio";
5464 if ( this.element.is("input") ) {
5465 this.type = "input";
5467 this.type = "button";
5472 if ( this.type === "checkbox" || this.type === "radio" ) {
5473 // we don't search against the document in case the element
5474 // is disconnected from the DOM
5475 this.buttonElement = this.element.parents().last()
5476 .find( "label[for=" + this.element.attr("id") + "]" );
5477 this.element.addClass( "ui-helper-hidden-accessible" );
5479 var checked = this.element.is( ":checked" );
5481 this.buttonElement.addClass( "ui-state-active" );
5483 this.buttonElement.attr( "aria-pressed", checked );
5485 this.buttonElement = this.element;
5489 widget: function() {
5490 return this.buttonElement;
5493 destroy: function() {
5495 .removeClass( "ui-helper-hidden-accessible" );
5497 .removeClass( baseClasses + " " + stateClasses + " " + typeClasses )
5498 .removeAttr( "role" )
5499 .removeAttr( "aria-pressed" )
5500 .html( this.buttonElement.find(".ui-button-text").html() );
5502 if ( !this.hasTitle ) {
5503 this.buttonElement.removeAttr( "title" );
5506 $.Widget.prototype.destroy.call( this );
5509 _setOption: function( key, value ) {
5510 $.Widget.prototype._setOption.apply( this, arguments );
5511 if ( key === "disabled" ) {
5513 this.element.attr( "disabled", true );
5515 this.element.removeAttr( "disabled" );
5518 this._resetButton();
5521 refresh: function() {
5522 var isDisabled = this.element.is( ":disabled" );
5523 if ( isDisabled !== this.options.disabled ) {
5524 this._setOption( "disabled", isDisabled );
5526 if ( this.type === "radio" ) {
5527 radioGroup( this.element[0] ).each(function() {
5528 if ( $( this ).is( ":checked" ) ) {
5529 $( this ).button( "widget" )
5530 .addClass( "ui-state-active" )
5531 .attr( "aria-pressed", true );
5533 $( this ).button( "widget" )
5534 .removeClass( "ui-state-active" )
5535 .attr( "aria-pressed", false );
5538 } else if ( this.type === "checkbox" ) {
5539 if ( this.element.is( ":checked" ) ) {
5541 .addClass( "ui-state-active" )
5542 .attr( "aria-pressed", true );
5545 .removeClass( "ui-state-active" )
5546 .attr( "aria-pressed", false );
5551 _resetButton: function() {
5552 if ( this.type === "input" ) {
5553 if ( this.options.label ) {
5554 this.element.val( this.options.label );
5558 var buttonElement = this.buttonElement.removeClass( typeClasses ),
5559 buttonText = $( "<span></span>" )
5560 .addClass( "ui-button-text" )
5561 .html( this.options.label )
5562 .appendTo( buttonElement.empty() )
5564 icons = this.options.icons,
5565 multipleIcons = icons.primary && icons.secondary;
5566 if ( icons.primary || icons.secondary ) {
5567 buttonElement.addClass( "ui-button-text-icon" +
5568 ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
5569 if ( icons.primary ) {
5570 buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
5572 if ( icons.secondary ) {
5573 buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
5575 if ( !this.options.text ) {
5577 .addClass( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" )
5578 .removeClass( "ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary" );
5579 if ( !this.hasTitle ) {
5580 buttonElement.attr( "title", buttonText );
5584 buttonElement.addClass( "ui-button-text-only" );
5589 $.widget( "ui.buttonset", {
5590 _create: function() {
5591 this.element.addClass( "ui-buttonset" );
5599 _setOption: function( key, value ) {
5600 if ( key === "disabled" ) {
5601 this.buttons.button( "option", key, value );
5604 $.Widget.prototype._setOption.apply( this, arguments );
5607 refresh: function() {
5608 this.buttons = this.element.find( ":button, :submit, :reset, :checkbox, :radio, a, :data(button)" )
5609 .filter( ":ui-button" )
5610 .button( "refresh" )
5612 .not( ":ui-button" )
5616 return $( this ).button( "widget" )[ 0 ];
5618 .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
5620 .addClass( "ui-corner-left" )
5623 .addClass( "ui-corner-right" )
5628 destroy: function() {
5629 this.element.removeClass( "ui-buttonset" );
5632 return $( this ).button( "widget" )[ 0 ];
5634 .removeClass( "ui-corner-left ui-corner-right" )
5636 .button( "destroy" );
5638 $.Widget.prototype.destroy.call( this );
5644 * jQuery UI Dialog 1.8.4
5646 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
5647 * Dual licensed under the MIT or GPL Version 2 licenses.
5648 * http://jquery.org/license
5650 * http://docs.jquery.com/UI/Dialog
5654 * jquery.ui.widget.js
5655 * jquery.ui.button.js
5656 * jquery.ui.draggable.js
5657 * jquery.ui.mouse.js
5658 * jquery.ui.position.js
5659 * jquery.ui.resizable.js
5661 (function( $, undefined ) {
5663 var uiDialogClasses =
5666 'ui-widget-content ' +
5669 $.widget("ui.dialog", {
5673 closeOnEscape: true,
5689 // ensure that the titlebar is never outside the document
5690 using: function(pos) {
5691 var topOffset = $(this).css(pos).offset().top;
5692 if (topOffset < 0) {
5693 $(this).css('top', pos.top - topOffset);
5705 _create: function() {
5706 this.originalTitle = this.element.attr('title');
5707 // #5742 - .attr() might return a DOMElement
5708 if ( typeof this.originalTitle !== "string" ) {
5709 this.originalTitle = "";
5713 options = self.options,
5715 title = options.title || self.originalTitle || ' ',
5716 titleId = $.ui.dialog.getTitleId(self.element),
5718 uiDialog = (self.uiDialog = $('<div></div>'))
5719 .appendTo(document.body)
5721 .addClass(uiDialogClasses + options.dialogClass)
5723 zIndex: options.zIndex
5725 // setting tabIndex makes the div focusable
5726 // setting outline to 0 prevents a border on focus in Mozilla
5727 .attr('tabIndex', -1).css('outline', 0).keydown(function(event) {
5728 if (options.closeOnEscape && event.keyCode &&
5729 event.keyCode === $.ui.keyCode.ESCAPE) {
5732 event.preventDefault();
5737 'aria-labelledby': titleId
5739 .mousedown(function(event) {
5740 self.moveToTop(false, event);
5743 uiDialogContent = self.element
5745 .removeAttr('title')
5747 'ui-dialog-content ' +
5748 'ui-widget-content')
5749 .appendTo(uiDialog),
5751 uiDialogTitlebar = (self.uiDialogTitlebar = $('<div></div>'))
5753 'ui-dialog-titlebar ' +
5754 'ui-widget-header ' +
5756 'ui-helper-clearfix'
5758 .prependTo(uiDialog),
5760 uiDialogTitlebarClose = $('<a href="#"></a>')
5762 'ui-dialog-titlebar-close ' +
5765 .attr('role', 'button')
5768 uiDialogTitlebarClose.addClass('ui-state-hover');
5771 uiDialogTitlebarClose.removeClass('ui-state-hover');
5775 uiDialogTitlebarClose.addClass('ui-state-focus');
5778 uiDialogTitlebarClose.removeClass('ui-state-focus');
5780 .click(function(event) {
5784 .appendTo(uiDialogTitlebar),
5786 uiDialogTitlebarCloseText = (self.uiDialogTitlebarCloseText = $('<span></span>'))
5789 'ui-icon-closethick'
5791 .text(options.closeText)
5792 .appendTo(uiDialogTitlebarClose),
5794 uiDialogTitle = $('<span></span>')
5795 .addClass('ui-dialog-title')
5796 .attr('id', titleId)
5798 .prependTo(uiDialogTitlebar);
5800 //handling of deprecated beforeclose (vs beforeClose) option
5801 //Ticket #4669 http://dev.jqueryui.com/ticket/4669
5802 //TODO: remove in 1.9pre
5803 if ($.isFunction(options.beforeclose) && !$.isFunction(options.beforeClose)) {
5804 options.beforeClose = options.beforeclose;
5807 uiDialogTitlebar.find("*").add(uiDialogTitlebar).disableSelection();
5809 if (options.draggable && $.fn.draggable) {
5810 self._makeDraggable();
5812 if (options.resizable && $.fn.resizable) {
5813 self._makeResizable();
5816 self._createButtons(options.buttons);
5817 self._isOpen = false;
5819 if ($.fn.bgiframe) {
5820 uiDialog.bgiframe();
5825 if ( this.options.autoOpen ) {
5830 destroy: function() {
5834 self.overlay.destroy();
5836 self.uiDialog.hide();
5839 .removeData('dialog')
5840 .removeClass('ui-dialog-content ui-widget-content')
5841 .hide().appendTo('body');
5842 self.uiDialog.remove();
5844 if (self.originalTitle) {
5845 self.element.attr('title', self.originalTitle);
5851 widget: function() {
5852 return this.uiDialog;
5855 close: function(event) {
5859 if (false === self._trigger('beforeClose', event)) {
5864 self.overlay.destroy();
5866 self.uiDialog.unbind('keypress.ui-dialog');
5868 self._isOpen = false;
5870 if (self.options.hide) {
5871 self.uiDialog.hide(self.options.hide, function() {
5872 self._trigger('close', event);
5875 self.uiDialog.hide();
5876 self._trigger('close', event);
5879 $.ui.dialog.overlay.resize();
5881 // adjust the maxZ to allow other modal dialogs to continue to work (see #4309)
5882 if (self.options.modal) {
5884 $('.ui-dialog').each(function() {
5885 if (this !== self.uiDialog[0]) {
5886 maxZ = Math.max(maxZ, $(this).css('z-index'));
5889 $.ui.dialog.maxZ = maxZ;
5895 isOpen: function() {
5896 return this._isOpen;
5899 // the force parameter allows us to move modal dialogs to their correct
5901 moveToTop: function(force, event) {
5903 options = self.options,
5906 if ((options.modal && !force) ||
5907 (!options.stack && !options.modal)) {
5908 return self._trigger('focus', event);
5911 if (options.zIndex > $.ui.dialog.maxZ) {
5912 $.ui.dialog.maxZ = options.zIndex;
5915 $.ui.dialog.maxZ += 1;
5916 self.overlay.$el.css('z-index', $.ui.dialog.overlay.maxZ = $.ui.dialog.maxZ);
5919 //Save and then restore scroll since Opera 9.5+ resets when parent z-Index is changed.
5920 // http://ui.jquery.com/bugs/ticket/3193
5921 saveScroll = { scrollTop: self.element.attr('scrollTop'), scrollLeft: self.element.attr('scrollLeft') };
5922 $.ui.dialog.maxZ += 1;
5923 self.uiDialog.css('z-index', $.ui.dialog.maxZ);
5924 self.element.attr(saveScroll);
5925 self._trigger('focus', event);
5931 if (this._isOpen) { return; }
5934 options = self.options,
5935 uiDialog = self.uiDialog;
5937 self.overlay = options.modal ? new $.ui.dialog.overlay(self) : null;
5938 if (uiDialog.next().length) {
5939 uiDialog.appendTo('body');
5942 self._position(options.position);
5943 uiDialog.show(options.show);
5944 self.moveToTop(true);
5946 // prevent tabbing out of modal dialogs
5947 if (options.modal) {
5948 uiDialog.bind('keypress.ui-dialog', function(event) {
5949 if (event.keyCode !== $.ui.keyCode.TAB) {
5953 var tabbables = $(':tabbable', this),
5954 first = tabbables.filter(':first'),
5955 last = tabbables.filter(':last');
5957 if (event.target === last[0] && !event.shiftKey) {
5960 } else if (event.target === first[0] && event.shiftKey) {
5967 // set focus to the first tabbable element in the content area or the first button
5968 // if there are no tabbable elements, set focus on the dialog itself
5969 $(self.element.find(':tabbable').get().concat(
5970 uiDialog.find('.ui-dialog-buttonpane :tabbable').get().concat(
5971 uiDialog.get()))).eq(0).focus();
5973 self._trigger('open');
5974 self._isOpen = true;
5979 _createButtons: function(buttons) {
5982 uiDialogButtonPane = $('<div></div>')
5984 'ui-dialog-buttonpane ' +
5985 'ui-widget-content ' +
5986 'ui-helper-clearfix'
5988 uiButtonSet = $( "<div></div>" )
5989 .addClass( "ui-dialog-buttonset" )
5990 .appendTo( uiDialogButtonPane );
5992 // if we already have a button pane, remove it
5993 self.uiDialog.find('.ui-dialog-buttonpane').remove();
5995 if (typeof buttons === 'object' && buttons !== null) {
5996 $.each(buttons, function() {
5997 return !(hasButtons = true);
6001 $.each(buttons, function(name, fn) {
6002 var button = $('<button type="button"></button>')
6004 .click(function() { fn.apply(self.element[0], arguments); })
6005 .appendTo(uiButtonSet);
6010 uiDialogButtonPane.appendTo(self.uiDialog);
6014 _makeDraggable: function() {
6016 options = self.options,
6020 function filteredUi(ui) {
6022 position: ui.position,
6027 self.uiDialog.draggable({
6028 cancel: '.ui-dialog-content, .ui-dialog-titlebar-close',
6029 handle: '.ui-dialog-titlebar',
6030 containment: 'document',
6031 start: function(event, ui) {
6032 heightBeforeDrag = options.height === "auto" ? "auto" : $(this).height();
6033 $(this).height($(this).height()).addClass("ui-dialog-dragging");
6034 self._trigger('dragStart', event, filteredUi(ui));
6036 drag: function(event, ui) {
6037 self._trigger('drag', event, filteredUi(ui));
6039 stop: function(event, ui) {
6040 options.position = [ui.position.left - doc.scrollLeft(),
6041 ui.position.top - doc.scrollTop()];
6042 $(this).removeClass("ui-dialog-dragging").height(heightBeforeDrag);
6043 self._trigger('dragStop', event, filteredUi(ui));
6044 $.ui.dialog.overlay.resize();
6049 _makeResizable: function(handles) {
6050 handles = (handles === undefined ? this.options.resizable : handles);
6052 options = self.options,
6053 // .ui-resizable has position: relative defined in the stylesheet
6054 // but dialogs have to use absolute or fixed positioning
6055 position = self.uiDialog.css('position'),
6056 resizeHandles = (typeof handles === 'string' ?
6058 'n,e,s,w,se,sw,ne,nw'
6061 function filteredUi(ui) {
6063 originalPosition: ui.originalPosition,
6064 originalSize: ui.originalSize,
6065 position: ui.position,
6070 self.uiDialog.resizable({
6071 cancel: '.ui-dialog-content',
6072 containment: 'document',
6073 alsoResize: self.element,
6074 maxWidth: options.maxWidth,
6075 maxHeight: options.maxHeight,
6076 minWidth: options.minWidth,
6077 minHeight: self._minHeight(),
6078 handles: resizeHandles,
6079 start: function(event, ui) {
6080 $(this).addClass("ui-dialog-resizing");
6081 self._trigger('resizeStart', event, filteredUi(ui));
6083 resize: function(event, ui) {
6084 self._trigger('resize', event, filteredUi(ui));
6086 stop: function(event, ui) {
6087 $(this).removeClass("ui-dialog-resizing");
6088 options.height = $(this).height();
6089 options.width = $(this).width();
6090 self._trigger('resizeStop', event, filteredUi(ui));
6091 $.ui.dialog.overlay.resize();
6094 .css('position', position)
6095 .find('.ui-resizable-se').addClass('ui-icon ui-icon-grip-diagonal-se');
6098 _minHeight: function() {
6099 var options = this.options;
6101 if (options.height === 'auto') {
6102 return options.minHeight;
6104 return Math.min(options.minHeight, options.height);
6108 _position: function(position) {
6114 // deep extending converts arrays to objects in jQuery <= 1.3.2 :-(
6115 // if (typeof position == 'string' || $.isArray(position)) {
6116 // myAt = $.isArray(position) ? position : position.split(' ');
6118 if (typeof position === 'string' || (typeof position === 'object' && '0' in position)) {
6119 myAt = position.split ? position.split(' ') : [position[0], position[1]];
6120 if (myAt.length === 1) {
6124 $.each(['left', 'top'], function(i, offsetPosition) {
6125 if (+myAt[i] === myAt[i]) {
6126 offset[i] = myAt[i];
6127 myAt[i] = offsetPosition;
6134 offset: offset.join(" ")
6138 position = $.extend({}, $.ui.dialog.prototype.options.position, position);
6140 position = $.ui.dialog.prototype.options.position;
6143 // need to show the dialog to get the actual offset in the position plugin
6144 isVisible = this.uiDialog.is(':visible');
6146 this.uiDialog.show();
6149 // workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781
6150 .css({ top: 0, left: 0 })
6151 .position(position);
6153 this.uiDialog.hide();
6157 _setOption: function(key, value){
6159 uiDialog = self.uiDialog,
6160 isResizable = uiDialog.is(':data(resizable)'),
6164 //handling of deprecated beforeclose (vs beforeClose) option
6165 //Ticket #4669 http://dev.jqueryui.com/ticket/4669
6166 //TODO: remove in 1.9pre
6168 key = "beforeClose";
6171 self._createButtons(value);
6175 // convert whatever was passed in to a string, for text() to not throw up
6176 self.uiDialogTitlebarCloseText.text("" + value);
6180 .removeClass(self.options.dialogClass)
6181 .addClass(uiDialogClasses + value);
6185 uiDialog.addClass('ui-dialog-disabled');
6187 uiDialog.removeClass('ui-dialog-disabled');
6192 self._makeDraggable();
6194 uiDialog.draggable('destroy');
6202 uiDialog.resizable('option', 'maxHeight', value);
6208 uiDialog.resizable('option', 'maxWidth', value);
6214 uiDialog.resizable('option', 'minHeight', value);
6220 uiDialog.resizable('option', 'minWidth', value);
6225 self._position(value);
6228 // currently resizable, becoming non-resizable
6229 if (isResizable && !value) {
6230 uiDialog.resizable('destroy');
6233 // currently resizable, changing handles
6234 if (isResizable && typeof value === 'string') {
6235 uiDialog.resizable('option', 'handles', value);
6238 // currently non-resizable, becoming resizable
6239 if (!isResizable && value !== false) {
6240 self._makeResizable(value);
6244 // convert whatever was passed in o a string, for html() to not throw up
6245 $(".ui-dialog-title", self.uiDialogTitlebar).html("" + (value || ' '));
6252 $.Widget.prototype._setOption.apply(self, arguments);
6259 /* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
6260 * divs will both have width and height set, so we need to reset them
6262 var options = this.options,
6265 // reset content sizing
6266 // hide for non content measurement because height: 0 doesn't work in IE quirks mode (see #4350)
6273 if (options.minWidth > options.width) {
6274 options.width = options.minWidth;
6277 // reset wrapper sizing
6278 // determine the height of all the non-content elements
6279 nonContentHeight = this.uiDialog.css({
6281 width: options.width
6286 .css(options.height === 'auto' ? {
6287 minHeight: Math.max(options.minHeight - nonContentHeight, 0),
6291 height: Math.max(options.height - nonContentHeight, 0)
6295 if (this.uiDialog.is(':data(resizable)')) {
6296 this.uiDialog.resizable('option', 'minHeight', this._minHeight());
6301 $.extend($.ui.dialog, {
6307 getTitleId: function($el) {
6308 var id = $el.attr('id');
6313 return 'ui-dialog-title-' + id;
6316 overlay: function(dialog) {
6317 this.$el = $.ui.dialog.overlay.create(dialog);
6321 $.extend($.ui.dialog.overlay, {
6323 // reuse old instances due to IE memory leak with alpha transparency (see #5185)
6326 events: $.map('focus,mousedown,mouseup,keydown,keypress,click'.split(','),
6327 function(event) { return event + '.dialog-overlay'; }).join(' '),
6328 create: function(dialog) {
6329 if (this.instances.length === 0) {
6330 // prevent use of anchors and inputs
6331 // we use a setTimeout in case the overlay is created from an
6332 // event that we're going to be cancelling (see #2804)
6333 setTimeout(function() {
6334 // handle $(el).dialog().dialog('close') (see #4065)
6335 if ($.ui.dialog.overlay.instances.length) {
6336 $(document).bind($.ui.dialog.overlay.events, function(event) {
6337 // stop events if the z-index of the target is < the z-index of the overlay
6338 return ($(event.target).zIndex() >= $.ui.dialog.overlay.maxZ);
6343 // allow closing by pressing the escape key
6344 $(document).bind('keydown.dialog-overlay', function(event) {
6345 if (dialog.options.closeOnEscape && event.keyCode &&
6346 event.keyCode === $.ui.keyCode.ESCAPE) {
6348 dialog.close(event);
6349 event.preventDefault();
6353 // handle window resize
6354 $(window).bind('resize.dialog-overlay', $.ui.dialog.overlay.resize);
6357 var $el = (this.oldInstances.pop() || $('<div></div>').addClass('ui-widget-overlay'))
6358 .appendTo(document.body)
6360 width: this.width(),
6361 height: this.height()
6364 if ($.fn.bgiframe) {
6368 this.instances.push($el);
6372 destroy: function($el) {
6373 this.oldInstances.push(this.instances.splice($.inArray($el, this.instances), 1)[0]);
6375 if (this.instances.length === 0) {
6376 $([document, window]).unbind('.dialog-overlay');
6381 // adjust the maxZ to allow other modal dialogs to continue to work (see #4309)
6383 $.each(this.instances, function() {
6384 maxZ = Math.max(maxZ, this.css('z-index'));
6389 height: function() {
6393 if ($.browser.msie && $.browser.version < 7) {
6394 scrollHeight = Math.max(
6395 document.documentElement.scrollHeight,
6396 document.body.scrollHeight
6398 offsetHeight = Math.max(
6399 document.documentElement.offsetHeight,
6400 document.body.offsetHeight
6403 if (scrollHeight < offsetHeight) {
6404 return $(window).height() + 'px';
6406 return scrollHeight + 'px';
6408 // handle "good" browsers
6410 return $(document).height() + 'px';
6418 if ($.browser.msie && $.browser.version < 7) {
6419 scrollWidth = Math.max(
6420 document.documentElement.scrollWidth,
6421 document.body.scrollWidth
6423 offsetWidth = Math.max(
6424 document.documentElement.offsetWidth,
6425 document.body.offsetWidth
6428 if (scrollWidth < offsetWidth) {
6429 return $(window).width() + 'px';
6431 return scrollWidth + 'px';
6433 // handle "good" browsers
6435 return $(document).width() + 'px';
6439 resize: function() {
6440 /* If the dialog is draggable and the user drags it past the
6441 * right edge of the window, the document becomes wider so we
6442 * need to stretch the overlay. If the user then drags the
6443 * dialog back to the left, the document will become narrower,
6444 * so we need to shrink the overlay to the appropriate size.
6445 * This is handled by shrinking the overlay before setting it
6446 * to the full document size.
6448 var $overlays = $([]);
6449 $.each($.ui.dialog.overlay.instances, function() {
6450 $overlays = $overlays.add(this);
6457 width: $.ui.dialog.overlay.width(),
6458 height: $.ui.dialog.overlay.height()
6463 $.extend($.ui.dialog.overlay.prototype, {
6464 destroy: function() {
6465 $.ui.dialog.overlay.destroy(this.$el);
6471 * jQuery UI Slider 1.8.4
6473 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
6474 * Dual licensed under the MIT or GPL Version 2 licenses.
6475 * http://jquery.org/license
6477 * http://docs.jquery.com/UI/Slider
6481 * jquery.ui.mouse.js
6482 * jquery.ui.widget.js
6484 (function( $, undefined ) {
6486 // number of pages in a slider
6487 // (how many times can you page up/down to go through the whole range)
6490 $.widget( "ui.slider", $.ui.mouse, {
6492 widgetEventPrefix: "slide",
6499 orientation: "horizontal",
6506 _create: function() {
6510 this._keySliding = false;
6511 this._mouseSliding = false;
6512 this._animateOff = true;
6513 this._handleIndex = null;
6514 this._detectOrientation();
6518 .addClass( "ui-slider" +
6519 " ui-slider-" + this.orientation +
6521 " ui-widget-content" +
6525 this.element.addClass( "ui-slider-disabled ui-disabled" );
6531 if ( o.range === true ) {
6532 this.range = $( "<div></div>" );
6534 o.values = [ this._valueMin(), this._valueMin() ];
6536 if ( o.values.length && o.values.length !== 2 ) {
6537 o.values = [ o.values[0], o.values[0] ];
6540 this.range = $( "<div></div>" );
6544 .appendTo( this.element )
6545 .addClass( "ui-slider-range" );
6547 if ( o.range === "min" || o.range === "max" ) {
6548 this.range.addClass( "ui-slider-range-" + o.range );
6551 // note: this isn't the most fittingly semantic framework class for this element,
6552 // but worked best visually with a variety of themes
6553 this.range.addClass( "ui-widget-header" );
6556 if ( $( ".ui-slider-handle", this.element ).length === 0 ) {
6557 $( "<a href='#'></a>" )
6558 .appendTo( this.element )
6559 .addClass( "ui-slider-handle" );
6562 if ( o.values && o.values.length ) {
6563 while ( $(".ui-slider-handle", this.element).length < o.values.length ) {
6564 $( "<a href='#'></a>" )
6565 .appendTo( this.element )
6566 .addClass( "ui-slider-handle" );
6570 this.handles = $( ".ui-slider-handle", this.element )
6571 .addClass( "ui-state-default" +
6574 this.handle = this.handles.eq( 0 );
6576 this.handles.add( this.range ).filter( "a" )
6577 .click(function( event ) {
6578 event.preventDefault();
6581 if ( !o.disabled ) {
6582 $( this ).addClass( "ui-state-hover" );
6585 $( this ).removeClass( "ui-state-hover" );
6588 if ( !o.disabled ) {
6589 $( ".ui-slider .ui-state-focus" ).removeClass( "ui-state-focus" );
6590 $( this ).addClass( "ui-state-focus" );
6596 $( this ).removeClass( "ui-state-focus" );
6599 this.handles.each(function( i ) {
6600 $( this ).data( "index.ui-slider-handle", i );
6604 .keydown(function( event ) {
6606 index = $( this ).data( "index.ui-slider-handle" ),
6612 if ( self.options.disabled ) {
6616 switch ( event.keyCode ) {
6617 case $.ui.keyCode.HOME:
6618 case $.ui.keyCode.END:
6619 case $.ui.keyCode.PAGE_UP:
6620 case $.ui.keyCode.PAGE_DOWN:
6621 case $.ui.keyCode.UP:
6622 case $.ui.keyCode.RIGHT:
6623 case $.ui.keyCode.DOWN:
6624 case $.ui.keyCode.LEFT:
6626 if ( !self._keySliding ) {
6627 self._keySliding = true;
6628 $( this ).addClass( "ui-state-active" );
6629 allowed = self._start( event, index );
6630 if ( allowed === false ) {
6637 step = self.options.step;
6638 if ( self.options.values && self.options.values.length ) {
6639 curVal = newVal = self.values( index );
6641 curVal = newVal = self.value();
6644 switch ( event.keyCode ) {
6645 case $.ui.keyCode.HOME:
6646 newVal = self._valueMin();
6648 case $.ui.keyCode.END:
6649 newVal = self._valueMax();
6651 case $.ui.keyCode.PAGE_UP:
6652 newVal = self._trimAlignValue( curVal + ( (self._valueMax() - self._valueMin()) / numPages ) );
6654 case $.ui.keyCode.PAGE_DOWN:
6655 newVal = self._trimAlignValue( curVal - ( (self._valueMax() - self._valueMin()) / numPages ) );
6657 case $.ui.keyCode.UP:
6658 case $.ui.keyCode.RIGHT:
6659 if ( curVal === self._valueMax() ) {
6662 newVal = self._trimAlignValue( curVal + step );
6664 case $.ui.keyCode.DOWN:
6665 case $.ui.keyCode.LEFT:
6666 if ( curVal === self._valueMin() ) {
6669 newVal = self._trimAlignValue( curVal - step );
6673 self._slide( event, index, newVal );
6678 .keyup(function( event ) {
6679 var index = $( this ).data( "index.ui-slider-handle" );
6681 if ( self._keySliding ) {
6682 self._keySliding = false;
6683 self._stop( event, index );
6684 self._change( event, index );
6685 $( this ).removeClass( "ui-state-active" );
6690 this._refreshValue();
6692 this._animateOff = false;
6695 destroy: function() {
6696 this.handles.remove();
6697 this.range.remove();
6700 .removeClass( "ui-slider" +
6701 " ui-slider-horizontal" +
6702 " ui-slider-vertical" +
6703 " ui-slider-disabled" +
6705 " ui-widget-content" +
6707 .removeData( "slider" )
6708 .unbind( ".slider" );
6710 this._mouseDestroy();
6715 _mouseCapture: function( event ) {
6716 var o = this.options,
6731 this.elementSize = {
6732 width: this.element.outerWidth(),
6733 height: this.element.outerHeight()
6735 this.elementOffset = this.element.offset();
6737 position = { x: event.pageX, y: event.pageY };
6738 normValue = this._normValueFromMouse( position );
6739 distance = this._valueMax() - this._valueMin() + 1;
6741 this.handles.each(function( i ) {
6742 var thisDistance = Math.abs( normValue - self.values(i) );
6743 if ( distance > thisDistance ) {
6744 distance = thisDistance;
6745 closestHandle = $( this );
6750 // workaround for bug #3736 (if both handles of a range are at 0,
6751 // the first is always used as the one with least distance,
6752 // and moving it is obviously prevented by preventing negative ranges)
6753 if( o.range === true && this.values(1) === o.min ) {
6755 closestHandle = $( this.handles[index] );
6758 allowed = this._start( event, index );
6759 if ( allowed === false ) {
6762 this._mouseSliding = true;
6764 self._handleIndex = index;
6767 .addClass( "ui-state-active" )
6770 offset = closestHandle.offset();
6771 mouseOverHandle = !$( event.target ).parents().andSelf().is( ".ui-slider-handle" );
6772 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
6773 left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
6774 top: event.pageY - offset.top -
6775 ( closestHandle.height() / 2 ) -
6776 ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
6777 ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
6778 ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
6781 this._slide( event, index, normValue );
6782 this._animateOff = true;
6786 _mouseStart: function( event ) {
6790 _mouseDrag: function( event ) {
6791 var position = { x: event.pageX, y: event.pageY },
6792 normValue = this._normValueFromMouse( position );
6794 this._slide( event, this._handleIndex, normValue );
6799 _mouseStop: function( event ) {
6800 this.handles.removeClass( "ui-state-active" );
6801 this._mouseSliding = false;
6803 this._stop( event, this._handleIndex );
6804 this._change( event, this._handleIndex );
6806 this._handleIndex = null;
6807 this._clickOffset = null;
6808 this._animateOff = false;
6813 _detectOrientation: function() {
6814 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
6817 _normValueFromMouse: function( position ) {
6824 if ( this.orientation === "horizontal" ) {
6825 pixelTotal = this.elementSize.width;
6826 pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
6828 pixelTotal = this.elementSize.height;
6829 pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
6832 percentMouse = ( pixelMouse / pixelTotal );
6833 if ( percentMouse > 1 ) {
6836 if ( percentMouse < 0 ) {
6839 if ( this.orientation === "vertical" ) {
6840 percentMouse = 1 - percentMouse;
6843 valueTotal = this._valueMax() - this._valueMin();
6844 valueMouse = this._valueMin() + percentMouse * valueTotal;
6846 return this._trimAlignValue( valueMouse );
6849 _start: function( event, index ) {
6851 handle: this.handles[ index ],
6854 if ( this.options.values && this.options.values.length ) {
6855 uiHash.value = this.values( index );
6856 uiHash.values = this.values();
6858 return this._trigger( "start", event, uiHash );
6861 _slide: function( event, index, newVal ) {
6866 if ( this.options.values && this.options.values.length ) {
6867 otherVal = this.values( index ? 0 : 1 );
6869 if ( ( this.options.values.length === 2 && this.options.range === true ) &&
6870 ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
6875 if ( newVal !== this.values( index ) ) {
6876 newValues = this.values();
6877 newValues[ index ] = newVal;
6878 // A slide can be canceled by returning false from the slide callback
6879 allowed = this._trigger( "slide", event, {
6880 handle: this.handles[ index ],
6884 otherVal = this.values( index ? 0 : 1 );
6885 if ( allowed !== false ) {
6886 this.values( index, newVal, true );
6890 if ( newVal !== this.value() ) {
6891 // A slide can be canceled by returning false from the slide callback
6892 allowed = this._trigger( "slide", event, {
6893 handle: this.handles[ index ],
6896 if ( allowed !== false ) {
6897 this.value( newVal );
6903 _stop: function( event, index ) {
6905 handle: this.handles[ index ],
6908 if ( this.options.values && this.options.values.length ) {
6909 uiHash.value = this.values( index );
6910 uiHash.values = this.values();
6913 this._trigger( "stop", event, uiHash );
6916 _change: function( event, index ) {
6917 if ( !this._keySliding && !this._mouseSliding ) {
6919 handle: this.handles[ index ],
6922 if ( this.options.values && this.options.values.length ) {
6923 uiHash.value = this.values( index );
6924 uiHash.values = this.values();
6927 this._trigger( "change", event, uiHash );
6931 value: function( newValue ) {
6932 if ( arguments.length ) {
6933 this.options.value = this._trimAlignValue( newValue );
6934 this._refreshValue();
6935 this._change( null, 0 );
6938 return this._value();
6941 values: function( index, newValue ) {
6946 if ( arguments.length > 1 ) {
6947 this.options.values[ index ] = this._trimAlignValue( newValue );
6948 this._refreshValue();
6949 this._change( null, index );
6952 if ( arguments.length ) {
6953 if ( $.isArray( arguments[ 0 ] ) ) {
6954 vals = this.options.values;
6955 newValues = arguments[ 0 ];
6956 for ( i = 0; i < vals.length; i += 1 ) {
6957 vals[ i ] = this._trimAlignValue( newValues[ i ] );
6958 this._change( null, i );
6960 this._refreshValue();
6962 if ( this.options.values && this.options.values.length ) {
6963 return this._values( index );
6965 return this.value();
6969 return this._values();
6973 _setOption: function( key, value ) {
6977 if ( $.isArray( this.options.values ) ) {
6978 valsLength = this.options.values.length;
6981 $.Widget.prototype._setOption.apply( this, arguments );
6986 this.handles.filter( ".ui-state-focus" ).blur();
6987 this.handles.removeClass( "ui-state-hover" );
6988 this.handles.attr( "disabled", "disabled" );
6989 this.element.addClass( "ui-disabled" );
6991 this.handles.removeAttr( "disabled" );
6992 this.element.removeClass( "ui-disabled" );
6996 this._detectOrientation();
6998 .removeClass( "ui-slider-horizontal ui-slider-vertical" )
6999 .addClass( "ui-slider-" + this.orientation );
7000 this._refreshValue();
7003 this._animateOff = true;
7004 this._refreshValue();
7005 this._change( null, 0 );
7006 this._animateOff = false;
7009 this._animateOff = true;
7010 this._refreshValue();
7011 for ( i = 0; i < valsLength; i += 1 ) {
7012 this._change( null, i );
7014 this._animateOff = false;
7019 //internal value getter
7020 // _value() returns value trimmed by min and max, aligned by step
7021 _value: function() {
7022 var val = this.options.value;
7023 val = this._trimAlignValue( val );
7028 //internal values getter
7029 // _values() returns array of values trimmed by min and max, aligned by step
7030 // _values( index ) returns single value trimmed by min and max, aligned by step
7031 _values: function( index ) {
7036 if ( arguments.length ) {
7037 val = this.options.values[ index ];
7038 val = this._trimAlignValue( val );
7042 // .slice() creates a copy of the array
7043 // this copy gets trimmed by min and max and then returned
7044 vals = this.options.values.slice();
7045 for ( i = 0; i < vals.length; i+= 1) {
7046 vals[ i ] = this._trimAlignValue( vals[ i ] );
7053 // returns the step-aligned value that val is closest to, between (inclusive) min and max
7054 _trimAlignValue: function( val ) {
7055 if ( val < this._valueMin() ) {
7056 return this._valueMin();
7058 if ( val > this._valueMax() ) {
7059 return this._valueMax();
7061 var step = ( this.options.step > 0 ) ? this.options.step : 1,
7062 valModStep = val % step,
7063 alignValue = val - valModStep;
7065 if ( Math.abs(valModStep) * 2 >= step ) {
7066 alignValue += ( valModStep > 0 ) ? step : ( -step );
7069 // Since JavaScript has problems with large floats, round
7070 // the final value to 5 digits after the decimal point (see #4124)
7071 return parseFloat( alignValue.toFixed(5) );
7074 _valueMin: function() {
7075 return this.options.min;
7078 _valueMax: function() {
7079 return this.options.max;
7082 _refreshValue: function() {
7083 var oRange = this.options.range,
7086 animate = ( !this._animateOff ) ? o.animate : false,
7094 if ( this.options.values && this.options.values.length ) {
7095 this.handles.each(function( i, j ) {
7096 valPercent = ( self.values(i) - self._valueMin() ) / ( self._valueMax() - self._valueMin() ) * 100;
7097 _set[ self.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
7098 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
7099 if ( self.options.range === true ) {
7100 if ( self.orientation === "horizontal" ) {
7102 self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
7105 self.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
7109 self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
7112 self.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
7116 lastValPercent = valPercent;
7119 value = this.value();
7120 valueMin = this._valueMin();
7121 valueMax = this._valueMax();
7122 valPercent = ( valueMax !== valueMin ) ?
7123 ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
7125 _set[ self.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
7126 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
7128 if ( oRange === "min" && this.orientation === "horizontal" ) {
7129 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
7131 if ( oRange === "max" && this.orientation === "horizontal" ) {
7132 this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
7134 if ( oRange === "min" && this.orientation === "vertical" ) {
7135 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
7137 if ( oRange === "max" && this.orientation === "vertical" ) {
7138 this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
7145 $.extend( $.ui.slider, {
7151 * jQuery UI Tabs 1.8.4
7153 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
7154 * Dual licensed under the MIT or GPL Version 2 licenses.
7155 * http://jquery.org/license
7157 * http://docs.jquery.com/UI/Tabs
7161 * jquery.ui.widget.js
7163 (function( $, undefined ) {
7168 function getNextTabId() {
7172 function getNextListId() {
7176 $.widget( "ui.tabs", {
7181 cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
7187 fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 }
7188 idPrefix: "ui-tabs-",
7190 panelTemplate: "<div></div>",
7194 spinner: "<em>Loading…</em>",
7195 tabTemplate: "<li><a href='#{href}'><span>#{label}</span></a></li>"
7198 _create: function() {
7199 this._tabify( true );
7202 _setOption: function( key, value ) {
7203 if ( key == "selected" ) {
7204 if (this.options.collapsible && value == this.options.selected ) {
7207 this.select( value );
7209 this.options[ key ] = value;
7214 _tabId: function( a ) {
7215 return a.title && a.title.replace( /\s/g, "_" ).replace( /[^A-Za-z0-9\-_:\.]/g, "" ) ||
7216 this.options.idPrefix + getNextTabId();
7219 _sanitizeSelector: function( hash ) {
7220 // we need this because an id may contain a ":"
7221 return hash.replace( /:/g, "\\:" );
7224 _cookie: function() {
7225 var cookie = this.cookie ||
7226 ( this.cookie = this.options.cookie.name || "ui-tabs-" + getNextListId() );
7227 return $.cookie.apply( null, [ cookie ].concat( $.makeArray( arguments ) ) );
7230 _ui: function( tab, panel ) {
7234 index: this.anchors.index( tab )
7238 _cleanup: function() {
7239 // restore all former loading tabs labels
7240 this.lis.filter( ".ui-state-processing" )
7241 .removeClass( "ui-state-processing" )
7242 .find( "span:data(label.tabs)" )
7245 el.html( el.data( "label.tabs" ) ).removeData( "label.tabs" );
7249 _tabify: function( init ) {
7252 fragmentId = /^#.+/; // Safari 2 reports '#' for an empty hash
7254 this.list = this.element.find( "ol,ul" ).eq( 0 );
7255 this.lis = $( "li:has(a[href])", this.list );
7256 this.anchors = this.lis.map(function() {
7257 return $( "a", this )[ 0 ];
7259 this.panels = $( [] );
7261 this.anchors.each(function( i, a ) {
7262 var href = $( a ).attr( "href" );
7263 // For dynamically created HTML that contains a hash as href IE < 8 expands
7264 // such href to the full page url with hash and then misinterprets tab as ajax.
7265 // Same consideration applies for an added tab with a fragment identifier
7266 // since a[href=#fragment-identifier] does unexpectedly not match.
7267 // Thus normalize href attribute...
7268 var hrefBase = href.split( "#" )[ 0 ],
7270 if ( hrefBase && ( hrefBase === location.toString().split( "#" )[ 0 ] ||
7271 ( baseEl = $( "base" )[ 0 ]) && hrefBase === baseEl.href ) ) {
7277 if ( fragmentId.test( href ) ) {
7278 self.panels = self.panels.add( self._sanitizeSelector( href ) );
7280 // prevent loading the page itself if href is just "#"
7281 } else if ( href !== "#" ) {
7282 // required for restore on destroy
7283 $.data( a, "href.tabs", href );
7285 // TODO until #3808 is fixed strip fragment identifier from url
7286 // (IE fails to load from such url)
7287 $.data( a, "load.tabs", href.replace( /#.*$/, "" ) );
7289 var id = self._tabId( a );
7291 var $panel = $( "#" + id );
7292 if ( !$panel.length ) {
7293 $panel = $( o.panelTemplate )
7295 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
7296 .insertAfter( self.panels[ i - 1 ] || self.list );
7297 $panel.data( "destroy.tabs", true );
7299 self.panels = self.panels.add( $panel );
7302 o.disabled.push( i );
7306 // initialization from scratch
7308 // attach necessary classes for styling
7309 this.element.addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" );
7310 this.list.addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" );
7311 this.lis.addClass( "ui-state-default ui-corner-top" );
7312 this.panels.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" );
7315 // use "selected" option or try to retrieve:
7316 // 1. from fragment identifier in url
7318 // 3. from selected class attribute on <li>
7319 if ( o.selected === undefined ) {
7320 if ( location.hash ) {
7321 this.anchors.each(function( i, a ) {
7322 if ( a.hash == location.hash ) {
7328 if ( typeof o.selected !== "number" && o.cookie ) {
7329 o.selected = parseInt( self._cookie(), 10 );
7331 if ( typeof o.selected !== "number" && this.lis.filter( ".ui-tabs-selected" ).length ) {
7332 o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) );
7334 o.selected = o.selected || ( this.lis.length ? 0 : -1 );
7335 } else if ( o.selected === null ) { // usage of null is deprecated, TODO remove in next release
7339 // sanity check - default to first tab...
7340 o.selected = ( ( o.selected >= 0 && this.anchors[ o.selected ] ) || o.selected < 0 )
7344 // Take disabling tabs via class attribute from HTML
7345 // into account and update option properly.
7346 // A selected tab cannot become disabled.
7347 o.disabled = $.unique( o.disabled.concat(
7348 $.map( this.lis.filter( ".ui-state-disabled" ), function( n, i ) {
7349 return self.lis.index( n );
7353 if ( $.inArray( o.selected, o.disabled ) != -1 ) {
7354 o.disabled.splice( $.inArray( o.selected, o.disabled ), 1 );
7357 // highlight selected tab
7358 this.panels.addClass( "ui-tabs-hide" );
7359 this.lis.removeClass( "ui-tabs-selected ui-state-active" );
7360 // check for length avoids error when initializing empty list
7361 if ( o.selected >= 0 && this.anchors.length ) {
7362 this.panels.eq( o.selected ).removeClass( "ui-tabs-hide" );
7363 this.lis.eq( o.selected ).addClass( "ui-tabs-selected ui-state-active" );
7365 // seems to be expected behavior that the show callback is fired
7366 self.element.queue( "tabs", function() {
7367 self._trigger( "show", null,
7368 self._ui( self.anchors[ o.selected ], self.panels[ o.selected ] ) );
7371 this.load( o.selected );
7374 // clean up to avoid memory leaks in certain versions of IE 6
7375 // TODO: namespace this event
7376 $( window ).bind( "unload", function() {
7377 self.lis.add( self.anchors ).unbind( ".tabs" );
7378 self.lis = self.anchors = self.panels = null;
7380 // update selected after add/remove
7382 o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) );
7385 // update collapsible
7386 // TODO: use .toggleClass()
7387 this.element[ o.collapsible ? "addClass" : "removeClass" ]( "ui-tabs-collapsible" );
7389 // set or update cookie after init and add/remove respectively
7391 this._cookie( o.selected, o.cookie );
7395 for ( var i = 0, li; ( li = this.lis[ i ] ); i++ ) {
7396 $( li )[ $.inArray( i, o.disabled ) != -1 &&
7397 // TODO: use .toggleClass()
7398 !$( li ).hasClass( "ui-tabs-selected" ) ? "addClass" : "removeClass" ]( "ui-state-disabled" );
7401 // reset cache if switching from cached to not cached
7402 if ( o.cache === false ) {
7403 this.anchors.removeData( "cache.tabs" );
7406 // remove all handlers before, tabify may run on existing tabs after add or option change
7407 this.lis.add( this.anchors ).unbind( ".tabs" );
7409 if ( o.event !== "mouseover" ) {
7410 var addState = function( state, el ) {
7411 if ( el.is( ":not(.ui-state-disabled)" ) ) {
7412 el.addClass( "ui-state-" + state );
7415 var removeState = function( state, el ) {
7416 el.removeClass( "ui-state-" + state );
7418 this.lis.bind( "mouseover.tabs" , function() {
7419 addState( "hover", $( this ) );
7421 this.lis.bind( "mouseout.tabs", function() {
7422 removeState( "hover", $( this ) );
7424 this.anchors.bind( "focus.tabs", function() {
7425 addState( "focus", $( this ).closest( "li" ) );
7427 this.anchors.bind( "blur.tabs", function() {
7428 removeState( "focus", $( this ).closest( "li" ) );
7432 // set up animations
7435 if ( $.isArray( o.fx ) ) {
7439 hideFx = showFx = o.fx;
7443 // Reset certain styles left over from animation
7444 // and prevent IE's ClearType bug...
7445 function resetStyle( $el, fx ) {
7446 $el.css( "display", "" );
7447 if ( !$.support.opacity && fx.opacity ) {
7448 $el[ 0 ].style.removeAttribute( "filter" );
7453 var showTab = showFx
7454 ? function( clicked, $show ) {
7455 $( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" );
7456 $show.hide().removeClass( "ui-tabs-hide" ) // avoid flicker that way
7457 .animate( showFx, showFx.duration || "normal", function() {
7458 resetStyle( $show, showFx );
7459 self._trigger( "show", null, self._ui( clicked, $show[ 0 ] ) );
7462 : function( clicked, $show ) {
7463 $( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" );
7464 $show.removeClass( "ui-tabs-hide" );
7465 self._trigger( "show", null, self._ui( clicked, $show[ 0 ] ) );
7468 // Hide a tab, $show is optional...
7469 var hideTab = hideFx
7470 ? function( clicked, $hide ) {
7471 $hide.animate( hideFx, hideFx.duration || "normal", function() {
7472 self.lis.removeClass( "ui-tabs-selected ui-state-active" );
7473 $hide.addClass( "ui-tabs-hide" );
7474 resetStyle( $hide, hideFx );
7475 self.element.dequeue( "tabs" );
7478 : function( clicked, $hide, $show ) {
7479 self.lis.removeClass( "ui-tabs-selected ui-state-active" );
7480 $hide.addClass( "ui-tabs-hide" );
7481 self.element.dequeue( "tabs" );
7484 // attach tab event handler, unbind to avoid duplicates from former tabifying...
7485 this.anchors.bind( o.event + ".tabs", function() {
7487 $li = $(el).closest( "li" ),
7488 $hide = self.panels.filter( ":not(.ui-tabs-hide)" ),
7489 $show = $( self._sanitizeSelector( el.hash ) );
7491 // If tab is already selected and not collapsible or tab disabled or
7492 // or is already loading or click callback returns false stop here.
7493 // Check if click handler returns false last so that it is not executed
7494 // for a disabled or loading tab!
7495 if ( ( $li.hasClass( "ui-tabs-selected" ) && !o.collapsible) ||
7496 $li.hasClass( "ui-state-disabled" ) ||
7497 $li.hasClass( "ui-state-processing" ) ||
7498 self._trigger( "select", null, self._ui( this, $show[ 0 ] ) ) === false ) {
7503 o.selected = self.anchors.index( this );
7507 // if tab may be closed
7508 if ( o.collapsible ) {
7509 if ( $li.hasClass( "ui-tabs-selected" ) ) {
7513 self._cookie( o.selected, o.cookie );
7516 self.element.queue( "tabs", function() {
7517 hideTab( el, $hide );
7518 }).dequeue( "tabs" );
7522 } else if ( !$hide.length ) {
7524 self._cookie( o.selected, o.cookie );
7527 self.element.queue( "tabs", function() {
7528 showTab( el, $show );
7531 // TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171
7532 self.load( self.anchors.index( this ) );
7540 self._cookie( o.selected, o.cookie );
7544 if ( $show.length ) {
7545 if ( $hide.length ) {
7546 self.element.queue( "tabs", function() {
7547 hideTab( el, $hide );
7550 self.element.queue( "tabs", function() {
7551 showTab( el, $show );
7554 self.load( self.anchors.index( this ) );
7556 throw "jQuery UI Tabs: Mismatching fragment identifier.";
7559 // Prevent IE from keeping other link focussed when using the back button
7560 // and remove dotted border from clicked link. This is controlled via CSS
7561 // in modern browsers; blur() removes focus from address bar in Firefox
7562 // which can become a usability and annoying problem with tabs('rotate').
7563 if ( $.browser.msie ) {
7568 // disable click in any case
7569 this.anchors.bind( "click.tabs", function(){
7574 _getIndex: function( index ) {
7575 // meta-function to give users option to provide a href string instead of a numerical index.
7576 // also sanitizes numerical indexes to valid values.
7577 if ( typeof index == "string" ) {
7578 index = this.anchors.index( this.anchors.filter( "[href$=" + index + "]" ) );
7584 destroy: function() {
7585 var o = this.options;
7591 .removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" )
7592 .removeData( "tabs" );
7594 this.list.removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" );
7596 this.anchors.each(function() {
7597 var href = $.data( this, "href.tabs" );
7601 var $this = $( this ).unbind( ".tabs" );
7602 $.each( [ "href", "load", "cache" ], function( i, prefix ) {
7603 $this.removeData( prefix + ".tabs" );
7607 this.lis.unbind( ".tabs" ).add( this.panels ).each(function() {
7608 if ( $.data( this, "destroy.tabs" ) ) {
7611 $( this ).removeClass([
7618 "ui-state-disabled",
7620 "ui-widget-content",
7628 this._cookie( null, o.cookie );
7634 add: function( url, label, index ) {
7635 if ( index === undefined ) {
7636 index = this.anchors.length;
7641 $li = $( o.tabTemplate.replace( /#\{href\}/g, url ).replace( /#\{label\}/g, label ) ),
7642 id = !url.indexOf( "#" ) ? url.replace( "#", "" ) : this._tabId( $( "a", $li )[ 0 ] );
7644 $li.addClass( "ui-state-default ui-corner-top" ).data( "destroy.tabs", true );
7646 // try to find an existing element before creating a new one
7647 var $panel = $( "#" + id );
7648 if ( !$panel.length ) {
7649 $panel = $( o.panelTemplate )
7651 .data( "destroy.tabs", true );
7653 $panel.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide" );
7655 if ( index >= this.lis.length ) {
7656 $li.appendTo( this.list );
7657 $panel.appendTo( this.list[ 0 ].parentNode );
7659 $li.insertBefore( this.lis[ index ] );
7660 $panel.insertBefore( this.panels[ index ] );
7663 o.disabled = $.map( o.disabled, function( n, i ) {
7664 return n >= index ? ++n : n;
7669 if ( this.anchors.length == 1 ) {
7671 $li.addClass( "ui-tabs-selected ui-state-active" );
7672 $panel.removeClass( "ui-tabs-hide" );
7673 this.element.queue( "tabs", function() {
7674 self._trigger( "show", null, self._ui( self.anchors[ 0 ], self.panels[ 0 ] ) );
7680 this._trigger( "add", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
7684 remove: function( index ) {
7685 index = this._getIndex( index );
7686 var o = this.options,
7687 $li = this.lis.eq( index ).remove(),
7688 $panel = this.panels.eq( index ).remove();
7690 // If selected tab was removed focus tab to the right or
7691 // in case the last tab was removed the tab to the left.
7692 if ( $li.hasClass( "ui-tabs-selected" ) && this.anchors.length > 1) {
7693 this.select( index + ( index + 1 < this.anchors.length ? 1 : -1 ) );
7697 $.grep( o.disabled, function(n, i) {
7701 return n >= index ? --n : n;
7706 this._trigger( "remove", null, this._ui( $li.find( "a" )[ 0 ], $panel[ 0 ] ) );
7710 enable: function( index ) {
7711 index = this._getIndex( index );
7712 var o = this.options;
7713 if ( $.inArray( index, o.disabled ) == -1 ) {
7717 this.lis.eq( index ).removeClass( "ui-state-disabled" );
7718 o.disabled = $.grep( o.disabled, function( n, i ) {
7722 this._trigger( "enable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
7726 disable: function( index ) {
7727 index = this._getIndex( index );
7728 var self = this, o = this.options;
7729 // cannot disable already selected tab
7730 if ( index != o.selected ) {
7731 this.lis.eq( index ).addClass( "ui-state-disabled" );
7733 o.disabled.push( index );
7736 this._trigger( "disable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
7742 select: function( index ) {
7743 index = this._getIndex( index );
7744 if ( index == -1 ) {
7745 if ( this.options.collapsible && this.options.selected != -1 ) {
7746 index = this.options.selected;
7751 this.anchors.eq( index ).trigger( this.options.event + ".tabs" );
7755 load: function( indexĀ ) {
7756 index = this._getIndex( index );
7759 a = this.anchors.eq( index )[ 0 ],
7760 url = $.data( a, "load.tabs" );
7764 // not remote or from cache
7765 if ( !url || this.element.queue( "tabs" ).length !== 0 && $.data( a, "cache.tabs" ) ) {
7766 this.element.dequeue( "tabs" );
7770 // load remote from here on
7771 this.lis.eq( index ).addClass( "ui-state-processing" );
7774 var span = $( "span", a );
7775 span.data( "label.tabs", span.html() ).html( o.spinner );
7778 this.xhr = $.ajax( $.extend( {}, o.ajaxOptions, {
7780 success: function( r, s ) {
7781 $( self._sanitizeSelector( a.hash ) ).html( r );
7783 // take care of tab labels
7787 $.data( a, "cache.tabs", true );
7790 self._trigger( "load", null, self._ui( self.anchors[ index ], self.panels[ index ] ) );
7792 o.ajaxOptions.success( r, s );
7796 error: function( xhr, s, e ) {
7797 // take care of tab labels
7800 self._trigger( "load", null, self._ui( self.anchors[ index ], self.panels[ index ] ) );
7802 // Passing index avoid a race condition when this method is
7803 // called after the user has selected another tab.
7804 // Pass the anchor that initiated this request allows
7805 // loadError to manipulate the tab content panel via $(a.hash)
7806 o.ajaxOptions.error( xhr, s, index, a );
7812 // last, so that load event is fired before show...
7813 self.element.dequeue( "tabs" );
7819 // stop possibly running animations
7820 this.element.queue( [] );
7821 this.panels.stop( false, true );
7823 // "tabs" queue must not contain more than two elements,
7824 // which are the callbacks for the latest clicked tab...
7825 this.element.queue( "tabs", this.element.queue( "tabs" ).splice( -2, 2 ) );
7827 // terminate pending requests from other tabs
7833 // take care of tab labels
7838 url: function( index, url ) {
7839 this.anchors.eq( index ).removeData( "cache.tabs" ).data( "load.tabs", url );
7843 length: function() {
7844 return this.anchors.length;
7848 $.extend( $.ui.tabs, {
7859 $.extend( $.ui.tabs.prototype, {
7861 rotate: function( ms, continuing ) {
7865 var rotate = self._rotate || ( self._rotate = function( e ) {
7866 clearTimeout( self.rotation );
7867 self.rotation = setTimeout(function() {
7869 self.select( ++t < self.anchors.length ? t : 0 );
7873 e.stopPropagation();
7877 var stop = self._unrotate || ( self._unrotate = !continuing
7879 if (e.clientX) { // in case of a true click
7890 this.element.bind( "tabsshow", rotate );
7891 this.anchors.bind( o.event + ".tabs", stop );
7895 clearTimeout( self.rotation );
7896 this.element.unbind( "tabsshow", rotate );
7897 this.anchors.unbind( o.event + ".tabs", stop );
7898 delete this._rotate;
7899 delete this._unrotate;
7908 * jQuery UI Datepicker 1.8.4
7910 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
7911 * Dual licensed under the MIT or GPL Version 2 licenses.
7912 * http://jquery.org/license
7914 * http://docs.jquery.com/UI/Datepicker
7919 (function( $, undefined ) {
7921 $.extend($.ui, { datepicker: { version: "1.8.4" } });
7923 var PROP_NAME = 'datepicker';
7924 var dpuuid = new Date().getTime();
7926 /* Date picker manager.
7927 Use the singleton instance of this class, $.datepicker, to interact with the date picker.
7928 Settings for (groups of) date pickers are maintained in an instance object,
7929 allowing multiple different settings on the same page. */
7931 function Datepicker() {
7932 this.debug = false; // Change this to true to start debugging
7933 this._curInst = null; // The current instance in use
7934 this._keyEvent = false; // If the last event was a key event
7935 this._disabledInputs = []; // List of date picker inputs that have been disabled
7936 this._datepickerShowing = false; // True if the popup picker is showing , false if not
7937 this._inDialog = false; // True if showing within a "dialog", false if not
7938 this._mainDivId = 'ui-datepicker-div'; // The ID of the main datepicker division
7939 this._inlineClass = 'ui-datepicker-inline'; // The name of the inline marker class
7940 this._appendClass = 'ui-datepicker-append'; // The name of the append marker class
7941 this._triggerClass = 'ui-datepicker-trigger'; // The name of the trigger marker class
7942 this._dialogClass = 'ui-datepicker-dialog'; // The name of the dialog marker class
7943 this._disableClass = 'ui-datepicker-disabled'; // The name of the disabled covering marker class
7944 this._unselectableClass = 'ui-datepicker-unselectable'; // The name of the unselectable cell marker class
7945 this._currentClass = 'ui-datepicker-current-day'; // The name of the current day marker class
7946 this._dayOverClass = 'ui-datepicker-days-cell-over'; // The name of the day hover marker class
7947 this.regional = []; // Available regional settings, indexed by language code
7948 this.regional[''] = { // Default regional settings
7949 closeText: 'Done', // Display text for close link
7950 prevText: 'Prev', // Display text for previous month link
7951 nextText: 'Next', // Display text for next month link
7952 currentText: 'Today', // Display text for current month link
7953 monthNames: ['January','February','March','April','May','June',
7954 'July','August','September','October','November','December'], // Names of months for drop-down and formatting
7955 monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting
7956 dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting
7957 dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting
7958 dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday
7959 weekHeader: 'Wk', // Column header for week of the year
7960 dateFormat: 'mm/dd/yy', // See format options on parseDate
7961 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
7962 isRTL: false, // True if right-to-left language, false if left-to-right
7963 showMonthAfterYear: false, // True if the year select precedes month, false for month then year
7964 yearSuffix: '' // Additional text to append to the year in the month headers
7966 this._defaults = { // Global defaults for all the date picker instances
7967 showOn: 'focus', // 'focus' for popup on focus,
7968 // 'button' for trigger button, or 'both' for either
7969 showAnim: 'fadeIn', // Name of jQuery animation for popup
7970 showOptions: {}, // Options for enhanced animations
7971 defaultDate: null, // Used when field is blank: actual date,
7972 // +/-number for offset from today, null for today
7973 appendText: '', // Display text following the input box, e.g. showing the format
7974 buttonText: '...', // Text for trigger button
7975 buttonImage: '', // URL for trigger button image
7976 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
7977 hideIfNoPrevNext: false, // True to hide next/previous month links
7978 // if not applicable, false to just disable them
7979 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
7980 gotoCurrent: false, // True if today link goes back to current selection instead
7981 changeMonth: false, // True if month can be selected directly, false if only prev/next
7982 changeYear: false, // True if year can be selected directly, false if only prev/next
7983 yearRange: 'c-10:c+10', // Range of years to display in drop-down,
7984 // either relative to today's year (-nn:+nn), relative to currently displayed year
7985 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
7986 showOtherMonths: false, // True to show dates in other months, false to leave blank
7987 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
7988 showWeek: false, // True to show week of the year, false to not show it
7989 calculateWeek: this.iso8601Week, // How to calculate the week of the year,
7990 // takes a Date and returns the number of the week for it
7991 shortYearCutoff: '+10', // Short year values < this are in the current century,
7992 // > this are in the previous century,
7993 // string value starting with '+' for current year + value
7994 minDate: null, // The earliest selectable date, or null for no limit
7995 maxDate: null, // The latest selectable date, or null for no limit
7996 duration: 'fast', // Duration of display/closure
7997 beforeShowDay: null, // Function that takes a date and returns an array with
7998 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '',
7999 // [2] = cell title (optional), e.g. $.datepicker.noWeekends
8000 beforeShow: null, // Function that takes an input field and
8001 // returns a set of custom settings for the date picker
8002 onSelect: null, // Define a callback function when a date is selected
8003 onChangeMonthYear: null, // Define a callback function when the month or year is changed
8004 onClose: null, // Define a callback function when the datepicker is closed
8005 numberOfMonths: 1, // Number of months to show at a time
8006 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
8007 stepMonths: 1, // Number of months to step back/forward
8008 stepBigMonths: 12, // Number of months to step back/forward for the big links
8009 altField: '', // Selector for an alternate field to store selected dates into
8010 altFormat: '', // The date format to use for the alternate field
8011 constrainInput: true, // The input is constrained by the current date format
8012 showButtonPanel: false, // True to show button panel, false to not show it
8013 autoSize: false // True to size the input for the date format, false to leave as is
8015 $.extend(this._defaults, this.regional['']);
8016 this.dpDiv = $('<div id="' + this._mainDivId + '" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all ui-helper-hidden-accessible"></div>');
8019 $.extend(Datepicker.prototype, {
8020 /* Class name added to elements to indicate already configured with a date picker. */
8021 markerClassName: 'hasDatepicker',
8023 /* Debug logging (if enabled). */
8026 console.log.apply('', arguments);
8029 // TODO rename to "widget" when switching to widget factory
8030 _widgetDatepicker: function() {
8034 /* Override the default settings for all instances of the date picker.
8035 @param settings object - the new settings to use as defaults (anonymous object)
8036 @return the manager object */
8037 setDefaults: function(settings) {
8038 extendRemove(this._defaults, settings || {});
8042 /* Attach the date picker to a jQuery selection.
8043 @param target element - the target input field or division or span
8044 @param settings object - the new settings to use for this date picker instance (anonymous) */
8045 _attachDatepicker: function(target, settings) {
8046 // check for settings on the control itself - in namespace 'date:'
8047 var inlineSettings = null;
8048 for (var attrName in this._defaults) {
8049 var attrValue = target.getAttribute('date:' + attrName);
8051 inlineSettings = inlineSettings || {};
8053 inlineSettings[attrName] = eval(attrValue);
8055 inlineSettings[attrName] = attrValue;
8059 var nodeName = target.nodeName.toLowerCase();
8060 var inline = (nodeName == 'div' || nodeName == 'span');
8063 target.id = 'dp' + this.uuid;
8065 var inst = this._newInst($(target), inline);
8066 inst.settings = $.extend({}, settings || {}, inlineSettings || {});
8067 if (nodeName == 'input') {
8068 this._connectDatepicker(target, inst);
8069 } else if (inline) {
8070 this._inlineDatepicker(target, inst);
8074 /* Create a new instance object. */
8075 _newInst: function(target, inline) {
8076 var id = target[0].id.replace(/([^A-Za-z0-9_])/g, '\\\\$1'); // escape jQuery meta chars
8077 return {id: id, input: target, // associated target
8078 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
8079 drawMonth: 0, drawYear: 0, // month being drawn
8080 inline: inline, // is datepicker inline or not
8081 dpDiv: (!inline ? this.dpDiv : // presentation div
8082 $('<div class="' + this._inlineClass + ' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))};
8085 /* Attach the date picker to an input field. */
8086 _connectDatepicker: function(target, inst) {
8087 var input = $(target);
8088 inst.append = $([]);
8089 inst.trigger = $([]);
8090 if (input.hasClass(this.markerClassName))
8092 this._attachments(input, inst);
8093 input.addClass(this.markerClassName).keydown(this._doKeyDown).
8094 keypress(this._doKeyPress).keyup(this._doKeyUp).
8095 bind("setData.datepicker", function(event, key, value) {
8096 inst.settings[key] = value;
8097 }).bind("getData.datepicker", function(event, key) {
8098 return this._get(inst, key);
8100 this._autoSize(inst);
8101 $.data(target, PROP_NAME, inst);
8104 /* Make attachments based on settings. */
8105 _attachments: function(input, inst) {
8106 var appendText = this._get(inst, 'appendText');
8107 var isRTL = this._get(inst, 'isRTL');
8109 inst.append.remove();
8111 inst.append = $('<span class="' + this._appendClass + '">' + appendText + '</span>');
8112 input[isRTL ? 'before' : 'after'](inst.append);
8114 input.unbind('focus', this._showDatepicker);
8116 inst.trigger.remove();
8117 var showOn = this._get(inst, 'showOn');
8118 if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field
8119 input.focus(this._showDatepicker);
8120 if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked
8121 var buttonText = this._get(inst, 'buttonText');
8122 var buttonImage = this._get(inst, 'buttonImage');
8123 inst.trigger = $(this._get(inst, 'buttonImageOnly') ?
8124 $('<img/>').addClass(this._triggerClass).
8125 attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
8126 $('<button type="button"></button>').addClass(this._triggerClass).
8127 html(buttonImage == '' ? buttonText : $('<img/>').attr(
8128 { src:buttonImage, alt:buttonText, title:buttonText })));
8129 input[isRTL ? 'before' : 'after'](inst.trigger);
8130 inst.trigger.click(function() {
8131 if ($.datepicker._datepickerShowing && $.datepicker._lastInput == input[0])
8132 $.datepicker._hideDatepicker();
8134 $.datepicker._showDatepicker(input[0]);
8140 /* Apply the maximum length for the date format. */
8141 _autoSize: function(inst) {
8142 if (this._get(inst, 'autoSize') && !inst.inline) {
8143 var date = new Date(2009, 12 - 1, 20); // Ensure double digits
8144 var dateFormat = this._get(inst, 'dateFormat');
8145 if (dateFormat.match(/[DM]/)) {
8146 var findMax = function(names) {
8149 for (var i = 0; i < names.length; i++) {
8150 if (names[i].length > max) {
8151 max = names[i].length;
8157 date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
8158 'monthNames' : 'monthNamesShort'))));
8159 date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
8160 'dayNames' : 'dayNamesShort'))) + 20 - date.getDay());
8162 inst.input.attr('size', this._formatDate(inst, date).length);
8166 /* Attach an inline date picker to a div. */
8167 _inlineDatepicker: function(target, inst) {
8168 var divSpan = $(target);
8169 if (divSpan.hasClass(this.markerClassName))
8171 divSpan.addClass(this.markerClassName).append(inst.dpDiv).
8172 bind("setData.datepicker", function(event, key, value){
8173 inst.settings[key] = value;
8174 }).bind("getData.datepicker", function(event, key){
8175 return this._get(inst, key);
8177 $.data(target, PROP_NAME, inst);
8178 this._setDate(inst, this._getDefaultDate(inst), true);
8179 this._updateDatepicker(inst);
8180 this._updateAlternate(inst);
8183 /* Pop-up the date picker in a "dialog" box.
8184 @param input element - ignored
8185 @param date string or Date - the initial date to display
8186 @param onSelect function - the function to call when a date is selected
8187 @param settings object - update the dialog date picker instance's settings (anonymous object)
8188 @param pos int[2] - coordinates for the dialog's position within the screen or
8189 event - with x/y coordinates or
8190 leave empty for default (screen centre)
8191 @return the manager object */
8192 _dialogDatepicker: function(input, date, onSelect, settings, pos) {
8193 var inst = this._dialogInst; // internal instance
8196 var id = 'dp' + this.uuid;
8197 this._dialogInput = $('<input type="text" id="' + id +
8198 '" style="position: absolute; top: -100px; width: 0px; z-index: -10;"/>');
8199 this._dialogInput.keydown(this._doKeyDown);
8200 $('body').append(this._dialogInput);
8201 inst = this._dialogInst = this._newInst(this._dialogInput, false);
8203 $.data(this._dialogInput[0], PROP_NAME, inst);
8205 extendRemove(inst.settings, settings || {});
8206 date = (date && date.constructor == Date ? this._formatDate(inst, date) : date);
8207 this._dialogInput.val(date);
8209 this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
8211 var browserWidth = document.documentElement.clientWidth;
8212 var browserHeight = document.documentElement.clientHeight;
8213 var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
8214 var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
8215 this._pos = // should use actual width/height below
8216 [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
8219 // move input on screen for focus, but hidden behind dialog
8220 this._dialogInput.css('left', (this._pos[0] + 20) + 'px').css('top', this._pos[1] + 'px');
8221 inst.settings.onSelect = onSelect;
8222 this._inDialog = true;
8223 this.dpDiv.addClass(this._dialogClass);
8224 this._showDatepicker(this._dialogInput[0]);
8226 $.blockUI(this.dpDiv);
8227 $.data(this._dialogInput[0], PROP_NAME, inst);
8231 /* Detach a datepicker from its control.
8232 @param target element - the target input field or division or span */
8233 _destroyDatepicker: function(target) {
8234 var $target = $(target);
8235 var inst = $.data(target, PROP_NAME);
8236 if (!$target.hasClass(this.markerClassName)) {
8239 var nodeName = target.nodeName.toLowerCase();
8240 $.removeData(target, PROP_NAME);
8241 if (nodeName == 'input') {
8242 inst.append.remove();
8243 inst.trigger.remove();
8244 $target.removeClass(this.markerClassName).
8245 unbind('focus', this._showDatepicker).
8246 unbind('keydown', this._doKeyDown).
8247 unbind('keypress', this._doKeyPress).
8248 unbind('keyup', this._doKeyUp);
8249 } else if (nodeName == 'div' || nodeName == 'span')
8250 $target.removeClass(this.markerClassName).empty();
8253 /* Enable the date picker to a jQuery selection.
8254 @param target element - the target input field or division or span */
8255 _enableDatepicker: function(target) {
8256 var $target = $(target);
8257 var inst = $.data(target, PROP_NAME);
8258 if (!$target.hasClass(this.markerClassName)) {
8261 var nodeName = target.nodeName.toLowerCase();
8262 if (nodeName == 'input') {
8263 target.disabled = false;
8264 inst.trigger.filter('button').
8265 each(function() { this.disabled = false; }).end().
8266 filter('img').css({opacity: '1.0', cursor: ''});
8268 else if (nodeName == 'div' || nodeName == 'span') {
8269 var inline = $target.children('.' + this._inlineClass);
8270 inline.children().removeClass('ui-state-disabled');
8272 this._disabledInputs = $.map(this._disabledInputs,
8273 function(value) { return (value == target ? null : value); }); // delete entry
8276 /* Disable the date picker to a jQuery selection.
8277 @param target element - the target input field or division or span */
8278 _disableDatepicker: function(target) {
8279 var $target = $(target);
8280 var inst = $.data(target, PROP_NAME);
8281 if (!$target.hasClass(this.markerClassName)) {
8284 var nodeName = target.nodeName.toLowerCase();
8285 if (nodeName == 'input') {
8286 target.disabled = true;
8287 inst.trigger.filter('button').
8288 each(function() { this.disabled = true; }).end().
8289 filter('img').css({opacity: '0.5', cursor: 'default'});
8291 else if (nodeName == 'div' || nodeName == 'span') {
8292 var inline = $target.children('.' + this._inlineClass);
8293 inline.children().addClass('ui-state-disabled');
8295 this._disabledInputs = $.map(this._disabledInputs,
8296 function(value) { return (value == target ? null : value); }); // delete entry
8297 this._disabledInputs[this._disabledInputs.length] = target;
8300 /* Is the first field in a jQuery collection disabled as a datepicker?
8301 @param target element - the target input field or division or span
8302 @return boolean - true if disabled, false if enabled */
8303 _isDisabledDatepicker: function(target) {
8307 for (var i = 0; i < this._disabledInputs.length; i++) {
8308 if (this._disabledInputs[i] == target)
8314 /* Retrieve the instance data for the target control.
8315 @param target element - the target input field or division or span
8316 @return object - the associated instance data
8317 @throws error if a jQuery problem getting data */
8318 _getInst: function(target) {
8320 return $.data(target, PROP_NAME);
8323 throw 'Missing instance data for this datepicker';
8327 /* Update or retrieve the settings for a date picker attached to an input field or division.
8328 @param target element - the target input field or division or span
8329 @param name object - the new settings to update or
8330 string - the name of the setting to change or retrieve,
8331 when retrieving also 'all' for all instance settings or
8332 'defaults' for all global defaults
8333 @param value any - the new value for the setting
8334 (omit if above is an object or to retrieve a value) */
8335 _optionDatepicker: function(target, name, value) {
8336 var inst = this._getInst(target);
8337 if (arguments.length == 2 && typeof name == 'string') {
8338 return (name == 'defaults' ? $.extend({}, $.datepicker._defaults) :
8339 (inst ? (name == 'all' ? $.extend({}, inst.settings) :
8340 this._get(inst, name)) : null));
8342 var settings = name || {};
8343 if (typeof name == 'string') {
8345 settings[name] = value;
8348 if (this._curInst == inst) {
8349 this._hideDatepicker();
8351 var date = this._getDateDatepicker(target, true);
8352 extendRemove(inst.settings, settings);
8353 this._attachments($(target), inst);
8354 this._autoSize(inst);
8355 this._setDateDatepicker(target, date);
8356 this._updateDatepicker(inst);
8360 // change method deprecated
8361 _changeDatepicker: function(target, name, value) {
8362 this._optionDatepicker(target, name, value);
8365 /* Redraw the date picker attached to an input field or division.
8366 @param target element - the target input field or division or span */
8367 _refreshDatepicker: function(target) {
8368 var inst = this._getInst(target);
8370 this._updateDatepicker(inst);
8374 /* Set the dates for a jQuery selection.
8375 @param target element - the target input field or division or span
8376 @param date Date - the new date */
8377 _setDateDatepicker: function(target, date) {
8378 var inst = this._getInst(target);
8380 this._setDate(inst, date);
8381 this._updateDatepicker(inst);
8382 this._updateAlternate(inst);
8386 /* Get the date(s) for the first entry in a jQuery selection.
8387 @param target element - the target input field or division or span
8388 @param noDefault boolean - true if no default date is to be used
8389 @return Date - the current date */
8390 _getDateDatepicker: function(target, noDefault) {
8391 var inst = this._getInst(target);
8392 if (inst && !inst.inline)
8393 this._setDateFromField(inst, noDefault);
8394 return (inst ? this._getDate(inst) : null);
8397 /* Handle keystrokes. */
8398 _doKeyDown: function(event) {
8399 var inst = $.datepicker._getInst(event.target);
8401 var isRTL = inst.dpDiv.is('.ui-datepicker-rtl');
8402 inst._keyEvent = true;
8403 if ($.datepicker._datepickerShowing)
8404 switch (event.keyCode) {
8405 case 9: $.datepicker._hideDatepicker();
8407 break; // hide on tab out
8408 case 13: var sel = $('td.' + $.datepicker._dayOverClass, inst.dpDiv).
8409 add($('td.' + $.datepicker._currentClass, inst.dpDiv));
8411 $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
8413 $.datepicker._hideDatepicker();
8414 return false; // don't submit the form
8415 break; // select the value on enter
8416 case 27: $.datepicker._hideDatepicker();
8417 break; // hide on escape
8418 case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
8419 -$.datepicker._get(inst, 'stepBigMonths') :
8420 -$.datepicker._get(inst, 'stepMonths')), 'M');
8421 break; // previous month/year on page up/+ ctrl
8422 case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
8423 +$.datepicker._get(inst, 'stepBigMonths') :
8424 +$.datepicker._get(inst, 'stepMonths')), 'M');
8425 break; // next month/year on page down/+ ctrl
8426 case 35: if (event.ctrlKey || event.metaKey) $.datepicker._clearDate(event.target);
8427 handled = event.ctrlKey || event.metaKey;
8428 break; // clear on ctrl or command +end
8429 case 36: if (event.ctrlKey || event.metaKey) $.datepicker._gotoToday(event.target);
8430 handled = event.ctrlKey || event.metaKey;
8431 break; // current on ctrl or command +home
8432 case 37: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), 'D');
8433 handled = event.ctrlKey || event.metaKey;
8434 // -1 day on ctrl or command +left
8435 if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ?
8436 -$.datepicker._get(inst, 'stepBigMonths') :
8437 -$.datepicker._get(inst, 'stepMonths')), 'M');
8438 // next month/year on alt +left on Mac
8440 case 38: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, -7, 'D');
8441 handled = event.ctrlKey || event.metaKey;
8442 break; // -1 week on ctrl or command +up
8443 case 39: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), 'D');
8444 handled = event.ctrlKey || event.metaKey;
8445 // +1 day on ctrl or command +right
8446 if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ?
8447 +$.datepicker._get(inst, 'stepBigMonths') :
8448 +$.datepicker._get(inst, 'stepMonths')), 'M');
8449 // next month/year on alt +right
8451 case 40: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, +7, 'D');
8452 handled = event.ctrlKey || event.metaKey;
8453 break; // +1 week on ctrl or command +down
8454 default: handled = false;
8456 else if (event.keyCode == 36 && event.ctrlKey) // display the date picker on ctrl+home
8457 $.datepicker._showDatepicker(this);
8462 event.preventDefault();
8463 event.stopPropagation();
8467 /* Filter entered characters - based on date format. */
8468 _doKeyPress: function(event) {
8469 var inst = $.datepicker._getInst(event.target);
8470 if ($.datepicker._get(inst, 'constrainInput')) {
8471 var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat'));
8472 var chr = String.fromCharCode(event.charCode == undefined ? event.keyCode : event.charCode);
8473 return event.ctrlKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1);
8477 /* Synchronise manual entry and field/alternate field. */
8478 _doKeyUp: function(event) {
8479 var inst = $.datepicker._getInst(event.target);
8480 if (inst.input.val() != inst.lastVal) {
8482 var date = $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'),
8483 (inst.input ? inst.input.val() : null),
8484 $.datepicker._getFormatConfig(inst));
8485 if (date) { // only if valid
8486 $.datepicker._setDateFromField(inst);
8487 $.datepicker._updateAlternate(inst);
8488 $.datepicker._updateDatepicker(inst);
8492 $.datepicker.log(event);
8498 /* Pop-up the date picker for a given input field.
8499 @param input element - the input field attached to the date picker or
8500 event - if triggered by focus */
8501 _showDatepicker: function(input) {
8502 input = input.target || input;
8503 if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger
8504 input = $('input', input.parentNode)[0];
8505 if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here
8507 var inst = $.datepicker._getInst(input);
8508 if ($.datepicker._curInst && $.datepicker._curInst != inst) {
8509 $.datepicker._curInst.dpDiv.stop(true, true);
8511 var beforeShow = $.datepicker._get(inst, 'beforeShow');
8512 extendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {}));
8513 inst.lastVal = null;
8514 $.datepicker._lastInput = input;
8515 $.datepicker._setDateFromField(inst);
8516 if ($.datepicker._inDialog) // hide cursor
8518 if (!$.datepicker._pos) { // position below input
8519 $.datepicker._pos = $.datepicker._findPos(input);
8520 $.datepicker._pos[1] += input.offsetHeight; // add the height
8522 var isFixed = false;
8523 $(input).parents().each(function() {
8524 isFixed |= $(this).css('position') == 'fixed';
8527 if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled
8528 $.datepicker._pos[0] -= document.documentElement.scrollLeft;
8529 $.datepicker._pos[1] -= document.documentElement.scrollTop;
8531 var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
8532 $.datepicker._pos = null;
8533 // determine sizing offscreen
8534 inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'});
8535 $.datepicker._updateDatepicker(inst);
8536 // fix width for dynamic number of date pickers
8537 // and adjust position before showing
8538 offset = $.datepicker._checkOffset(inst, offset, isFixed);
8539 inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
8540 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none',
8541 left: offset.left + 'px', top: offset.top + 'px'});
8543 var showAnim = $.datepicker._get(inst, 'showAnim');
8544 var duration = $.datepicker._get(inst, 'duration');
8545 var postProcess = function() {
8546 $.datepicker._datepickerShowing = true;
8547 var borders = $.datepicker._getBorders(inst.dpDiv);
8548 inst.dpDiv.find('iframe.ui-datepicker-cover'). // IE6- only
8549 css({left: -borders[0], top: -borders[1],
8550 width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()});
8552 inst.dpDiv.zIndex($(input).zIndex()+1);
8553 if ($.effects && $.effects[showAnim])
8554 inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);
8556 inst.dpDiv[showAnim || 'show']((showAnim ? duration : null), postProcess);
8557 if (!showAnim || !duration)
8559 if (inst.input.is(':visible') && !inst.input.is(':disabled'))
8561 $.datepicker._curInst = inst;
8565 /* Generate the date picker content. */
8566 _updateDatepicker: function(inst) {
8568 var borders = $.datepicker._getBorders(inst.dpDiv);
8569 inst.dpDiv.empty().append(this._generateHTML(inst))
8570 .find('iframe.ui-datepicker-cover') // IE6- only
8571 .css({left: -borders[0], top: -borders[1],
8572 width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()})
8574 .find('button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a')
8575 .bind('mouseout', function(){
8576 $(this).removeClass('ui-state-hover');
8577 if(this.className.indexOf('ui-datepicker-prev') != -1) $(this).removeClass('ui-datepicker-prev-hover');
8578 if(this.className.indexOf('ui-datepicker-next') != -1) $(this).removeClass('ui-datepicker-next-hover');
8580 .bind('mouseover', function(){
8581 if (!self._isDisabledDatepicker( inst.inline ? inst.dpDiv.parent()[0] : inst.input[0])) {
8582 $(this).parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover');
8583 $(this).addClass('ui-state-hover');
8584 if(this.className.indexOf('ui-datepicker-prev') != -1) $(this).addClass('ui-datepicker-prev-hover');
8585 if(this.className.indexOf('ui-datepicker-next') != -1) $(this).addClass('ui-datepicker-next-hover');
8589 .find('.' + this._dayOverClass + ' a')
8590 .trigger('mouseover')
8592 var numMonths = this._getNumberOfMonths(inst);
8593 var cols = numMonths[1];
8596 inst.dpDiv.addClass('ui-datepicker-multi-' + cols).css('width', (width * cols) + 'em');
8598 inst.dpDiv.removeClass('ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4').width('');
8599 inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') +
8600 'Class']('ui-datepicker-multi');
8601 inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') +
8602 'Class']('ui-datepicker-rtl');
8603 if (inst == $.datepicker._curInst && $.datepicker._datepickerShowing && inst.input &&
8604 inst.input.is(':visible') && !inst.input.is(':disabled'))
8608 /* Retrieve the size of left and top borders for an element.
8609 @param elem (jQuery object) the element of interest
8610 @return (number[2]) the left and top borders */
8611 _getBorders: function(elem) {
8612 var convert = function(value) {
8613 return {thin: 1, medium: 2, thick: 3}[value] || value;
8615 return [parseFloat(convert(elem.css('border-left-width'))),
8616 parseFloat(convert(elem.css('border-top-width')))];
8619 /* Check positioning to remain on screen. */
8620 _checkOffset: function(inst, offset, isFixed) {
8621 var dpWidth = inst.dpDiv.outerWidth();
8622 var dpHeight = inst.dpDiv.outerHeight();
8623 var inputWidth = inst.input ? inst.input.outerWidth() : 0;
8624 var inputHeight = inst.input ? inst.input.outerHeight() : 0;
8625 var viewWidth = document.documentElement.clientWidth + $(document).scrollLeft();
8626 var viewHeight = document.documentElement.clientHeight + $(document).scrollTop();
8628 offset.left -= (this._get(inst, 'isRTL') ? (dpWidth - inputWidth) : 0);
8629 offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0;
8630 offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
8632 // now check if datepicker is showing outside window viewport - move to a better place if so.
8633 offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
8634 Math.abs(offset.left + dpWidth - viewWidth) : 0);
8635 offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
8636 Math.abs(dpHeight + inputHeight) : 0);
8641 /* Find an object's position on the screen. */
8642 _findPos: function(obj) {
8643 var inst = this._getInst(obj);
8644 var isRTL = this._get(inst, 'isRTL');
8645 while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) {
8646 obj = obj[isRTL ? 'previousSibling' : 'nextSibling'];
8648 var position = $(obj).offset();
8649 return [position.left, position.top];
8652 /* Hide the date picker from view.
8653 @param input element - the input field attached to the date picker */
8654 _hideDatepicker: function(input) {
8655 var inst = this._curInst;
8656 if (!inst || (input && inst != $.data(input, PROP_NAME)))
8658 if (this._datepickerShowing) {
8659 var showAnim = this._get(inst, 'showAnim');
8660 var duration = this._get(inst, 'duration');
8661 var postProcess = function() {
8662 $.datepicker._tidyDialog(inst);
8663 this._curInst = null;
8665 if ($.effects && $.effects[showAnim])
8666 inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);
8668 inst.dpDiv[(showAnim == 'slideDown' ? 'slideUp' :
8669 (showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))]((showAnim ? duration : null), postProcess);
8672 var onClose = this._get(inst, 'onClose');
8674 onClose.apply((inst.input ? inst.input[0] : null),
8675 [(inst.input ? inst.input.val() : ''), inst]); // trigger custom callback
8676 this._datepickerShowing = false;
8677 this._lastInput = null;
8678 if (this._inDialog) {
8679 this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' });
8682 $('body').append(this.dpDiv);
8685 this._inDialog = false;
8689 /* Tidy up after a dialog display. */
8690 _tidyDialog: function(inst) {
8691 inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker-calendar');
8694 /* Close date picker if clicked elsewhere. */
8695 _checkExternalClick: function(event) {
8696 if (!$.datepicker._curInst)
8698 var $target = $(event.target);
8699 if ($target[0].id != $.datepicker._mainDivId &&
8700 $target.parents('#' + $.datepicker._mainDivId).length == 0 &&
8701 !$target.hasClass($.datepicker.markerClassName) &&
8702 !$target.hasClass($.datepicker._triggerClass) &&
8703 $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI))
8704 $.datepicker._hideDatepicker();
8707 /* Adjust one of the date sub-fields. */
8708 _adjustDate: function(id, offset, period) {
8710 var inst = this._getInst(target[0]);
8711 if (this._isDisabledDatepicker(target[0])) {
8714 this._adjustInstDate(inst, offset +
8715 (period == 'M' ? this._get(inst, 'showCurrentAtPos') : 0), // undo positioning
8717 this._updateDatepicker(inst);
8720 /* Action for current link. */
8721 _gotoToday: function(id) {
8723 var inst = this._getInst(target[0]);
8724 if (this._get(inst, 'gotoCurrent') && inst.currentDay) {
8725 inst.selectedDay = inst.currentDay;
8726 inst.drawMonth = inst.selectedMonth = inst.currentMonth;
8727 inst.drawYear = inst.selectedYear = inst.currentYear;
8730 var date = new Date();
8731 inst.selectedDay = date.getDate();
8732 inst.drawMonth = inst.selectedMonth = date.getMonth();
8733 inst.drawYear = inst.selectedYear = date.getFullYear();
8735 this._notifyChange(inst);
8736 this._adjustDate(target);
8739 /* Action for selecting a new month/year. */
8740 _selectMonthYear: function(id, select, period) {
8742 var inst = this._getInst(target[0]);
8743 inst._selectingMonthYear = false;
8744 inst['selected' + (period == 'M' ? 'Month' : 'Year')] =
8745 inst['draw' + (period == 'M' ? 'Month' : 'Year')] =
8746 parseInt(select.options[select.selectedIndex].value,10);
8747 this._notifyChange(inst);
8748 this._adjustDate(target);
8751 /* Restore input focus after not changing month/year. */
8752 _clickMonthYear: function(id) {
8754 var inst = this._getInst(target[0]);
8755 if (inst.input && inst._selectingMonthYear) {
8756 setTimeout(function() {
8760 inst._selectingMonthYear = !inst._selectingMonthYear;
8763 /* Action for selecting a day. */
8764 _selectDay: function(id, month, year, td) {
8766 if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
8769 var inst = this._getInst(target[0]);
8770 inst.selectedDay = inst.currentDay = $('a', td).html();
8771 inst.selectedMonth = inst.currentMonth = month;
8772 inst.selectedYear = inst.currentYear = year;
8773 this._selectDate(id, this._formatDate(inst,
8774 inst.currentDay, inst.currentMonth, inst.currentYear));
8777 /* Erase the input field and hide the date picker. */
8778 _clearDate: function(id) {
8780 var inst = this._getInst(target[0]);
8781 this._selectDate(target, '');
8784 /* Update the input field with the selected date. */
8785 _selectDate: function(id, dateStr) {
8787 var inst = this._getInst(target[0]);
8788 dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
8790 inst.input.val(dateStr);
8791 this._updateAlternate(inst);
8792 var onSelect = this._get(inst, 'onSelect');
8794 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
8795 else if (inst.input)
8796 inst.input.trigger('change'); // fire the change event
8798 this._updateDatepicker(inst);
8800 this._hideDatepicker();
8801 this._lastInput = inst.input[0];
8802 if (typeof(inst.input[0]) != 'object')
8803 inst.input.focus(); // restore focus
8804 this._lastInput = null;
8808 /* Update any alternate field to synchronise with the main field. */
8809 _updateAlternate: function(inst) {
8810 var altField = this._get(inst, 'altField');
8811 if (altField) { // update alternate field too
8812 var altFormat = this._get(inst, 'altFormat') || this._get(inst, 'dateFormat');
8813 var date = this._getDate(inst);
8814 var dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
8815 $(altField).each(function() { $(this).val(dateStr); });
8819 /* Set as beforeShowDay function to prevent selection of weekends.
8820 @param date Date - the date to customise
8821 @return [boolean, string] - is this date selectable?, what is its CSS class? */
8822 noWeekends: function(date) {
8823 var day = date.getDay();
8824 return [(day > 0 && day < 6), ''];
8827 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
8828 @param date Date - the date to get the week for
8829 @return number - the number of the week within the year that contains this date */
8830 iso8601Week: function(date) {
8831 var checkDate = new Date(date.getTime());
8832 // Find Thursday of this week starting on Monday
8833 checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
8834 var time = checkDate.getTime();
8835 checkDate.setMonth(0); // Compare with Jan 1
8836 checkDate.setDate(1);
8837 return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
8840 /* Parse a string value into a date object.
8841 See formatDate below for the possible formats.
8843 @param format string - the expected format of the date
8844 @param value string - the date in the above format
8845 @param settings Object - attributes include:
8846 shortYearCutoff number - the cutoff year for determining the century (optional)
8847 dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
8848 dayNames string[7] - names of the days from Sunday (optional)
8849 monthNamesShort string[12] - abbreviated names of the months (optional)
8850 monthNames string[12] - names of the months (optional)
8851 @return Date - the extracted date value or null if value is blank */
8852 parseDate: function (format, value, settings) {
8853 if (format == null || value == null)
8854 throw 'Invalid arguments';
8855 value = (typeof value == 'object' ? value.toString() : value + '');
8858 var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff;
8859 var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
8860 var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
8861 var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
8862 var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
8867 var literal = false;
8868 // Check whether a format character is doubled
8869 var lookAhead = function(match) {
8870 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
8875 // Extract a number from the string value
8876 var getNumber = function(match) {
8878 var size = (match == '@' ? 14 : (match == '!' ? 20 :
8879 (match == 'y' ? 4 : (match == 'o' ? 3 : 2))));
8880 var digits = new RegExp('^\\d{1,' + size + '}');
8881 var num = value.substring(iValue).match(digits);
8883 throw 'Missing number at position ' + iValue;
8884 iValue += num[0].length;
8885 return parseInt(num[0], 10);
8887 // Extract a name from the string value and convert to an index
8888 var getName = function(match, shortNames, longNames) {
8889 var names = (lookAhead(match) ? longNames : shortNames);
8890 for (var i = 0; i < names.length; i++) {
8891 if (value.substr(iValue, names[i].length) == names[i]) {
8892 iValue += names[i].length;
8896 throw 'Unknown name at position ' + iValue;
8898 // Confirm that a literal character matches the string value
8899 var checkLiteral = function() {
8900 if (value.charAt(iValue) != format.charAt(iFormat))
8901 throw 'Unexpected literal at position ' + iValue;
8905 for (var iFormat = 0; iFormat < format.length; iFormat++) {
8907 if (format.charAt(iFormat) == "'" && !lookAhead("'"))
8912 switch (format.charAt(iFormat)) {
8914 day = getNumber('d');
8917 getName('D', dayNamesShort, dayNames);
8920 doy = getNumber('o');
8923 month = getNumber('m');
8926 month = getName('M', monthNamesShort, monthNames);
8929 year = getNumber('y');
8932 var date = new Date(getNumber('@'));
8933 year = date.getFullYear();
8934 month = date.getMonth() + 1;
8935 day = date.getDate();
8938 var date = new Date((getNumber('!') - this._ticksTo1970) / 10000);
8939 year = date.getFullYear();
8940 month = date.getMonth() + 1;
8941 day = date.getDate();
8954 year = new Date().getFullYear();
8955 else if (year < 100)
8956 year += new Date().getFullYear() - new Date().getFullYear() % 100 +
8957 (year <= shortYearCutoff ? 0 : -100);
8962 var dim = this._getDaysInMonth(year, month - 1);
8969 var date = this._daylightSavingAdjust(new Date(year, month - 1, day));
8970 if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day)
8971 throw 'Invalid date'; // E.g. 31/02/*
8975 /* Standard date formats. */
8976 ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601)
8977 COOKIE: 'D, dd M yy',
8978 ISO_8601: 'yy-mm-dd',
8979 RFC_822: 'D, d M y',
8980 RFC_850: 'DD, dd-M-y',
8981 RFC_1036: 'D, d M y',
8982 RFC_1123: 'D, d M yy',
8983 RFC_2822: 'D, d M yy',
8984 RSS: 'D, d M y', // RFC 822
8987 W3C: 'yy-mm-dd', // ISO 8601
8989 _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
8990 Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
8992 /* Format a date object into a string value.
8993 The format can be combinations of the following:
8994 d - day of month (no leading zero)
8995 dd - day of month (two digit)
8996 o - day of year (no leading zeros)
8997 oo - day of year (three digit)
9000 m - month of year (no leading zero)
9001 mm - month of year (two digit)
9002 M - month name short
9003 MM - month name long
9004 y - year (two digit)
9005 yy - year (four digit)
9006 @ - Unix timestamp (ms since 01/01/1970)
9007 ! - Windows ticks (100ns since 01/01/0001)
9008 '...' - literal text
9011 @param format string - the desired format of the date
9012 @param date Date - the date value to format
9013 @param settings Object - attributes include:
9014 dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
9015 dayNames string[7] - names of the days from Sunday (optional)
9016 monthNamesShort string[12] - abbreviated names of the months (optional)
9017 monthNames string[12] - names of the months (optional)
9018 @return string - the date in the above format */
9019 formatDate: function (format, date, settings) {
9022 var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
9023 var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
9024 var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
9025 var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
9026 // Check whether a format character is doubled
9027 var lookAhead = function(match) {
9028 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
9033 // Format a number, with leading zero if necessary
9034 var formatNumber = function(match, value, len) {
9035 var num = '' + value;
9036 if (lookAhead(match))
9037 while (num.length < len)
9041 // Format a name, short or long as requested
9042 var formatName = function(match, value, shortNames, longNames) {
9043 return (lookAhead(match) ? longNames[value] : shortNames[value]);
9046 var literal = false;
9048 for (var iFormat = 0; iFormat < format.length; iFormat++) {
9050 if (format.charAt(iFormat) == "'" && !lookAhead("'"))
9053 output += format.charAt(iFormat);
9055 switch (format.charAt(iFormat)) {
9057 output += formatNumber('d', date.getDate(), 2);
9060 output += formatName('D', date.getDay(), dayNamesShort, dayNames);
9063 output += formatNumber('o',
9064 (date.getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000, 3);
9067 output += formatNumber('m', date.getMonth() + 1, 2);
9070 output += formatName('M', date.getMonth(), monthNamesShort, monthNames);
9073 output += (lookAhead('y') ? date.getFullYear() :
9074 (date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100);
9077 output += date.getTime();
9080 output += date.getTime() * 10000 + this._ticksTo1970;
9089 output += format.charAt(iFormat);
9095 /* Extract all possible characters from the date format. */
9096 _possibleChars: function (format) {
9098 var literal = false;
9099 // Check whether a format character is doubled
9100 var lookAhead = function(match) {
9101 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
9106 for (var iFormat = 0; iFormat < format.length; iFormat++)
9108 if (format.charAt(iFormat) == "'" && !lookAhead("'"))
9111 chars += format.charAt(iFormat);
9113 switch (format.charAt(iFormat)) {
9114 case 'd': case 'm': case 'y': case '@':
9115 chars += '0123456789';
9118 return null; // Accept anything
9126 chars += format.charAt(iFormat);
9131 /* Get a setting value, defaulting if necessary. */
9132 _get: function(inst, name) {
9133 return inst.settings[name] !== undefined ?
9134 inst.settings[name] : this._defaults[name];
9137 /* Parse existing date and initialise date picker. */
9138 _setDateFromField: function(inst, noDefault) {
9139 if (inst.input.val() == inst.lastVal) {
9142 var dateFormat = this._get(inst, 'dateFormat');
9143 var dates = inst.lastVal = inst.input ? inst.input.val() : null;
9144 var date, defaultDate;
9145 date = defaultDate = this._getDefaultDate(inst);
9146 var settings = this._getFormatConfig(inst);
9148 date = this.parseDate(dateFormat, dates, settings) || defaultDate;
9151 dates = (noDefault ? '' : dates);
9153 inst.selectedDay = date.getDate();
9154 inst.drawMonth = inst.selectedMonth = date.getMonth();
9155 inst.drawYear = inst.selectedYear = date.getFullYear();
9156 inst.currentDay = (dates ? date.getDate() : 0);
9157 inst.currentMonth = (dates ? date.getMonth() : 0);
9158 inst.currentYear = (dates ? date.getFullYear() : 0);
9159 this._adjustInstDate(inst);
9162 /* Retrieve the default date shown on opening. */
9163 _getDefaultDate: function(inst) {
9164 return this._restrictMinMax(inst,
9165 this._determineDate(inst, this._get(inst, 'defaultDate'), new Date()));
9168 /* A date may be specified as an exact value or a relative one. */
9169 _determineDate: function(inst, date, defaultDate) {
9170 var offsetNumeric = function(offset) {
9171 var date = new Date();
9172 date.setDate(date.getDate() + offset);
9175 var offsetString = function(offset) {
9177 return $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'),
9178 offset, $.datepicker._getFormatConfig(inst));
9183 var date = (offset.toLowerCase().match(/^c/) ?
9184 $.datepicker._getDate(inst) : null) || new Date();
9185 var year = date.getFullYear();
9186 var month = date.getMonth();
9187 var day = date.getDate();
9188 var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g;
9189 var matches = pattern.exec(offset);
9191 switch (matches[2] || 'd') {
9192 case 'd' : case 'D' :
9193 day += parseInt(matches[1],10); break;
9194 case 'w' : case 'W' :
9195 day += parseInt(matches[1],10) * 7; break;
9196 case 'm' : case 'M' :
9197 month += parseInt(matches[1],10);
9198 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
9200 case 'y': case 'Y' :
9201 year += parseInt(matches[1],10);
9202 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
9205 matches = pattern.exec(offset);
9207 return new Date(year, month, day);
9209 date = (date == null ? defaultDate : (typeof date == 'string' ? offsetString(date) :
9210 (typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : date)));
9211 date = (date && date.toString() == 'Invalid Date' ? defaultDate : date);
9216 date.setMilliseconds(0);
9218 return this._daylightSavingAdjust(date);
9221 /* Handle switch to/from daylight saving.
9222 Hours may be non-zero on daylight saving cut-over:
9223 > 12 when midnight changeover, but then cannot generate
9224 midnight datetime, so jump to 1AM, otherwise reset.
9225 @param date (Date) the date to check
9226 @return (Date) the corrected date */
9227 _daylightSavingAdjust: function(date) {
9228 if (!date) return null;
9229 date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
9233 /* Set the date(s) directly. */
9234 _setDate: function(inst, date, noChange) {
9235 var clear = !(date);
9236 var origMonth = inst.selectedMonth;
9237 var origYear = inst.selectedYear;
9238 date = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
9239 inst.selectedDay = inst.currentDay = date.getDate();
9240 inst.drawMonth = inst.selectedMonth = inst.currentMonth = date.getMonth();
9241 inst.drawYear = inst.selectedYear = inst.currentYear = date.getFullYear();
9242 if ((origMonth != inst.selectedMonth || origYear != inst.selectedYear) && !noChange)
9243 this._notifyChange(inst);
9244 this._adjustInstDate(inst);
9246 inst.input.val(clear ? '' : this._formatDate(inst));
9250 /* Retrieve the date(s) directly. */
9251 _getDate: function(inst) {
9252 var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null :
9253 this._daylightSavingAdjust(new Date(
9254 inst.currentYear, inst.currentMonth, inst.currentDay)));
9258 /* Generate the HTML for the current state of the date picker. */
9259 _generateHTML: function(inst) {
9260 var today = new Date();
9261 today = this._daylightSavingAdjust(
9262 new Date(today.getFullYear(), today.getMonth(), today.getDate())); // clear time
9263 var isRTL = this._get(inst, 'isRTL');
9264 var showButtonPanel = this._get(inst, 'showButtonPanel');
9265 var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext');
9266 var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat');
9267 var numMonths = this._getNumberOfMonths(inst);
9268 var showCurrentAtPos = this._get(inst, 'showCurrentAtPos');
9269 var stepMonths = this._get(inst, 'stepMonths');
9270 var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1);
9271 var currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
9272 new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
9273 var minDate = this._getMinMaxDate(inst, 'min');
9274 var maxDate = this._getMinMaxDate(inst, 'max');
9275 var drawMonth = inst.drawMonth - showCurrentAtPos;
9276 var drawYear = inst.drawYear;
9277 if (drawMonth < 0) {
9282 var maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
9283 maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
9284 maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
9285 while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
9287 if (drawMonth < 0) {
9293 inst.drawMonth = drawMonth;
9294 inst.drawYear = drawYear;
9295 var prevText = this._get(inst, 'prevText');
9296 prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
9297 this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
9298 this._getFormatConfig(inst)));
9299 var prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
9300 '<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery_' + dpuuid +
9301 '.datepicker._adjustDate(\'#' + inst.id + '\', -' + stepMonths + ', \'M\');"' +
9302 ' title="' + prevText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'e' : 'w') + '">' + prevText + '</span></a>' :
9303 (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>'));
9304 var nextText = this._get(inst, 'nextText');
9305 nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
9306 this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
9307 this._getFormatConfig(inst)));
9308 var next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
9309 '<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery_' + dpuuid +
9310 '.datepicker._adjustDate(\'#' + inst.id + '\', +' + stepMonths + ', \'M\');"' +
9311 ' title="' + nextText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'w' : 'e') + '">' + nextText + '</span></a>' :
9312 (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>'));
9313 var currentText = this._get(inst, 'currentText');
9314 var gotoDate = (this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today);
9315 currentText = (!navigationAsDateFormat ? currentText :
9316 this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
9317 var controls = (!inst.inline ? '<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery_' + dpuuid +
9318 '.datepicker._hideDatepicker();">' + this._get(inst, 'closeText') + '</button>' : '');
9319 var buttonPanel = (showButtonPanel) ? '<div class="ui-datepicker-buttonpane ui-widget-content">' + (isRTL ? controls : '') +
9320 (this._isInRange(inst, gotoDate) ? '<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery_' + dpuuid +
9321 '.datepicker._gotoToday(\'#' + inst.id + '\');"' +
9322 '>' + currentText + '</button>' : '') + (isRTL ? '' : controls) + '</div>' : '';
9323 var firstDay = parseInt(this._get(inst, 'firstDay'),10);
9324 firstDay = (isNaN(firstDay) ? 0 : firstDay);
9325 var showWeek = this._get(inst, 'showWeek');
9326 var dayNames = this._get(inst, 'dayNames');
9327 var dayNamesShort = this._get(inst, 'dayNamesShort');
9328 var dayNamesMin = this._get(inst, 'dayNamesMin');
9329 var monthNames = this._get(inst, 'monthNames');
9330 var monthNamesShort = this._get(inst, 'monthNamesShort');
9331 var beforeShowDay = this._get(inst, 'beforeShowDay');
9332 var showOtherMonths = this._get(inst, 'showOtherMonths');
9333 var selectOtherMonths = this._get(inst, 'selectOtherMonths');
9334 var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week;
9335 var defaultDate = this._getDefaultDate(inst);
9337 for (var row = 0; row < numMonths[0]; row++) {
9339 for (var col = 0; col < numMonths[1]; col++) {
9340 var selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
9341 var cornerClass = ' ui-corner-all';
9344 calender += '<div class="ui-datepicker-group';
9345 if (numMonths[1] > 1)
9347 case 0: calender += ' ui-datepicker-group-first';
9348 cornerClass = ' ui-corner-' + (isRTL ? 'right' : 'left'); break;
9349 case numMonths[1]-1: calender += ' ui-datepicker-group-last';
9350 cornerClass = ' ui-corner-' + (isRTL ? 'left' : 'right'); break;
9351 default: calender += ' ui-datepicker-group-middle'; cornerClass = ''; break;
9355 calender += '<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix' + cornerClass + '">' +
9356 (/all|left/.test(cornerClass) && row == 0 ? (isRTL ? next : prev) : '') +
9357 (/all|right/.test(cornerClass) && row == 0 ? (isRTL ? prev : next) : '') +
9358 this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
9359 row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
9360 '</div><table class="ui-datepicker-calendar"><thead>' +
9362 var thead = (showWeek ? '<th class="ui-datepicker-week-col">' + this._get(inst, 'weekHeader') + '</th>' : '');
9363 for (var dow = 0; dow < 7; dow++) { // days of the week
9364 var day = (dow + firstDay) % 7;
9365 thead += '<th' + ((dow + firstDay + 6) % 7 >= 5 ? ' class="ui-datepicker-week-end"' : '') + '>' +
9366 '<span title="' + dayNames[day] + '">' + dayNamesMin[day] + '</span></th>';
9368 calender += thead + '</tr></thead><tbody>';
9369 var daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
9370 if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth)
9371 inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
9372 var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
9373 var numRows = (isMultiMonth ? 6 : Math.ceil((leadDays + daysInMonth) / 7)); // calculate the number of rows to generate
9374 var printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
9375 for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows
9377 var tbody = (!showWeek ? '' : '<td class="ui-datepicker-week-col">' +
9378 this._get(inst, 'calculateWeek')(printDate) + '</td>');
9379 for (var dow = 0; dow < 7; dow++) { // create date picker days
9380 var daySettings = (beforeShowDay ?
9381 beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']);
9382 var otherMonth = (printDate.getMonth() != drawMonth);
9383 var unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
9384 (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
9385 tbody += '<td class="' +
9386 ((dow + firstDay + 6) % 7 >= 5 ? ' ui-datepicker-week-end' : '') + // highlight weekends
9387 (otherMonth ? ' ui-datepicker-other-month' : '') + // highlight days from other months
9388 ((printDate.getTime() == selectedDate.getTime() && drawMonth == inst.selectedMonth && inst._keyEvent) || // user pressed key
9389 (defaultDate.getTime() == printDate.getTime() && defaultDate.getTime() == selectedDate.getTime()) ?
9390 // or defaultDate is current printedDate and defaultDate is selectedDate
9391 ' ' + this._dayOverClass : '') + // highlight selected day
9392 (unselectable ? ' ' + this._unselectableClass + ' ui-state-disabled': '') + // highlight unselectable days
9393 (otherMonth && !showOtherMonths ? '' : ' ' + daySettings[1] + // highlight custom dates
9394 (printDate.getTime() == currentDate.getTime() ? ' ' + this._currentClass : '') + // highlight selected day
9395 (printDate.getTime() == today.getTime() ? ' ui-datepicker-today' : '')) + '"' + // highlight today (if different)
9396 ((!otherMonth || showOtherMonths) && daySettings[2] ? ' title="' + daySettings[2] + '"' : '') + // cell title
9397 (unselectable ? '' : ' onclick="DP_jQuery_' + dpuuid + '.datepicker._selectDay(\'#' +
9398 inst.id + '\',' + printDate.getMonth() + ',' + printDate.getFullYear() + ', this);return false;"') + '>' + // actions
9399 (otherMonth && !showOtherMonths ? ' ' : // display for other months
9400 (unselectable ? '<span class="ui-state-default">' + printDate.getDate() + '</span>' : '<a class="ui-state-default' +
9401 (printDate.getTime() == today.getTime() ? ' ui-state-highlight' : '') +
9402 (printDate.getTime() == selectedDate.getTime() ? ' ui-state-active' : '') + // highlight selected day
9403 (otherMonth ? ' ui-priority-secondary' : '') + // distinguish dates from other months
9404 '" href="#">' + printDate.getDate() + '</a>')) + '</td>'; // display selectable date
9405 printDate.setDate(printDate.getDate() + 1);
9406 printDate = this._daylightSavingAdjust(printDate);
9408 calender += tbody + '</tr>';
9411 if (drawMonth > 11) {
9415 calender += '</tbody></table>' + (isMultiMonth ? '</div>' +
9416 ((numMonths[0] > 0 && col == numMonths[1]-1) ? '<div class="ui-datepicker-row-break"></div>' : '') : '');
9421 html += buttonPanel + ($.browser.msie && parseInt($.browser.version,10) < 7 && !inst.inline ?
9422 '<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>' : '');
9423 inst._keyEvent = false;
9427 /* Generate the month and year header. */
9428 _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
9429 secondary, monthNames, monthNamesShort) {
9430 var changeMonth = this._get(inst, 'changeMonth');
9431 var changeYear = this._get(inst, 'changeYear');
9432 var showMonthAfterYear = this._get(inst, 'showMonthAfterYear');
9433 var html = '<div class="ui-datepicker-title">';
9436 if (secondary || !changeMonth)
9437 monthHtml += '<span class="ui-datepicker-month">' + monthNames[drawMonth] + '</span>';
9439 var inMinYear = (minDate && minDate.getFullYear() == drawYear);
9440 var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear);
9441 monthHtml += '<select class="ui-datepicker-month" ' +
9442 'onchange="DP_jQuery_' + dpuuid + '.datepicker._selectMonthYear(\'#' + inst.id + '\', this, \'M\');" ' +
9443 'onclick="DP_jQuery_' + dpuuid + '.datepicker._clickMonthYear(\'#' + inst.id + '\');"' +
9445 for (var month = 0; month < 12; month++) {
9446 if ((!inMinYear || month >= minDate.getMonth()) &&
9447 (!inMaxYear || month <= maxDate.getMonth()))
9448 monthHtml += '<option value="' + month + '"' +
9449 (month == drawMonth ? ' selected="selected"' : '') +
9450 '>' + monthNamesShort[month] + '</option>';
9452 monthHtml += '</select>';
9454 if (!showMonthAfterYear)
9455 html += monthHtml + (secondary || !(changeMonth && changeYear) ? ' ' : '');
9457 if (secondary || !changeYear)
9458 html += '<span class="ui-datepicker-year">' + drawYear + '</span>';
9460 // determine range of years to display
9461 var years = this._get(inst, 'yearRange').split(':');
9462 var thisYear = new Date().getFullYear();
9463 var determineYear = function(value) {
9464 var year = (value.match(/c[+-].*/) ? drawYear + parseInt(value.substring(1), 10) :
9465 (value.match(/[+-].*/) ? thisYear + parseInt(value, 10) :
9466 parseInt(value, 10)));
9467 return (isNaN(year) ? thisYear : year);
9469 var year = determineYear(years[0]);
9470 var endYear = Math.max(year, determineYear(years[1] || ''));
9471 year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
9472 endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
9473 html += '<select class="ui-datepicker-year" ' +
9474 'onchange="DP_jQuery_' + dpuuid + '.datepicker._selectMonthYear(\'#' + inst.id + '\', this, \'Y\');" ' +
9475 'onclick="DP_jQuery_' + dpuuid + '.datepicker._clickMonthYear(\'#' + inst.id + '\');"' +
9477 for (; year <= endYear; year++) {
9478 html += '<option value="' + year + '"' +
9479 (year == drawYear ? ' selected="selected"' : '') +
9480 '>' + year + '</option>';
9482 html += '</select>';
9484 html += this._get(inst, 'yearSuffix');
9485 if (showMonthAfterYear)
9486 html += (secondary || !(changeMonth && changeYear) ? ' ' : '') + monthHtml;
9487 html += '</div>'; // Close datepicker_header
9491 /* Adjust one of the date sub-fields. */
9492 _adjustInstDate: function(inst, offset, period) {
9493 var year = inst.drawYear + (period == 'Y' ? offset : 0);
9494 var month = inst.drawMonth + (period == 'M' ? offset : 0);
9495 var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) +
9496 (period == 'D' ? offset : 0);
9497 var date = this._restrictMinMax(inst,
9498 this._daylightSavingAdjust(new Date(year, month, day)));
9499 inst.selectedDay = date.getDate();
9500 inst.drawMonth = inst.selectedMonth = date.getMonth();
9501 inst.drawYear = inst.selectedYear = date.getFullYear();
9502 if (period == 'M' || period == 'Y')
9503 this._notifyChange(inst);
9506 /* Ensure a date is within any min/max bounds. */
9507 _restrictMinMax: function(inst, date) {
9508 var minDate = this._getMinMaxDate(inst, 'min');
9509 var maxDate = this._getMinMaxDate(inst, 'max');
9510 date = (minDate && date < minDate ? minDate : date);
9511 date = (maxDate && date > maxDate ? maxDate : date);
9515 /* Notify change of month/year. */
9516 _notifyChange: function(inst) {
9517 var onChange = this._get(inst, 'onChangeMonthYear');
9519 onChange.apply((inst.input ? inst.input[0] : null),
9520 [inst.selectedYear, inst.selectedMonth + 1, inst]);
9523 /* Determine the number of months to show. */
9524 _getNumberOfMonths: function(inst) {
9525 var numMonths = this._get(inst, 'numberOfMonths');
9526 return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths));
9529 /* Determine the current maximum date - ensure no time components are set. */
9530 _getMinMaxDate: function(inst, minMax) {
9531 return this._determineDate(inst, this._get(inst, minMax + 'Date'), null);
9534 /* Find the number of days in a given month. */
9535 _getDaysInMonth: function(year, month) {
9536 return 32 - new Date(year, month, 32).getDate();
9539 /* Find the day of the week of the first of a month. */
9540 _getFirstDayOfMonth: function(year, month) {
9541 return new Date(year, month, 1).getDay();
9544 /* Determines if we should allow a "next/prev" month display change. */
9545 _canAdjustMonth: function(inst, offset, curYear, curMonth) {
9546 var numMonths = this._getNumberOfMonths(inst);
9547 var date = this._daylightSavingAdjust(new Date(curYear,
9548 curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
9550 date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
9551 return this._isInRange(inst, date);
9554 /* Is the given date in the accepted range? */
9555 _isInRange: function(inst, date) {
9556 var minDate = this._getMinMaxDate(inst, 'min');
9557 var maxDate = this._getMinMaxDate(inst, 'max');
9558 return ((!minDate || date.getTime() >= minDate.getTime()) &&
9559 (!maxDate || date.getTime() <= maxDate.getTime()));
9562 /* Provide the configuration settings for formatting/parsing. */
9563 _getFormatConfig: function(inst) {
9564 var shortYearCutoff = this._get(inst, 'shortYearCutoff');
9565 shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff :
9566 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
9567 return {shortYearCutoff: shortYearCutoff,
9568 dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'),
9569 monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')};
9572 /* Format the given date for display. */
9573 _formatDate: function(inst, day, month, year) {
9575 inst.currentDay = inst.selectedDay;
9576 inst.currentMonth = inst.selectedMonth;
9577 inst.currentYear = inst.selectedYear;
9579 var date = (day ? (typeof day == 'object' ? day :
9580 this._daylightSavingAdjust(new Date(year, month, day))) :
9581 this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
9582 return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst));
9586 /* jQuery extend now ignores nulls! */
9587 function extendRemove(target, props) {
9588 $.extend(target, props);
9589 for (var name in props)
9590 if (props[name] == null || props[name] == undefined)
9591 target[name] = props[name];
9595 /* Determine whether an object is an array. */
9596 function isArray(a) {
9597 return (a && (($.browser.safari && typeof a == 'object' && a.length) ||
9598 (a.constructor && a.constructor.toString().match(/\Array\(\)/))));
9601 /* Invoke the datepicker functionality.
9602 @param options string - a command, optionally followed by additional parameters or
9603 Object - settings for attaching new datepicker functionality
9604 @return jQuery object */
9605 $.fn.datepicker = function(options){
9607 /* Initialise the date picker. */
9608 if (!$.datepicker.initialized) {
9609 $(document).mousedown($.datepicker._checkExternalClick).
9610 find('body').append($.datepicker.dpDiv);
9611 $.datepicker.initialized = true;
9614 var otherArgs = Array.prototype.slice.call(arguments, 1);
9615 if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate' || options == 'widget'))
9616 return $.datepicker['_' + options + 'Datepicker'].
9617 apply($.datepicker, [this[0]].concat(otherArgs));
9618 if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string')
9619 return $.datepicker['_' + options + 'Datepicker'].
9620 apply($.datepicker, [this[0]].concat(otherArgs));
9621 return this.each(function() {
9622 typeof options == 'string' ?
9623 $.datepicker['_' + options + 'Datepicker'].
9624 apply($.datepicker, [this].concat(otherArgs)) :
9625 $.datepicker._attachDatepicker(this, options);
9629 $.datepicker = new Datepicker(); // singleton instance
9630 $.datepicker.initialized = false;
9631 $.datepicker.uuid = new Date().getTime();
9632 $.datepicker.version = "1.8.4";
9634 // Workaround for #4055
9635 // Add another global to avoid noConflict issues with inline event handlers
9636 window['DP_jQuery_' + dpuuid] = $;
9640 * jQuery UI Progressbar 1.8.4
9642 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
9643 * Dual licensed under the MIT or GPL Version 2 licenses.
9644 * http://jquery.org/license
9646 * http://docs.jquery.com/UI/Progressbar
9650 * jquery.ui.widget.js
9652 (function( $, undefined ) {
9654 $.widget( "ui.progressbar", {
9662 _create: function() {
9664 .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
9666 role: "progressbar",
9667 "aria-valuemin": this.min,
9668 "aria-valuemax": this.max,
9669 "aria-valuenow": this._value()
9672 this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
9673 .appendTo( this.element );
9675 this._refreshValue();
9678 destroy: function() {
9680 .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
9681 .removeAttr( "role" )
9682 .removeAttr( "aria-valuemin" )
9683 .removeAttr( "aria-valuemax" )
9684 .removeAttr( "aria-valuenow" );
9686 this.valueDiv.remove();
9688 $.Widget.prototype.destroy.apply( this, arguments );
9691 value: function( newValue ) {
9692 if ( newValue === undefined ) {
9693 return this._value();
9696 this._setOption( "value", newValue );
9700 _setOption: function( key, value ) {
9701 if ( key === "value" ) {
9702 this.options.value = value;
9703 this._refreshValue();
9704 this._trigger( "change" );
9707 $.Widget.prototype._setOption.apply( this, arguments );
9710 _value: function() {
9711 var val = this.options.value;
9712 // normalize invalid value
9713 if ( typeof val !== "number" ) {
9716 return Math.min( this.max, Math.max( this.min, val ) );
9719 _refreshValue: function() {
9720 var value = this.value();
9722 .toggleClass( "ui-corner-right", value === this.max )
9723 .width( value + "%" );
9724 this.element.attr( "aria-valuenow", value );
9728 $.extend( $.ui.progressbar, {
9734 * jQuery UI Effects 1.8.4
9736 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
9737 * Dual licensed under the MIT or GPL Version 2 licenses.
9738 * http://jquery.org/license
9740 * http://docs.jquery.com/UI/Effects/
9742 ;jQuery.effects || (function($, undefined) {
9748 /******************************************************************************/
9749 /****************************** COLOR ANIMATIONS ******************************/
9750 /******************************************************************************/
9752 // override the animation for color styles
9753 $.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor',
9754 'borderRightColor', 'borderTopColor', 'color', 'outlineColor'],
9756 $.fx.step[attr] = function(fx) {
9757 if (!fx.colorInit) {
9758 fx.start = getColor(fx.elem, attr);
9759 fx.end = getRGB(fx.end);
9760 fx.colorInit = true;
9763 fx.elem.style[attr] = 'rgb(' +
9764 Math.max(Math.min(parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0], 10), 255), 0) + ',' +
9765 Math.max(Math.min(parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1], 10), 255), 0) + ',' +
9766 Math.max(Math.min(parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2], 10), 255), 0) + ')';
9770 // Color Conversion functions from highlightFade
9771 // By Blair Mitchelmore
9772 // http://jquery.offput.ca/highlightFade/
9774 // Parse strings looking for color tuples [255,255,255]
9775 function getRGB(color) {
9778 // Check if we're already dealing with an array of colors
9779 if ( color && color.constructor == Array && color.length == 3 )
9782 // Look for rgb(num,num,num)
9783 if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color))
9784 return [parseInt(result[1],10), parseInt(result[2],10), parseInt(result[3],10)];
9786 // Look for rgb(num%,num%,num%)
9787 if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color))
9788 return [parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55];
9791 if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color))
9792 return [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)];
9795 if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color))
9796 return [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)];
9798 // Look for rgba(0, 0, 0, 0) == transparent in Safari 3
9799 if (result = /rgba\(0, 0, 0, 0\)/.exec(color))
9800 return colors['transparent'];
9802 // Otherwise, we're most likely dealing with a named color
9803 return colors[$.trim(color).toLowerCase()];
9806 function getColor(elem, attr) {
9810 color = $.curCSS(elem, attr);
9812 // Keep going until we find an element that has color, or we hit the body
9813 if ( color != '' && color != 'transparent' || $.nodeName(elem, "body") )
9816 attr = "backgroundColor";
9817 } while ( elem = elem.parentNode );
9819 return getRGB(color);
9822 // Some named colors to work with
9823 // From Interface by Stefan Petre
9824 // http://interface.eyecon.ro/
9828 azure:[240,255,255],
9829 beige:[245,245,220],
9835 darkcyan:[0,139,139],
9836 darkgrey:[169,169,169],
9837 darkgreen:[0,100,0],
9838 darkkhaki:[189,183,107],
9839 darkmagenta:[139,0,139],
9840 darkolivegreen:[85,107,47],
9841 darkorange:[255,140,0],
9842 darkorchid:[153,50,204],
9844 darksalmon:[233,150,122],
9845 darkviolet:[148,0,211],
9846 fuchsia:[255,0,255],
9850 khaki:[240,230,140],
9851 lightblue:[173,216,230],
9852 lightcyan:[224,255,255],
9853 lightgreen:[144,238,144],
9854 lightgrey:[211,211,211],
9855 lightpink:[255,182,193],
9856 lightyellow:[255,255,224],
9858 magenta:[255,0,255],
9867 silver:[192,192,192],
9868 white:[255,255,255],
9870 transparent: [255,255,255]
9875 /******************************************************************************/
9876 /****************************** CLASS ANIMATIONS ******************************/
9877 /******************************************************************************/
9879 var classAnimationActions = ['add', 'remove', 'toggle'],
9892 function getElementStyles() {
9893 var style = document.defaultView
9894 ? document.defaultView.getComputedStyle(this, null)
9895 : this.currentStyle,
9900 // webkit enumerates style porperties
9901 if (style && style.length && style[0] && style[style[0]]) {
9902 var len = style.length;
9905 if (typeof style[key] == 'string') {
9906 camelCase = key.replace(/\-(\w)/g, function(all, letter){
9907 return letter.toUpperCase();
9909 newStyle[camelCase] = style[key];
9913 for (key in style) {
9914 if (typeof style[key] === 'string') {
9915 newStyle[key] = style[key];
9923 function filterStyles(styles) {
9925 for (name in styles) {
9926 value = styles[name];
9928 // ignore null and undefined values
9930 // ignore functions (when does this occur?)
9931 $.isFunction(value) ||
9932 // shorthand styles that need to be expanded
9933 name in shorthandStyles ||
9934 // ignore scrollbars (break in IE)
9935 (/scrollbar/).test(name) ||
9937 // only colors or values that can be converted to numbers
9938 (!(/color/i).test(name) && isNaN(parseFloat(value)))
9940 delete styles[name];
9947 function styleDifference(oldStyle, newStyle) {
9948 var diff = { _: 0 }, // http://dev.jquery.com/ticket/5459
9951 for (name in newStyle) {
9952 if (oldStyle[name] != newStyle[name]) {
9953 diff[name] = newStyle[name];
9960 $.effects.animateClass = function(value, duration, easing, callback) {
9961 if ($.isFunction(easing)) {
9966 return this.each(function() {
9969 originalStyleAttr = that.attr('style') || ' ',
9970 originalStyle = filterStyles(getElementStyles.call(this)),
9972 className = that.attr('className');
9974 $.each(classAnimationActions, function(i, action) {
9975 if (value[action]) {
9976 that[action + 'Class'](value[action]);
9979 newStyle = filterStyles(getElementStyles.call(this));
9980 that.attr('className', className);
9982 that.animate(styleDifference(originalStyle, newStyle), duration, easing, function() {
9983 $.each(classAnimationActions, function(i, action) {
9984 if (value[action]) { that[action + 'Class'](value[action]); }
9986 // work around bug in IE by clearing the cssText before setting it
9987 if (typeof that.attr('style') == 'object') {
9988 that.attr('style').cssText = '';
9989 that.attr('style').cssText = originalStyleAttr;
9991 that.attr('style', originalStyleAttr);
9993 if (callback) { callback.apply(this, arguments); }
9999 _addClass: $.fn.addClass,
10000 addClass: function(classNames, speed, easing, callback) {
10001 return speed ? $.effects.animateClass.apply(this, [{ add: classNames },speed,easing,callback]) : this._addClass(classNames);
10004 _removeClass: $.fn.removeClass,
10005 removeClass: function(classNames,speed,easing,callback) {
10006 return speed ? $.effects.animateClass.apply(this, [{ remove: classNames },speed,easing,callback]) : this._removeClass(classNames);
10009 _toggleClass: $.fn.toggleClass,
10010 toggleClass: function(classNames, force, speed, easing, callback) {
10011 if ( typeof force == "boolean" || force === undefined ) {
10013 // without speed parameter;
10014 return this._toggleClass(classNames, force);
10016 return $.effects.animateClass.apply(this, [(force?{add:classNames}:{remove:classNames}),speed,easing,callback]);
10019 // without switch parameter;
10020 return $.effects.animateClass.apply(this, [{ toggle: classNames },force,speed,easing]);
10024 switchClass: function(remove,add,speed,easing,callback) {
10025 return $.effects.animateClass.apply(this, [{ add: add, remove: remove },speed,easing,callback]);
10031 /******************************************************************************/
10032 /*********************************** EFFECTS **********************************/
10033 /******************************************************************************/
10035 $.extend($.effects, {
10038 // Saves a set of properties in a data storage
10039 save: function(element, set) {
10040 for(var i=0; i < set.length; i++) {
10041 if(set[i] !== null) element.data("ec.storage."+set[i], element[0].style[set[i]]);
10045 // Restores a set of previously saved properties from a data storage
10046 restore: function(element, set) {
10047 for(var i=0; i < set.length; i++) {
10048 if(set[i] !== null) element.css(set[i], element.data("ec.storage."+set[i]));
10052 setMode: function(el, mode) {
10053 if (mode == 'toggle') mode = el.is(':hidden') ? 'show' : 'hide'; // Set for toggle
10057 getBaseline: function(origin, original) { // Translates a [top,left] array into a baseline value
10058 // this should be a little more flexible in the future to handle a string & hash
10060 switch (origin[0]) {
10061 case 'top': y = 0; break;
10062 case 'middle': y = 0.5; break;
10063 case 'bottom': y = 1; break;
10064 default: y = origin[0] / original.height;
10066 switch (origin[1]) {
10067 case 'left': x = 0; break;
10068 case 'center': x = 0.5; break;
10069 case 'right': x = 1; break;
10070 default: x = origin[1] / original.width;
10072 return {x: x, y: y};
10075 // Wraps the element around a wrapper that copies position properties
10076 createWrapper: function(element) {
10078 // if the element is already wrapped, return it
10079 if (element.parent().is('.ui-effects-wrapper')) {
10080 return element.parent();
10083 // wrap the element
10085 width: element.outerWidth(true),
10086 height: element.outerHeight(true),
10087 'float': element.css('float')
10089 wrapper = $('<div></div>')
10090 .addClass('ui-effects-wrapper')
10093 background: 'transparent',
10099 element.wrap(wrapper);
10100 wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually loose the reference to the wrapped element
10102 // transfer positioning properties to the wrapper
10103 if (element.css('position') == 'static') {
10104 wrapper.css({ position: 'relative' });
10105 element.css({ position: 'relative' });
10108 position: element.css('position'),
10109 zIndex: element.css('z-index')
10111 $.each(['top', 'left', 'bottom', 'right'], function(i, pos) {
10112 props[pos] = element.css(pos);
10113 if (isNaN(parseInt(props[pos], 10))) {
10114 props[pos] = 'auto';
10117 element.css({position: 'relative', top: 0, left: 0 });
10120 return wrapper.css(props).show();
10123 removeWrapper: function(element) {
10124 if (element.parent().is('.ui-effects-wrapper'))
10125 return element.parent().replaceWith(element);
10129 setTransition: function(element, list, factor, value) {
10130 value = value || {};
10131 $.each(list, function(i, x){
10132 unit = element.cssUnit(x);
10133 if (unit[0] > 0) value[x] = unit[0] * factor + unit[1];
10140 function _normalizeArguments(effect, options, speed, callback) {
10141 // shift params for method overloading
10142 if (typeof effect == 'object') {
10143 callback = options;
10146 effect = options.effect;
10148 if ($.isFunction(options)) {
10149 callback = options;
10153 if (typeof options == 'number' || $.fx.speeds[options]) {
10158 if ($.isFunction(speed)) {
10163 options = options || {};
10165 speed = speed || options.duration;
10166 speed = $.fx.off ? 0 : typeof speed == 'number'
10167 ? speed : $.fx.speeds[speed] || $.fx.speeds._default;
10169 callback = callback || options.complete;
10171 return [effect, options, speed, callback];
10175 effect: function(effect, options, speed, callback) {
10176 var args = _normalizeArguments.apply(this, arguments),
10177 // TODO: make effects takes actual parameters instead of a hash
10183 effectMethod = $.effects[effect];
10185 return effectMethod && !$.fx.off ? effectMethod.call(this, args2) : this;
10189 show: function(speed) {
10190 if (!speed || typeof speed == 'number' || $.fx.speeds[speed]) {
10191 return this._show.apply(this, arguments);
10193 var args = _normalizeArguments.apply(this, arguments);
10194 args[1].mode = 'show';
10195 return this.effect.apply(this, args);
10200 hide: function(speed) {
10201 if (!speed || typeof speed == 'number' || $.fx.speeds[speed]) {
10202 return this._hide.apply(this, arguments);
10204 var args = _normalizeArguments.apply(this, arguments);
10205 args[1].mode = 'hide';
10206 return this.effect.apply(this, args);
10210 // jQuery core overloads toggle and create _toggle
10211 __toggle: $.fn.toggle,
10212 toggle: function(speed) {
10213 if (!speed || typeof speed == 'number' || $.fx.speeds[speed] ||
10214 typeof speed == 'boolean' || $.isFunction(speed)) {
10215 return this.__toggle.apply(this, arguments);
10217 var args = _normalizeArguments.apply(this, arguments);
10218 args[1].mode = 'toggle';
10219 return this.effect.apply(this, args);
10223 // helper functions
10224 cssUnit: function(key) {
10225 var style = this.css(key), val = [];
10226 $.each( ['em','px','%','pt'], function(i, unit){
10227 if(style.indexOf(unit) > 0)
10228 val = [parseFloat(style), unit];
10236 /******************************************************************************/
10237 /*********************************** EASING ***********************************/
10238 /******************************************************************************/
10241 * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
10243 * Uses the built in easing capabilities added In jQuery 1.1
10244 * to offer multiple easing options
10246 * TERMS OF USE - jQuery Easing
10248 * Open source under the BSD License.
10250 * Copyright 2008 George McGinley Smith
10251 * All rights reserved.
10253 * Redistribution and use in source and binary forms, with or without modification,
10254 * are permitted provided that the following conditions are met:
10256 * Redistributions of source code must retain the above copyright notice, this list of
10257 * conditions and the following disclaimer.
10258 * Redistributions in binary form must reproduce the above copyright notice, this list
10259 * of conditions and the following disclaimer in the documentation and/or other materials
10260 * provided with the distribution.
10262 * Neither the name of the author nor the names of contributors may be used to endorse
10263 * or promote products derived from this software without specific prior written permission.
10265 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
10266 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
10267 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
10268 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
10269 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
10270 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
10271 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
10272 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
10273 * OF THE POSSIBILITY OF SUCH DAMAGE.
10277 // t: current time, b: begInnIng value, c: change In value, d: duration
10278 $.easing.jswing = $.easing.swing;
10282 def: 'easeOutQuad',
10283 swing: function (x, t, b, c, d) {
10284 //alert($.easing.default);
10285 return $.easing[$.easing.def](x, t, b, c, d);
10287 easeInQuad: function (x, t, b, c, d) {
10288 return c*(t/=d)*t + b;
10290 easeOutQuad: function (x, t, b, c, d) {
10291 return -c *(t/=d)*(t-2) + b;
10293 easeInOutQuad: function (x, t, b, c, d) {
10294 if ((t/=d/2) < 1) return c/2*t*t + b;
10295 return -c/2 * ((--t)*(t-2) - 1) + b;
10297 easeInCubic: function (x, t, b, c, d) {
10298 return c*(t/=d)*t*t + b;
10300 easeOutCubic: function (x, t, b, c, d) {
10301 return c*((t=t/d-1)*t*t + 1) + b;
10303 easeInOutCubic: function (x, t, b, c, d) {
10304 if ((t/=d/2) < 1) return c/2*t*t*t + b;
10305 return c/2*((t-=2)*t*t + 2) + b;
10307 easeInQuart: function (x, t, b, c, d) {
10308 return c*(t/=d)*t*t*t + b;
10310 easeOutQuart: function (x, t, b, c, d) {
10311 return -c * ((t=t/d-1)*t*t*t - 1) + b;
10313 easeInOutQuart: function (x, t, b, c, d) {
10314 if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
10315 return -c/2 * ((t-=2)*t*t*t - 2) + b;
10317 easeInQuint: function (x, t, b, c, d) {
10318 return c*(t/=d)*t*t*t*t + b;
10320 easeOutQuint: function (x, t, b, c, d) {
10321 return c*((t=t/d-1)*t*t*t*t + 1) + b;
10323 easeInOutQuint: function (x, t, b, c, d) {
10324 if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
10325 return c/2*((t-=2)*t*t*t*t + 2) + b;
10327 easeInSine: function (x, t, b, c, d) {
10328 return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
10330 easeOutSine: function (x, t, b, c, d) {
10331 return c * Math.sin(t/d * (Math.PI/2)) + b;
10333 easeInOutSine: function (x, t, b, c, d) {
10334 return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
10336 easeInExpo: function (x, t, b, c, d) {
10337 return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
10339 easeOutExpo: function (x, t, b, c, d) {
10340 return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
10342 easeInOutExpo: function (x, t, b, c, d) {
10343 if (t==0) return b;
10344 if (t==d) return b+c;
10345 if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
10346 return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
10348 easeInCirc: function (x, t, b, c, d) {
10349 return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
10351 easeOutCirc: function (x, t, b, c, d) {
10352 return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
10354 easeInOutCirc: function (x, t, b, c, d) {
10355 if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
10356 return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
10358 easeInElastic: function (x, t, b, c, d) {
10359 var s=1.70158;var p=0;var a=c;
10360 if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
10361 if (a < Math.abs(c)) { a=c; var s=p/4; }
10362 else var s = p/(2*Math.PI) * Math.asin (c/a);
10363 return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
10365 easeOutElastic: function (x, t, b, c, d) {
10366 var s=1.70158;var p=0;var a=c;
10367 if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
10368 if (a < Math.abs(c)) { a=c; var s=p/4; }
10369 else var s = p/(2*Math.PI) * Math.asin (c/a);
10370 return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
10372 easeInOutElastic: function (x, t, b, c, d) {
10373 var s=1.70158;var p=0;var a=c;
10374 if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5);
10375 if (a < Math.abs(c)) { a=c; var s=p/4; }
10376 else var s = p/(2*Math.PI) * Math.asin (c/a);
10377 if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
10378 return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
10380 easeInBack: function (x, t, b, c, d, s) {
10381 if (s == undefined) s = 1.70158;
10382 return c*(t/=d)*t*((s+1)*t - s) + b;
10384 easeOutBack: function (x, t, b, c, d, s) {
10385 if (s == undefined) s = 1.70158;
10386 return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
10388 easeInOutBack: function (x, t, b, c, d, s) {
10389 if (s == undefined) s = 1.70158;
10390 if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
10391 return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
10393 easeInBounce: function (x, t, b, c, d) {
10394 return c - $.easing.easeOutBounce (x, d-t, 0, c, d) + b;
10396 easeOutBounce: function (x, t, b, c, d) {
10397 if ((t/=d) < (1/2.75)) {
10398 return c*(7.5625*t*t) + b;
10399 } else if (t < (2/2.75)) {
10400 return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
10401 } else if (t < (2.5/2.75)) {
10402 return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
10404 return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
10407 easeInOutBounce: function (x, t, b, c, d) {
10408 if (t < d/2) return $.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
10409 return $.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
10415 * TERMS OF USE - EASING EQUATIONS
10417 * Open source under the BSD License.
10419 * Copyright 2001 Robert Penner
10420 * All rights reserved.
10422 * Redistribution and use in source and binary forms, with or without modification,
10423 * are permitted provided that the following conditions are met:
10425 * Redistributions of source code must retain the above copyright notice, this list of
10426 * conditions and the following disclaimer.
10427 * Redistributions in binary form must reproduce the above copyright notice, this list
10428 * of conditions and the following disclaimer in the documentation and/or other materials
10429 * provided with the distribution.
10431 * Neither the name of the author nor the names of contributors may be used to endorse
10432 * or promote products derived from this software without specific prior written permission.
10434 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
10435 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
10436 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
10437 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
10438 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
10439 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
10440 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
10441 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
10442 * OF THE POSSIBILITY OF SUCH DAMAGE.
10448 * jQuery UI Effects Blind 1.8.4
10450 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
10451 * Dual licensed under the MIT or GPL Version 2 licenses.
10452 * http://jquery.org/license
10454 * http://docs.jquery.com/UI/Effects/Blind
10457 * jquery.effects.core.js
10459 (function( $, undefined ) {
10461 $.effects.blind = function(o) {
10463 return this.queue(function() {
10466 var el = $(this), props = ['position','top','left'];
10469 var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode
10470 var direction = o.options.direction || 'vertical'; // Default direction
10473 $.effects.save(el, props); el.show(); // Save & Show
10474 var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper
10475 var ref = (direction == 'vertical') ? 'height' : 'width';
10476 var distance = (direction == 'vertical') ? wrapper.height() : wrapper.width();
10477 if(mode == 'show') wrapper.css(ref, 0); // Shift
10480 var animation = {};
10481 animation[ref] = mode == 'show' ? distance : 0;
10484 wrapper.animate(animation, o.duration, o.options.easing, function() {
10485 if(mode == 'hide') el.hide(); // Hide
10486 $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
10487 if(o.callback) o.callback.apply(el[0], arguments); // Callback
10497 * jQuery UI Effects Bounce 1.8.4
10499 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
10500 * Dual licensed under the MIT or GPL Version 2 licenses.
10501 * http://jquery.org/license
10503 * http://docs.jquery.com/UI/Effects/Bounce
10506 * jquery.effects.core.js
10508 (function( $, undefined ) {
10510 $.effects.bounce = function(o) {
10512 return this.queue(function() {
10515 var el = $(this), props = ['position','top','left'];
10518 var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode
10519 var direction = o.options.direction || 'up'; // Default direction
10520 var distance = o.options.distance || 20; // Default distance
10521 var times = o.options.times || 5; // Default # of times
10522 var speed = o.duration || 250; // Default speed per bounce
10523 if (/show|hide/.test(mode)) props.push('opacity'); // Avoid touching opacity to prevent clearType and PNG issues in IE
10526 $.effects.save(el, props); el.show(); // Save & Show
10527 $.effects.createWrapper(el); // Create Wrapper
10528 var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left';
10529 var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg';
10530 var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) / 3 : el.outerWidth({margin:true}) / 3);
10531 if (mode == 'show') el.css('opacity', 0).css(ref, motion == 'pos' ? -distance : distance); // Shift
10532 if (mode == 'hide') distance = distance / (times * 2);
10533 if (mode != 'hide') times--;
10536 if (mode == 'show') { // Show Bounce
10537 var animation = {opacity: 1};
10538 animation[ref] = (motion == 'pos' ? '+=' : '-=') + distance;
10539 el.animate(animation, speed / 2, o.options.easing);
10540 distance = distance / 2;
10543 for (var i = 0; i < times; i++) { // Bounces
10544 var animation1 = {}, animation2 = {};
10545 animation1[ref] = (motion == 'pos' ? '-=' : '+=') + distance;
10546 animation2[ref] = (motion == 'pos' ? '+=' : '-=') + distance;
10547 el.animate(animation1, speed / 2, o.options.easing).animate(animation2, speed / 2, o.options.easing);
10548 distance = (mode == 'hide') ? distance * 2 : distance / 2;
10550 if (mode == 'hide') { // Last Bounce
10551 var animation = {opacity: 0};
10552 animation[ref] = (motion == 'pos' ? '-=' : '+=') + distance;
10553 el.animate(animation, speed / 2, o.options.easing, function(){
10555 $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
10556 if(o.callback) o.callback.apply(this, arguments); // Callback
10559 var animation1 = {}, animation2 = {};
10560 animation1[ref] = (motion == 'pos' ? '-=' : '+=') + distance;
10561 animation2[ref] = (motion == 'pos' ? '+=' : '-=') + distance;
10562 el.animate(animation1, speed / 2, o.options.easing).animate(animation2, speed / 2, o.options.easing, function(){
10563 $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
10564 if(o.callback) o.callback.apply(this, arguments); // Callback
10567 el.queue('fx', function() { el.dequeue(); });
10575 * jQuery UI Effects Clip 1.8.4
10577 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
10578 * Dual licensed under the MIT or GPL Version 2 licenses.
10579 * http://jquery.org/license
10581 * http://docs.jquery.com/UI/Effects/Clip
10584 * jquery.effects.core.js
10586 (function( $, undefined ) {
10588 $.effects.clip = function(o) {
10590 return this.queue(function() {
10593 var el = $(this), props = ['position','top','left','height','width'];
10596 var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode
10597 var direction = o.options.direction || 'vertical'; // Default direction
10600 $.effects.save(el, props); el.show(); // Save & Show
10601 var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper
10602 var animate = el[0].tagName == 'IMG' ? wrapper : el;
10604 size: (direction == 'vertical') ? 'height' : 'width',
10605 position: (direction == 'vertical') ? 'top' : 'left'
10607 var distance = (direction == 'vertical') ? animate.height() : animate.width();
10608 if(mode == 'show') { animate.css(ref.size, 0); animate.css(ref.position, distance / 2); } // Shift
10611 var animation = {};
10612 animation[ref.size] = mode == 'show' ? distance : 0;
10613 animation[ref.position] = mode == 'show' ? 0 : distance / 2;
10616 animate.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() {
10617 if(mode == 'hide') el.hide(); // Hide
10618 $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
10619 if(o.callback) o.callback.apply(el[0], arguments); // Callback
10629 * jQuery UI Effects Drop 1.8.4
10631 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
10632 * Dual licensed under the MIT or GPL Version 2 licenses.
10633 * http://jquery.org/license
10635 * http://docs.jquery.com/UI/Effects/Drop
10638 * jquery.effects.core.js
10640 (function( $, undefined ) {
10642 $.effects.drop = function(o) {
10644 return this.queue(function() {
10647 var el = $(this), props = ['position','top','left','opacity'];
10650 var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode
10651 var direction = o.options.direction || 'left'; // Default Direction
10654 $.effects.save(el, props); el.show(); // Save & Show
10655 $.effects.createWrapper(el); // Create Wrapper
10656 var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left';
10657 var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg';
10658 var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) / 2 : el.outerWidth({margin:true}) / 2);
10659 if (mode == 'show') el.css('opacity', 0).css(ref, motion == 'pos' ? -distance : distance); // Shift
10662 var animation = {opacity: mode == 'show' ? 1 : 0};
10663 animation[ref] = (mode == 'show' ? (motion == 'pos' ? '+=' : '-=') : (motion == 'pos' ? '-=' : '+=')) + distance;
10666 el.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() {
10667 if(mode == 'hide') el.hide(); // Hide
10668 $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
10669 if(o.callback) o.callback.apply(this, arguments); // Callback
10679 * jQuery UI Effects Explode 1.8.4
10681 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
10682 * Dual licensed under the MIT or GPL Version 2 licenses.
10683 * http://jquery.org/license
10685 * http://docs.jquery.com/UI/Effects/Explode
10688 * jquery.effects.core.js
10690 (function( $, undefined ) {
10692 $.effects.explode = function(o) {
10694 return this.queue(function() {
10696 var rows = o.options.pieces ? Math.round(Math.sqrt(o.options.pieces)) : 3;
10697 var cells = o.options.pieces ? Math.round(Math.sqrt(o.options.pieces)) : 3;
10699 o.options.mode = o.options.mode == 'toggle' ? ($(this).is(':visible') ? 'hide' : 'show') : o.options.mode;
10700 var el = $(this).show().css('visibility', 'hidden');
10701 var offset = el.offset();
10703 //Substract the margins - not fixing the problem yet.
10704 offset.top -= parseInt(el.css("marginTop"),10) || 0;
10705 offset.left -= parseInt(el.css("marginLeft"),10) || 0;
10707 var width = el.outerWidth(true);
10708 var height = el.outerHeight(true);
10710 for(var i=0;i<rows;i++) { // =
10711 for(var j=0;j<cells;j++) { // ||
10715 .wrap('<div></div>')
10717 position: 'absolute',
10718 visibility: 'visible',
10719 left: -j*(width/cells),
10720 top: -i*(height/rows)
10723 .addClass('ui-effects-explode')
10725 position: 'absolute',
10726 overflow: 'hidden',
10727 width: width/cells,
10728 height: height/rows,
10729 left: offset.left + j*(width/cells) + (o.options.mode == 'show' ? (j-Math.floor(cells/2))*(width/cells) : 0),
10730 top: offset.top + i*(height/rows) + (o.options.mode == 'show' ? (i-Math.floor(rows/2))*(height/rows) : 0),
10731 opacity: o.options.mode == 'show' ? 0 : 1
10733 left: offset.left + j*(width/cells) + (o.options.mode == 'show' ? 0 : (j-Math.floor(cells/2))*(width/cells)),
10734 top: offset.top + i*(height/rows) + (o.options.mode == 'show' ? 0 : (i-Math.floor(rows/2))*(height/rows)),
10735 opacity: o.options.mode == 'show' ? 1 : 0
10736 }, o.duration || 500);
10740 // Set a timeout, to call the callback approx. when the other animations have finished
10741 setTimeout(function() {
10743 o.options.mode == 'show' ? el.css({ visibility: 'visible' }) : el.css({ visibility: 'visible' }).hide();
10744 if(o.callback) o.callback.apply(el[0]); // Callback
10747 $('div.ui-effects-explode').remove();
10749 }, o.duration || 500);
10758 * jQuery UI Effects Fold 1.8.4
10760 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
10761 * Dual licensed under the MIT or GPL Version 2 licenses.
10762 * http://jquery.org/license
10764 * http://docs.jquery.com/UI/Effects/Fold
10767 * jquery.effects.core.js
10769 (function( $, undefined ) {
10771 $.effects.fold = function(o) {
10773 return this.queue(function() {
10776 var el = $(this), props = ['position','top','left'];
10779 var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode
10780 var size = o.options.size || 15; // Default fold size
10781 var horizFirst = !(!o.options.horizFirst); // Ensure a boolean value
10782 var duration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2;
10785 $.effects.save(el, props); el.show(); // Save & Show
10786 var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper
10787 var widthFirst = ((mode == 'show') != horizFirst);
10788 var ref = widthFirst ? ['width', 'height'] : ['height', 'width'];
10789 var distance = widthFirst ? [wrapper.width(), wrapper.height()] : [wrapper.height(), wrapper.width()];
10790 var percent = /([0-9]+)%/.exec(size);
10791 if(percent) size = parseInt(percent[1],10) / 100 * distance[mode == 'hide' ? 0 : 1];
10792 if(mode == 'show') wrapper.css(horizFirst ? {height: 0, width: size} : {height: size, width: 0}); // Shift
10795 var animation1 = {}, animation2 = {};
10796 animation1[ref[0]] = mode == 'show' ? distance[0] : size;
10797 animation2[ref[1]] = mode == 'show' ? distance[1] : 0;
10800 wrapper.animate(animation1, duration, o.options.easing)
10801 .animate(animation2, duration, o.options.easing, function() {
10802 if(mode == 'hide') el.hide(); // Hide
10803 $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
10804 if(o.callback) o.callback.apply(el[0], arguments); // Callback
10814 * jQuery UI Effects Highlight 1.8.4
10816 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
10817 * Dual licensed under the MIT or GPL Version 2 licenses.
10818 * http://jquery.org/license
10820 * http://docs.jquery.com/UI/Effects/Highlight
10823 * jquery.effects.core.js
10825 (function( $, undefined ) {
10827 $.effects.highlight = function(o) {
10828 return this.queue(function() {
10829 var elem = $(this),
10830 props = ['backgroundImage', 'backgroundColor', 'opacity'],
10831 mode = $.effects.setMode(elem, o.options.mode || 'show'),
10833 backgroundColor: elem.css('backgroundColor')
10836 if (mode == 'hide') {
10837 animation.opacity = 0;
10840 $.effects.save(elem, props);
10844 backgroundImage: 'none',
10845 backgroundColor: o.options.color || '#ffff99'
10847 .animate(animation, {
10849 duration: o.duration,
10850 easing: o.options.easing,
10851 complete: function() {
10852 (mode == 'hide' && elem.hide());
10853 $.effects.restore(elem, props);
10854 (mode == 'show' && !$.support.opacity && this.style.removeAttribute('filter'));
10855 (o.callback && o.callback.apply(this, arguments));
10864 * jQuery UI Effects Pulsate 1.8.4
10866 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
10867 * Dual licensed under the MIT or GPL Version 2 licenses.
10868 * http://jquery.org/license
10870 * http://docs.jquery.com/UI/Effects/Pulsate
10873 * jquery.effects.core.js
10875 (function( $, undefined ) {
10877 $.effects.pulsate = function(o) {
10878 return this.queue(function() {
10879 var elem = $(this),
10880 mode = $.effects.setMode(elem, o.options.mode || 'show');
10881 times = ((o.options.times || 5) * 2) - 1;
10882 duration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2,
10883 isVisible = elem.is(':visible'),
10887 elem.css('opacity', 0).show();
10891 if ((mode == 'hide' && isVisible) || (mode == 'show' && !isVisible)) {
10895 for (var i = 0; i < times; i++) {
10896 elem.animate({ opacity: animateTo }, duration, o.options.easing);
10897 animateTo = (animateTo + 1) % 2;
10900 elem.animate({ opacity: animateTo }, duration, o.options.easing, function() {
10901 if (animateTo == 0) {
10904 (o.callback && o.callback.apply(this, arguments));
10908 .queue('fx', function() { elem.dequeue(); })
10915 * jQuery UI Effects Scale 1.8.4
10917 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
10918 * Dual licensed under the MIT or GPL Version 2 licenses.
10919 * http://jquery.org/license
10921 * http://docs.jquery.com/UI/Effects/Scale
10924 * jquery.effects.core.js
10926 (function( $, undefined ) {
10928 $.effects.puff = function(o) {
10929 return this.queue(function() {
10930 var elem = $(this),
10931 mode = $.effects.setMode(elem, o.options.mode || 'hide'),
10932 percent = parseInt(o.options.percent, 10) || 150,
10933 factor = percent / 100,
10934 original = { height: elem.height(), width: elem.width() };
10936 $.extend(o.options, {
10939 percent: mode == 'hide' ? percent : 100,
10940 from: mode == 'hide'
10943 height: original.height * factor,
10944 width: original.width * factor
10948 elem.effect('scale', o.options, o.duration, o.callback);
10953 $.effects.scale = function(o) {
10955 return this.queue(function() {
10961 var options = $.extend(true, {}, o.options);
10962 var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode
10963 var percent = parseInt(o.options.percent,10) || (parseInt(o.options.percent,10) == 0 ? 0 : (mode == 'hide' ? 0 : 100)); // Set default scaling percent
10964 var direction = o.options.direction || 'both'; // Set default axis
10965 var origin = o.options.origin; // The origin of the scaling
10966 if (mode != 'effect') { // Set default origin and restore for show/hide
10967 options.origin = origin || ['middle','center'];
10968 options.restore = true;
10970 var original = {height: el.height(), width: el.width()}; // Save original
10971 el.from = o.options.from || (mode == 'show' ? {height: 0, width: 0} : original); // Default from state
10974 var factor = { // Set scaling factor
10975 y: direction != 'horizontal' ? (percent / 100) : 1,
10976 x: direction != 'vertical' ? (percent / 100) : 1
10978 el.to = {height: original.height * factor.y, width: original.width * factor.x}; // Set to state
10980 if (o.options.fade) { // Fade option to support puff
10981 if (mode == 'show') {el.from.opacity = 0; el.to.opacity = 1;};
10982 if (mode == 'hide') {el.from.opacity = 1; el.to.opacity = 0;};
10986 options.from = el.from; options.to = el.to; options.mode = mode;
10989 el.effect('size', options, o.duration, o.callback);
10995 $.effects.size = function(o) {
10997 return this.queue(function() {
11000 var el = $(this), props = ['position','top','left','width','height','overflow','opacity'];
11001 var props1 = ['position','top','left','overflow','opacity']; // Always restore
11002 var props2 = ['width','height','overflow']; // Copy for children
11003 var cProps = ['fontSize'];
11004 var vProps = ['borderTopWidth', 'borderBottomWidth', 'paddingTop', 'paddingBottom'];
11005 var hProps = ['borderLeftWidth', 'borderRightWidth', 'paddingLeft', 'paddingRight'];
11008 var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode
11009 var restore = o.options.restore || false; // Default restore
11010 var scale = o.options.scale || 'both'; // Default scale mode
11011 var origin = o.options.origin; // The origin of the sizing
11012 var original = {height: el.height(), width: el.width()}; // Save original
11013 el.from = o.options.from || original; // Default from state
11014 el.to = o.options.to || original; // Default to state
11016 if (origin) { // Calculate baseline shifts
11017 var baseline = $.effects.getBaseline(origin, original);
11018 el.from.top = (original.height - el.from.height) * baseline.y;
11019 el.from.left = (original.width - el.from.width) * baseline.x;
11020 el.to.top = (original.height - el.to.height) * baseline.y;
11021 el.to.left = (original.width - el.to.width) * baseline.x;
11023 var factor = { // Set scaling factor
11024 from: {y: el.from.height / original.height, x: el.from.width / original.width},
11025 to: {y: el.to.height / original.height, x: el.to.width / original.width}
11027 if (scale == 'box' || scale == 'both') { // Scale the css box
11028 if (factor.from.y != factor.to.y) { // Vertical props scaling
11029 props = props.concat(vProps);
11030 el.from = $.effects.setTransition(el, vProps, factor.from.y, el.from);
11031 el.to = $.effects.setTransition(el, vProps, factor.to.y, el.to);
11033 if (factor.from.x != factor.to.x) { // Horizontal props scaling
11034 props = props.concat(hProps);
11035 el.from = $.effects.setTransition(el, hProps, factor.from.x, el.from);
11036 el.to = $.effects.setTransition(el, hProps, factor.to.x, el.to);
11039 if (scale == 'content' || scale == 'both') { // Scale the content
11040 if (factor.from.y != factor.to.y) { // Vertical props scaling
11041 props = props.concat(cProps);
11042 el.from = $.effects.setTransition(el, cProps, factor.from.y, el.from);
11043 el.to = $.effects.setTransition(el, cProps, factor.to.y, el.to);
11046 $.effects.save(el, restore ? props : props1); el.show(); // Save & Show
11047 $.effects.createWrapper(el); // Create Wrapper
11048 el.css('overflow','hidden').css(el.from); // Shift
11051 if (scale == 'content' || scale == 'both') { // Scale the children
11052 vProps = vProps.concat(['marginTop','marginBottom']).concat(cProps); // Add margins/font-size
11053 hProps = hProps.concat(['marginLeft','marginRight']); // Add margins
11054 props2 = props.concat(vProps).concat(hProps); // Concat
11055 el.find("*[width]").each(function(){
11057 if (restore) $.effects.save(child, props2);
11058 var c_original = {height: child.height(), width: child.width()}; // Save original
11059 child.from = {height: c_original.height * factor.from.y, width: c_original.width * factor.from.x};
11060 child.to = {height: c_original.height * factor.to.y, width: c_original.width * factor.to.x};
11061 if (factor.from.y != factor.to.y) { // Vertical props scaling
11062 child.from = $.effects.setTransition(child, vProps, factor.from.y, child.from);
11063 child.to = $.effects.setTransition(child, vProps, factor.to.y, child.to);
11065 if (factor.from.x != factor.to.x) { // Horizontal props scaling
11066 child.from = $.effects.setTransition(child, hProps, factor.from.x, child.from);
11067 child.to = $.effects.setTransition(child, hProps, factor.to.x, child.to);
11069 child.css(child.from); // Shift children
11070 child.animate(child.to, o.duration, o.options.easing, function(){
11071 if (restore) $.effects.restore(child, props2); // Restore children
11072 }); // Animate children
11077 el.animate(el.to, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() {
11078 if (el.to.opacity === 0) {
11079 el.css('opacity', el.from.opacity);
11081 if(mode == 'hide') el.hide(); // Hide
11082 $.effects.restore(el, restore ? props : props1); $.effects.removeWrapper(el); // Restore
11083 if(o.callback) o.callback.apply(this, arguments); // Callback
11093 * jQuery UI Effects Shake 1.8.4
11095 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
11096 * Dual licensed under the MIT or GPL Version 2 licenses.
11097 * http://jquery.org/license
11099 * http://docs.jquery.com/UI/Effects/Shake
11102 * jquery.effects.core.js
11104 (function( $, undefined ) {
11106 $.effects.shake = function(o) {
11108 return this.queue(function() {
11111 var el = $(this), props = ['position','top','left'];
11114 var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode
11115 var direction = o.options.direction || 'left'; // Default direction
11116 var distance = o.options.distance || 20; // Default distance
11117 var times = o.options.times || 3; // Default # of times
11118 var speed = o.duration || o.options.duration || 140; // Default speed per shake
11121 $.effects.save(el, props); el.show(); // Save & Show
11122 $.effects.createWrapper(el); // Create Wrapper
11123 var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left';
11124 var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg';
11127 var animation = {}, animation1 = {}, animation2 = {};
11128 animation[ref] = (motion == 'pos' ? '-=' : '+=') + distance;
11129 animation1[ref] = (motion == 'pos' ? '+=' : '-=') + distance * 2;
11130 animation2[ref] = (motion == 'pos' ? '-=' : '+=') + distance * 2;
11133 el.animate(animation, speed, o.options.easing);
11134 for (var i = 1; i < times; i++) { // Shakes
11135 el.animate(animation1, speed, o.options.easing).animate(animation2, speed, o.options.easing);
11137 el.animate(animation1, speed, o.options.easing).
11138 animate(animation, speed / 2, o.options.easing, function(){ // Last shake
11139 $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
11140 if(o.callback) o.callback.apply(this, arguments); // Callback
11142 el.queue('fx', function() { el.dequeue(); });
11150 * jQuery UI Effects Slide 1.8.4
11152 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
11153 * Dual licensed under the MIT or GPL Version 2 licenses.
11154 * http://jquery.org/license
11156 * http://docs.jquery.com/UI/Effects/Slide
11159 * jquery.effects.core.js
11161 (function( $, undefined ) {
11163 $.effects.slide = function(o) {
11165 return this.queue(function() {
11168 var el = $(this), props = ['position','top','left'];
11171 var mode = $.effects.setMode(el, o.options.mode || 'show'); // Set Mode
11172 var direction = o.options.direction || 'left'; // Default Direction
11175 $.effects.save(el, props); el.show(); // Save & Show
11176 $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper
11177 var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left';
11178 var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg';
11179 var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) : el.outerWidth({margin:true}));
11180 if (mode == 'show') el.css(ref, motion == 'pos' ? -distance : distance); // Shift
11183 var animation = {};
11184 animation[ref] = (mode == 'show' ? (motion == 'pos' ? '+=' : '-=') : (motion == 'pos' ? '-=' : '+=')) + distance;
11187 el.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() {
11188 if(mode == 'hide') el.hide(); // Hide
11189 $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
11190 if(o.callback) o.callback.apply(this, arguments); // Callback
11200 * jQuery UI Effects Transfer 1.8.4
11202 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
11203 * Dual licensed under the MIT or GPL Version 2 licenses.
11204 * http://jquery.org/license
11206 * http://docs.jquery.com/UI/Effects/Transfer
11209 * jquery.effects.core.js
11211 (function( $, undefined ) {
11213 $.effects.transfer = function(o) {
11214 return this.queue(function() {
11215 var elem = $(this),
11216 target = $(o.options.to),
11217 endPosition = target.offset(),
11219 top: endPosition.top,
11220 left: endPosition.left,
11221 height: target.innerHeight(),
11222 width: target.innerWidth()
11224 startPosition = elem.offset(),
11225 transfer = $('<div class="ui-effects-transfer"></div>')
11226 .appendTo(document.body)
11227 .addClass(o.options.className)
11229 top: startPosition.top,
11230 left: startPosition.left,
11231 height: elem.innerHeight(),
11232 width: elem.innerWidth(),
11233 position: 'absolute'
11235 .animate(animation, o.duration, o.options.easing, function() {
11237 (o.callback && o.callback.apply(elem[0], arguments));