4 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
5 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
6 * and GPL (GPL-LICENSE.txt) licenses.
\r
8 * http://docs.jquery.com/UI
\r
10 ;jQuery.ui || (function($) {
\r
12 //Helper functions and ui object
\r
16 // $.ui.plugin is deprecated. Use the proxy pattern instead.
\r
18 add: function(module, option, set) {
\r
19 var proto = $.ui[module].prototype;
\r
21 proto.plugins[i] = proto.plugins[i] || [];
\r
22 proto.plugins[i].push([option, set[i]]);
\r
25 call: function(instance, name, args) {
\r
26 var set = instance.plugins[name];
\r
27 if(!set || !instance.element[0].parentNode) { return; }
\r
29 for (var i = 0; i < set.length; i++) {
\r
30 if (instance.options[set[i][0]]) {
\r
31 set[i][1].apply(instance.element, args);
\r
37 contains: function(a, b) {
\r
38 return document.compareDocumentPosition
\r
39 ? a.compareDocumentPosition(b) & 16
\r
40 : a !== b && a.contains(b);
\r
43 hasScroll: function(el, a) {
\r
45 //If overflow is hidden, the element might have extra content, but the user wants to hide it
\r
46 if ($(el).css('overflow') == 'hidden') { return false; }
\r
48 var scroll = (a && a == 'left') ? 'scrollLeft' : 'scrollTop',
\r
51 if (el[scroll] > 0) { return true; }
\r
53 // TODO: determine which cases actually cause this to happen
\r
54 // if the element doesn't have the scroll set, see if it's possible to
\r
57 has = (el[scroll] > 0);
\r
62 isOverAxis: function(x, reference, size) {
\r
63 //Determines when x coordinate is over "b" element axis
\r
64 return (x > reference) && (x < (reference + size));
\r
67 isOver: function(y, x, top, left, height, width) {
\r
68 //Determines when x, y coordinates is over "b" element
\r
69 return $.ui.isOverAxis(y, top, height) && $.ui.isOverAxis(x, left, width);
\r
86 NUMPAD_DECIMAL: 110,
\r
89 NUMPAD_MULTIPLY: 106,
\r
90 NUMPAD_SUBTRACT: 109,
\r
104 _focus: $.fn.focus,
\r
105 focus: function(delay, fn) {
\r
106 return typeof delay === 'number'
\r
107 ? this.each(function() {
\r
109 setTimeout(function() {
\r
111 (fn && fn.call(elem));
\r
114 : this._focus.apply(this, arguments);
\r
117 enableSelection: function() {
\r
119 .attr('unselectable', 'off')
\r
120 .css('MozUserSelect', '')
\r
121 .unbind('selectstart.ui');
\r
124 disableSelection: function() {
\r
126 .attr('unselectable', 'on')
\r
127 .css('MozUserSelect', 'none')
\r
128 .bind('selectstart.ui', function() { return false; });
\r
131 scrollParent: function() {
\r
133 if(($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) {
\r
134 scrollParent = this.parents().filter(function() {
\r
135 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));
\r
138 scrollParent = this.parents().filter(function() {
\r
139 return (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
\r
143 return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent;
\r
146 zIndex: function(zIndex) {
\r
147 if (zIndex !== undefined) {
\r
148 return this.css('zIndex', zIndex);
\r
152 var elem = $(this[0]), position, value;
\r
153 while (elem.length && elem[0] !== document) {
\r
154 // Ignore z-index if position is set to a value where z-index is ignored by the browser
\r
155 // This makes behavior of this function consistent across browsers
\r
156 // WebKit always returns auto if the element is positioned
\r
157 position = elem.css('position');
\r
158 if (position == 'absolute' || position == 'relative' || position == 'fixed')
\r
160 // IE returns 0 when zIndex is not specified
\r
161 // other browsers return a string
\r
162 // we ignore the case of nested elements with an explicit value of 0
\r
163 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
\r
164 value = parseInt(elem.css('zIndex'));
\r
165 if (!isNaN(value) && value != 0) {
\r
169 elem = elem.parent();
\r
178 //Additional selectors
\r
179 $.extend($.expr[':'], {
\r
180 data: function(elem, i, match) {
\r
181 return !!$.data(elem, match[3]);
\r
184 focusable: function(element) {
\r
185 var nodeName = element.nodeName.toLowerCase(),
\r
186 tabIndex = $.attr(element, 'tabindex');
\r
187 return (/input|select|textarea|button|object/.test(nodeName)
\r
188 ? !element.disabled
\r
189 : 'a' == nodeName || 'area' == nodeName
\r
190 ? element.href || !isNaN(tabIndex)
\r
191 : !isNaN(tabIndex))
\r
192 // the element and all of its ancestors must be visible
\r
193 // the browser may report that the area is hidden
\r
194 && !$(element)['area' == nodeName ? 'parents' : 'closest'](':hidden').length;
\r
197 tabbable: function(element) {
\r
198 var tabIndex = $.attr(element, 'tabindex');
\r
199 return (isNaN(tabIndex) || tabIndex >= 0) && $(element).is(':focusable');
\r
205 * jQuery UI Widget 1.8
\r
207 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
208 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
209 * and GPL (GPL-LICENSE.txt) licenses.
\r
211 * http://docs.jquery.com/UI/Widget
\r
215 var _remove = $.fn.remove;
\r
217 $.fn.remove = function( selector, keepData ) {
\r
218 return this.each(function() {
\r
220 if ( !selector || $.filter( selector, [ this ] ).length ) {
\r
221 $( "*", this ).add( this ).each(function() {
\r
222 $( this ).triggerHandler( "remove" );
\r
226 return _remove.call( $(this), selector, keepData );
\r
230 $.widget = function( name, base, prototype ) {
\r
231 var namespace = name.split( "." )[ 0 ],
\r
233 name = name.split( "." )[ 1 ];
\r
234 fullName = namespace + "-" + name;
\r
236 if ( !prototype ) {
\r
241 // create selector for plugin
\r
242 $.expr[ ":" ][ fullName ] = function( elem ) {
\r
243 return !!$.data( elem, name );
\r
246 $[ namespace ] = $[ namespace ] || {};
\r
247 $[ namespace ][ name ] = function( options, element ) {
\r
248 // allow instantiation without initializing for simple inheritance
\r
249 if ( arguments.length ) {
\r
250 this._createWidget( options, element );
\r
254 var basePrototype = new base();
\r
255 // we need to make the options hash a property directly on the new instance
\r
256 // otherwise we'll modify the options hash on the prototype that we're
\r
258 // $.each( basePrototype, function( key, val ) {
\r
259 // if ( $.isPlainObject(val) ) {
\r
260 // basePrototype[ key ] = $.extend( {}, val );
\r
263 basePrototype.options = $.extend( {}, basePrototype.options );
\r
264 $[ namespace ][ name ].prototype = $.extend( true, basePrototype, {
\r
265 namespace: namespace,
\r
267 widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name,
\r
268 widgetBaseClass: fullName
\r
271 $.widget.bridge( name, $[ namespace ][ name ] );
\r
274 $.widget.bridge = function( name, object ) {
\r
275 $.fn[ name ] = function( options ) {
\r
276 var isMethodCall = typeof options === "string",
\r
277 args = Array.prototype.slice.call( arguments, 1 ),
\r
278 returnValue = this;
\r
280 // allow multiple hashes to be passed on init
\r
281 options = !isMethodCall && args.length ?
\r
282 $.extend.apply( null, [ true, options ].concat(args) ) :
\r
285 // prevent calls to internal methods
\r
286 if ( isMethodCall && options.substring( 0, 1 ) === "_" ) {
\r
287 return returnValue;
\r
290 if ( isMethodCall ) {
\r
291 this.each(function() {
\r
292 var instance = $.data( this, name ),
\r
293 methodValue = instance && $.isFunction( instance[options] ) ?
\r
294 instance[ options ].apply( instance, args ) :
\r
296 if ( methodValue !== instance && methodValue !== undefined ) {
\r
297 returnValue = methodValue;
\r
302 this.each(function() {
\r
303 var instance = $.data( this, name );
\r
306 instance.option( options );
\r
310 $.data( this, name, new object( options, this ) );
\r
315 return returnValue;
\r
319 $.Widget = function( options, element ) {
\r
320 // allow instantiation without initializing for simple inheritance
\r
321 if ( arguments.length ) {
\r
322 this._createWidget( options, element );
\r
326 $.Widget.prototype = {
\r
327 widgetName: "widget",
\r
328 widgetEventPrefix: "",
\r
332 _createWidget: function( options, element ) {
\r
333 // $.widget.bridge stores the plugin instance, but we do it anyway
\r
334 // so that it's stored even before the _create function runs
\r
335 this.element = $( element ).data( this.widgetName, this );
\r
336 this.options = $.extend( true, {},
\r
338 $.metadata && $.metadata.get( element )[ this.widgetName ],
\r
342 this.element.bind( "remove." + this.widgetName, function() {
\r
349 _create: function() {},
\r
350 _init: function() {},
\r
352 destroy: function() {
\r
354 .unbind( "." + this.widgetName )
\r
355 .removeData( this.widgetName );
\r
357 .unbind( "." + this.widgetName )
\r
358 .removeAttr( "aria-disabled" )
\r
360 this.widgetBaseClass + "-disabled " +
\r
361 this.namespace + "-state-disabled" );
\r
364 widget: function() {
\r
365 return this.element;
\r
368 option: function( key, value ) {
\r
372 if ( arguments.length === 0 ) {
\r
373 // don't return a reference to the internal hash
\r
374 return $.extend( {}, self.options );
\r
377 if (typeof key === "string" ) {
\r
378 if ( value === undefined ) {
\r
379 return this.options[ key ];
\r
382 options[ key ] = value;
\r
385 $.each( options, function( key, value ) {
\r
386 self._setOption( key, value );
\r
391 _setOption: function( key, value ) {
\r
392 this.options[ key ] = value;
\r
394 if ( key === "disabled" ) {
\r
396 [ value ? "addClass" : "removeClass"](
\r
397 this.widgetBaseClass + "-disabled" + " " +
\r
398 this.namespace + "-state-disabled" )
\r
399 .attr( "aria-disabled", value );
\r
405 enable: function() {
\r
406 return this._setOption( "disabled", false );
\r
408 disable: function() {
\r
409 return this._setOption( "disabled", true );
\r
412 _trigger: function( type, event, data ) {
\r
413 var callback = this.options[ type ];
\r
415 event = $.Event( event );
\r
416 event.type = ( type === this.widgetEventPrefix ?
\r
418 this.widgetEventPrefix + type ).toLowerCase();
\r
421 // copy original event properties over to the new event
\r
422 // this would happen if we could call $.event.fix instead of $.Event
\r
423 // but we don't have a way to force an event to be fixed multiple times
\r
424 if ( event.originalEvent ) {
\r
425 for ( var i = $.event.props.length, prop; i; ) {
\r
426 prop = $.event.props[ --i ];
\r
427 event[ prop ] = event.originalEvent[ prop ];
\r
431 this.element.trigger( event, data );
\r
433 return !( $.isFunction(callback) &&
\r
434 callback.call( this.element[0], event, data ) === false ||
\r
435 event.isDefaultPrevented() );
\r
441 * jQuery UI Mouse 1.8
\r
443 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
444 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
445 * and GPL (GPL-LICENSE.txt) licenses.
\r
447 * http://docs.jquery.com/UI/Mouse
\r
450 * jquery.ui.widget.js
\r
454 $.widget("ui.mouse", {
\r
456 cancel: ':input,option',
\r
460 _mouseInit: function() {
\r
464 .bind('mousedown.'+this.widgetName, function(event) {
\r
465 return self._mouseDown(event);
\r
467 .bind('click.'+this.widgetName, function(event) {
\r
468 if(self._preventClickEvent) {
\r
469 self._preventClickEvent = false;
\r
470 event.stopImmediatePropagation();
\r
475 this.started = false;
\r
478 // TODO: make sure destroying one instance of mouse doesn't mess with
\r
479 // other instances of mouse
\r
480 _mouseDestroy: function() {
\r
481 this.element.unbind('.'+this.widgetName);
\r
484 _mouseDown: function(event) {
\r
485 // don't let more than one widget handle mouseStart
\r
486 // TODO: figure out why we have to use originalEvent
\r
487 event.originalEvent = event.originalEvent || {};
\r
488 if (event.originalEvent.mouseHandled) { return; }
\r
490 // we may have missed mouseup (out of window)
\r
491 (this._mouseStarted && this._mouseUp(event));
\r
493 this._mouseDownEvent = event;
\r
496 btnIsLeft = (event.which == 1),
\r
497 elIsCancel = (typeof this.options.cancel == "string" ? $(event.target).parents().add(event.target).filter(this.options.cancel).length : false);
\r
498 if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
\r
502 this.mouseDelayMet = !this.options.delay;
\r
503 if (!this.mouseDelayMet) {
\r
504 this._mouseDelayTimer = setTimeout(function() {
\r
505 self.mouseDelayMet = true;
\r
506 }, this.options.delay);
\r
509 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
\r
510 this._mouseStarted = (this._mouseStart(event) !== false);
\r
511 if (!this._mouseStarted) {
\r
512 event.preventDefault();
\r
517 // these delegates are required to keep context
\r
518 this._mouseMoveDelegate = function(event) {
\r
519 return self._mouseMove(event);
\r
521 this._mouseUpDelegate = function(event) {
\r
522 return self._mouseUp(event);
\r
525 .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
\r
526 .bind('mouseup.'+this.widgetName, this._mouseUpDelegate);
\r
528 // preventDefault() is used to prevent the selection of text here -
\r
529 // however, in Safari, this causes select boxes not to be selectable
\r
530 // anymore, so this fix is needed
\r
531 ($.browser.safari || event.preventDefault());
\r
533 event.originalEvent.mouseHandled = true;
\r
537 _mouseMove: function(event) {
\r
538 // IE mouseup check - mouseup happened when mouse was out of window
\r
539 if ($.browser.msie && !event.button) {
\r
540 return this._mouseUp(event);
\r
543 if (this._mouseStarted) {
\r
544 this._mouseDrag(event);
\r
545 return event.preventDefault();
\r
548 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
\r
549 this._mouseStarted =
\r
550 (this._mouseStart(this._mouseDownEvent, event) !== false);
\r
551 (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
\r
554 return !this._mouseStarted;
\r
557 _mouseUp: function(event) {
\r
559 .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
\r
560 .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
\r
562 if (this._mouseStarted) {
\r
563 this._mouseStarted = false;
\r
564 this._preventClickEvent = (event.target == this._mouseDownEvent.target);
\r
565 this._mouseStop(event);
\r
571 _mouseDistanceMet: function(event) {
\r
573 Math.abs(this._mouseDownEvent.pageX - event.pageX),
\r
574 Math.abs(this._mouseDownEvent.pageY - event.pageY)
\r
575 ) >= this.options.distance
\r
579 _mouseDelayMet: function(event) {
\r
580 return this.mouseDelayMet;
\r
583 // These are placeholder methods, to be overriden by extending plugin
\r
584 _mouseStart: function(event) {},
\r
585 _mouseDrag: function(event) {},
\r
586 _mouseStop: function(event) {},
\r
587 _mouseCapture: function(event) { return true; }
\r
592 * jQuery UI Draggable 1.8
\r
594 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
595 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
596 * and GPL (GPL-LICENSE.txt) licenses.
\r
598 * http://docs.jquery.com/UI/Draggables
\r
601 * jquery.ui.core.js
\r
602 * jquery.ui.mouse.js
\r
603 * jquery.ui.widget.js
\r
607 $.widget("ui.draggable", $.ui.mouse, {
\r
608 widgetEventPrefix: "drag",
\r
611 appendTo: "parent",
\r
613 connectToSortable: false,
\r
614 containment: false,
\r
619 helper: "original",
\r
622 refreshPositions: false,
\r
624 revertDuration: 500,
\r
627 scrollSensitivity: 20,
\r
635 _create: function() {
\r
637 if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position")))
\r
638 this.element[0].style.position = 'relative';
\r
640 (this.options.addClasses && this.element.addClass("ui-draggable"));
\r
641 (this.options.disabled && this.element.addClass("ui-draggable-disabled"));
\r
647 destroy: function() {
\r
648 if(!this.element.data('draggable')) return;
\r
650 .removeData("draggable")
\r
651 .unbind(".draggable")
\r
652 .removeClass("ui-draggable"
\r
653 + " ui-draggable-dragging"
\r
654 + " ui-draggable-disabled");
\r
655 this._mouseDestroy();
\r
660 _mouseCapture: function(event) {
\r
662 var o = this.options;
\r
664 // among others, prevent a drag on a resizable-handle
\r
665 if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle'))
\r
668 //Quit if we're not on a valid handle
\r
669 this.handle = this._getHandle(event);
\r
677 _mouseStart: function(event) {
\r
679 var o = this.options;
\r
681 //Create and append the visible helper
\r
682 this.helper = this._createHelper(event);
\r
684 //Cache the helper size
\r
685 this._cacheHelperProportions();
\r
687 //If ddmanager is used for droppables, set the global draggable
\r
689 $.ui.ddmanager.current = this;
\r
692 * - Position generation -
\r
693 * This block generates everything position related - it's the core of draggables.
\r
696 //Cache the margins of the original element
\r
697 this._cacheMargins();
\r
699 //Store the helper's css position
\r
700 this.cssPosition = this.helper.css("position");
\r
701 this.scrollParent = this.helper.scrollParent();
\r
703 //The element's absolute position on the page minus margins
\r
704 this.offset = this.positionAbs = this.element.offset();
\r
706 top: this.offset.top - this.margins.top,
\r
707 left: this.offset.left - this.margins.left
\r
710 $.extend(this.offset, {
\r
711 click: { //Where the click happened, relative to the element
\r
712 left: event.pageX - this.offset.left,
\r
713 top: event.pageY - this.offset.top
\r
715 parent: this._getParentOffset(),
\r
716 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
\r
719 //Generate the original position
\r
720 this.originalPosition = this.position = this._generatePosition(event);
\r
721 this.originalPageX = event.pageX;
\r
722 this.originalPageY = event.pageY;
\r
724 //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
\r
725 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
\r
727 //Set a containment if given in the options
\r
729 this._setContainment();
\r
731 //Trigger event + callbacks
\r
732 if(this._trigger("start", event) === false) {
\r
737 //Recache the helper size
\r
738 this._cacheHelperProportions();
\r
740 //Prepare the droppable offsets
\r
741 if ($.ui.ddmanager && !o.dropBehaviour)
\r
742 $.ui.ddmanager.prepareOffsets(this, event);
\r
744 this.helper.addClass("ui-draggable-dragging");
\r
745 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
\r
749 _mouseDrag: function(event, noPropagation) {
\r
751 //Compute the helpers position
\r
752 this.position = this._generatePosition(event);
\r
753 this.positionAbs = this._convertPositionTo("absolute");
\r
755 //Call plugins and callbacks and use the resulting position if something is returned
\r
756 if (!noPropagation) {
\r
757 var ui = this._uiHash();
\r
758 if(this._trigger('drag', event, ui) === false) {
\r
762 this.position = ui.position;
\r
765 if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
\r
766 if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
\r
767 if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
\r
772 _mouseStop: function(event) {
\r
774 //If we are using droppables, inform the manager about the drop
\r
775 var dropped = false;
\r
776 if ($.ui.ddmanager && !this.options.dropBehaviour)
\r
777 dropped = $.ui.ddmanager.drop(this, event);
\r
779 //if a drop comes from outside (a sortable)
\r
781 dropped = this.dropped;
\r
782 this.dropped = false;
\r
785 //if the original element is removed, don't bother to continue
\r
786 if(!this.element[0] || !this.element[0].parentNode)
\r
789 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))) {
\r
791 $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
\r
792 if(self._trigger("stop", event) !== false) {
\r
797 if(this._trigger("stop", event) !== false) {
\r
805 cancel: function() {
\r
807 if(this.helper.is(".ui-draggable-dragging")) {
\r
817 _getHandle: function(event) {
\r
819 var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false;
\r
820 $(this.options.handle, this.element)
\r
824 if(this == event.target) handle = true;
\r
831 _createHelper: function(event) {
\r
833 var o = this.options;
\r
834 var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone() : this.element);
\r
836 if(!helper.parents('body').length)
\r
837 helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo));
\r
839 if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position")))
\r
840 helper.css("position", "absolute");
\r
846 _adjustOffsetFromHelper: function(obj) {
\r
847 if (typeof obj == 'string') {
\r
848 obj = obj.split(' ');
\r
850 if ($.isArray(obj)) {
\r
851 obj = {left: +obj[0], top: +obj[1] || 0};
\r
853 if ('left' in obj) {
\r
854 this.offset.click.left = obj.left + this.margins.left;
\r
856 if ('right' in obj) {
\r
857 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
\r
859 if ('top' in obj) {
\r
860 this.offset.click.top = obj.top + this.margins.top;
\r
862 if ('bottom' in obj) {
\r
863 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
\r
867 _getParentOffset: function() {
\r
869 //Get the offsetParent and cache its position
\r
870 this.offsetParent = this.helper.offsetParent();
\r
871 var po = this.offsetParent.offset();
\r
873 // This is a special case where we need to modify a offset calculated on start, since the following happened:
\r
874 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
\r
875 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
\r
876 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
\r
877 if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) {
\r
878 po.left += this.scrollParent.scrollLeft();
\r
879 po.top += this.scrollParent.scrollTop();
\r
882 if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information
\r
883 || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix
\r
884 po = { top: 0, left: 0 };
\r
887 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
\r
888 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
\r
893 _getRelativeOffset: function() {
\r
895 if(this.cssPosition == "relative") {
\r
896 var p = this.element.position();
\r
898 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
\r
899 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
\r
902 return { top: 0, left: 0 };
\r
907 _cacheMargins: function() {
\r
909 left: (parseInt(this.element.css("marginLeft"),10) || 0),
\r
910 top: (parseInt(this.element.css("marginTop"),10) || 0)
\r
914 _cacheHelperProportions: function() {
\r
915 this.helperProportions = {
\r
916 width: this.helper.outerWidth(),
\r
917 height: this.helper.outerHeight()
\r
921 _setContainment: function() {
\r
923 var o = this.options;
\r
924 if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
\r
925 if(o.containment == 'document' || o.containment == 'window') this.containment = [
\r
926 0 - this.offset.relative.left - this.offset.parent.left,
\r
927 0 - this.offset.relative.top - this.offset.parent.top,
\r
928 $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left,
\r
929 ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
\r
932 if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) {
\r
933 var ce = $(o.containment)[0]; if(!ce) return;
\r
934 var co = $(o.containment).offset();
\r
935 var over = ($(ce).css("overflow") != 'hidden');
\r
937 this.containment = [
\r
938 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
\r
939 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
\r
940 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,
\r
941 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
\r
943 } else if(o.containment.constructor == Array) {
\r
944 this.containment = o.containment;
\r
949 _convertPositionTo: function(d, pos) {
\r
951 if(!pos) pos = this.position;
\r
952 var mod = d == "absolute" ? 1 : -1;
\r
953 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);
\r
957 pos.top // The absolute mouse position
\r
958 + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent
\r
959 + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border)
\r
960 - ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
\r
963 pos.left // The absolute mouse position
\r
964 + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent
\r
965 + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border)
\r
966 - ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
\r
972 _generatePosition: function(event) {
\r
974 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);
\r
975 var pageX = event.pageX;
\r
976 var pageY = event.pageY;
\r
979 * - Position constraining -
\r
980 * Constrain the position to a mix of grid, containment.
\r
983 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
\r
985 if(this.containment) {
\r
986 if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left;
\r
987 if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top;
\r
988 if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left;
\r
989 if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top;
\r
993 var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
\r
994 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;
\r
996 var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
\r
997 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;
\r
1004 pageY // The absolute mouse position
\r
1005 - this.offset.click.top // Click offset (relative to the element)
\r
1006 - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent
\r
1007 - this.offset.parent.top // The offsetParent's offset without borders (offset + border)
\r
1008 + ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
\r
1011 pageX // The absolute mouse position
\r
1012 - this.offset.click.left // Click offset (relative to the element)
\r
1013 - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent
\r
1014 - this.offset.parent.left // The offsetParent's offset without borders (offset + border)
\r
1015 + ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
\r
1021 _clear: function() {
\r
1022 this.helper.removeClass("ui-draggable-dragging");
\r
1023 if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove();
\r
1024 //if($.ui.ddmanager) $.ui.ddmanager.current = null;
\r
1025 this.helper = null;
\r
1026 this.cancelHelperRemoval = false;
\r
1029 // From now on bulk stuff - mainly helpers
\r
1031 _trigger: function(type, event, ui) {
\r
1032 ui = ui || this._uiHash();
\r
1033 $.ui.plugin.call(this, type, [event, ui]);
\r
1034 if(type == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins
\r
1035 return $.Widget.prototype._trigger.call(this, type, event, ui);
\r
1040 _uiHash: function(event) {
\r
1042 helper: this.helper,
\r
1043 position: this.position,
\r
1044 originalPosition: this.originalPosition,
\r
1045 offset: this.positionAbs
\r
1051 $.extend($.ui.draggable, {
\r
1055 $.ui.plugin.add("draggable", "connectToSortable", {
\r
1056 start: function(event, ui) {
\r
1058 var inst = $(this).data("draggable"), o = inst.options,
\r
1059 uiSortable = $.extend({}, ui, { item: inst.element });
\r
1060 inst.sortables = [];
\r
1061 $(o.connectToSortable).each(function() {
\r
1062 var sortable = $.data(this, 'sortable');
\r
1063 if (sortable && !sortable.options.disabled) {
\r
1064 inst.sortables.push({
\r
1065 instance: sortable,
\r
1066 shouldRevert: sortable.options.revert
\r
1068 sortable._refreshItems(); //Do a one-time refresh at start to refresh the containerCache
\r
1069 sortable._trigger("activate", event, uiSortable);
\r
1074 stop: function(event, ui) {
\r
1076 //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
\r
1077 var inst = $(this).data("draggable"),
\r
1078 uiSortable = $.extend({}, ui, { item: inst.element });
\r
1080 $.each(inst.sortables, function() {
\r
1081 if(this.instance.isOver) {
\r
1083 this.instance.isOver = 0;
\r
1085 inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
\r
1086 this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
\r
1088 //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid'
\r
1089 if(this.shouldRevert) this.instance.options.revert = true;
\r
1091 //Trigger the stop of the sortable
\r
1092 this.instance._mouseStop(event);
\r
1094 this.instance.options.helper = this.instance.options._helper;
\r
1096 //If the helper has been the original item, restore properties in the sortable
\r
1097 if(inst.options.helper == 'original')
\r
1098 this.instance.currentItem.css({ top: 'auto', left: 'auto' });
\r
1101 this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
\r
1102 this.instance._trigger("deactivate", event, uiSortable);
\r
1108 drag: function(event, ui) {
\r
1110 var inst = $(this).data("draggable"), self = this;
\r
1112 var checkPos = function(o) {
\r
1113 var dyClick = this.offset.click.top, dxClick = this.offset.click.left;
\r
1114 var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left;
\r
1115 var itemHeight = o.height, itemWidth = o.width;
\r
1116 var itemTop = o.top, itemLeft = o.left;
\r
1118 return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth);
\r
1121 $.each(inst.sortables, function(i) {
\r
1123 //Copy over some variables to allow calling the sortable's native _intersectsWith
\r
1124 this.instance.positionAbs = inst.positionAbs;
\r
1125 this.instance.helperProportions = inst.helperProportions;
\r
1126 this.instance.offset.click = inst.offset.click;
\r
1128 if(this.instance._intersectsWith(this.instance.containerCache)) {
\r
1130 //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
\r
1131 if(!this.instance.isOver) {
\r
1133 this.instance.isOver = 1;
\r
1134 //Now we fake the start of dragging for the sortable instance,
\r
1135 //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
\r
1136 //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)
\r
1137 this.instance.currentItem = $(self).clone().appendTo(this.instance.element).data("sortable-item", true);
\r
1138 this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
\r
1139 this.instance.options.helper = function() { return ui.helper[0]; };
\r
1141 event.target = this.instance.currentItem[0];
\r
1142 this.instance._mouseCapture(event, true);
\r
1143 this.instance._mouseStart(event, true, true);
\r
1145 //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
\r
1146 this.instance.offset.click.top = inst.offset.click.top;
\r
1147 this.instance.offset.click.left = inst.offset.click.left;
\r
1148 this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
\r
1149 this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
\r
1151 inst._trigger("toSortable", event);
\r
1152 inst.dropped = this.instance.element; //draggable revert needs that
\r
1153 //hack so receive/update callbacks work (mostly)
\r
1154 inst.currentItem = inst.element;
\r
1155 this.instance.fromOutside = inst;
\r
1159 //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
\r
1160 if(this.instance.currentItem) this.instance._mouseDrag(event);
\r
1164 //If it doesn't intersect with the sortable, and it intersected before,
\r
1165 //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
\r
1166 if(this.instance.isOver) {
\r
1168 this.instance.isOver = 0;
\r
1169 this.instance.cancelHelperRemoval = true;
\r
1171 //Prevent reverting on this forced stop
\r
1172 this.instance.options.revert = false;
\r
1174 // The out event needs to be triggered independently
\r
1175 this.instance._trigger('out', event, this.instance._uiHash(this.instance));
\r
1177 this.instance._mouseStop(event, true);
\r
1178 this.instance.options.helper = this.instance.options._helper;
\r
1180 //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
\r
1181 this.instance.currentItem.remove();
\r
1182 if(this.instance.placeholder) this.instance.placeholder.remove();
\r
1184 inst._trigger("fromSortable", event);
\r
1185 inst.dropped = false; //draggable revert needs that
\r
1195 $.ui.plugin.add("draggable", "cursor", {
\r
1196 start: function(event, ui) {
\r
1197 var t = $('body'), o = $(this).data('draggable').options;
\r
1198 if (t.css("cursor")) o._cursor = t.css("cursor");
\r
1199 t.css("cursor", o.cursor);
\r
1201 stop: function(event, ui) {
\r
1202 var o = $(this).data('draggable').options;
\r
1203 if (o._cursor) $('body').css("cursor", o._cursor);
\r
1207 $.ui.plugin.add("draggable", "iframeFix", {
\r
1208 start: function(event, ui) {
\r
1209 var o = $(this).data('draggable').options;
\r
1210 $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
\r
1211 $('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>')
\r
1213 width: this.offsetWidth+"px", height: this.offsetHeight+"px",
\r
1214 position: "absolute", opacity: "0.001", zIndex: 1000
\r
1216 .css($(this).offset())
\r
1217 .appendTo("body");
\r
1220 stop: function(event, ui) {
\r
1221 $("div.ui-draggable-iframeFix").each(function() { this.parentNode.removeChild(this); }); //Remove frame helpers
\r
1225 $.ui.plugin.add("draggable", "opacity", {
\r
1226 start: function(event, ui) {
\r
1227 var t = $(ui.helper), o = $(this).data('draggable').options;
\r
1228 if(t.css("opacity")) o._opacity = t.css("opacity");
\r
1229 t.css('opacity', o.opacity);
\r
1231 stop: function(event, ui) {
\r
1232 var o = $(this).data('draggable').options;
\r
1233 if(o._opacity) $(ui.helper).css('opacity', o._opacity);
\r
1237 $.ui.plugin.add("draggable", "scroll", {
\r
1238 start: function(event, ui) {
\r
1239 var i = $(this).data("draggable");
\r
1240 if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset();
\r
1242 drag: function(event, ui) {
\r
1244 var i = $(this).data("draggable"), o = i.options, scrolled = false;
\r
1246 if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') {
\r
1248 if(!o.axis || o.axis != 'x') {
\r
1249 if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
\r
1250 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
\r
1251 else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity)
\r
1252 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
\r
1255 if(!o.axis || o.axis != 'y') {
\r
1256 if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
\r
1257 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
\r
1258 else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity)
\r
1259 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
\r
1264 if(!o.axis || o.axis != 'x') {
\r
1265 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
\r
1266 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
\r
1267 else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
\r
1268 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
\r
1271 if(!o.axis || o.axis != 'y') {
\r
1272 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
\r
1273 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
\r
1274 else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
\r
1275 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
\r
1280 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
\r
1281 $.ui.ddmanager.prepareOffsets(i, event);
\r
1286 $.ui.plugin.add("draggable", "snap", {
\r
1287 start: function(event, ui) {
\r
1289 var i = $(this).data("draggable"), o = i.options;
\r
1290 i.snapElements = [];
\r
1292 $(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) : o.snap).each(function() {
\r
1293 var $t = $(this); var $o = $t.offset();
\r
1294 if(this != i.element[0]) i.snapElements.push({
\r
1296 width: $t.outerWidth(), height: $t.outerHeight(),
\r
1297 top: $o.top, left: $o.left
\r
1302 drag: function(event, ui) {
\r
1304 var inst = $(this).data("draggable"), o = inst.options;
\r
1305 var d = o.snapTolerance;
\r
1307 var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
\r
1308 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
\r
1310 for (var i = inst.snapElements.length - 1; i >= 0; i--){
\r
1312 var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width,
\r
1313 t = inst.snapElements[i].top, b = t + inst.snapElements[i].height;
\r
1315 //Yes, I know, this is insane ;)
\r
1316 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))) {
\r
1317 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 })));
\r
1318 inst.snapElements[i].snapping = false;
\r
1322 if(o.snapMode != 'inner') {
\r
1323 var ts = Math.abs(t - y2) <= d;
\r
1324 var bs = Math.abs(b - y1) <= d;
\r
1325 var ls = Math.abs(l - x2) <= d;
\r
1326 var rs = Math.abs(r - x1) <= d;
\r
1327 if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
\r
1328 if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
\r
1329 if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
\r
1330 if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
\r
1333 var first = (ts || bs || ls || rs);
\r
1335 if(o.snapMode != 'outer') {
\r
1336 var ts = Math.abs(t - y1) <= d;
\r
1337 var bs = Math.abs(b - y2) <= d;
\r
1338 var ls = Math.abs(l - x1) <= d;
\r
1339 var rs = Math.abs(r - x2) <= d;
\r
1340 if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
\r
1341 if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
\r
1342 if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
\r
1343 if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
\r
1346 if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first))
\r
1347 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
\r
1348 inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
\r
1355 $.ui.plugin.add("draggable", "stack", {
\r
1356 start: function(event, ui) {
\r
1358 var o = $(this).data("draggable").options;
\r
1360 var group = $.makeArray($(o.stack)).sort(function(a,b) {
\r
1361 return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0);
\r
1363 if (!group.length) { return; }
\r
1365 var min = parseInt(group[0].style.zIndex) || 0;
\r
1366 $(group).each(function(i) {
\r
1367 this.style.zIndex = min + i;
\r
1370 this[0].style.zIndex = min + group.length;
\r
1375 $.ui.plugin.add("draggable", "zIndex", {
\r
1376 start: function(event, ui) {
\r
1377 var t = $(ui.helper), o = $(this).data("draggable").options;
\r
1378 if(t.css("zIndex")) o._zIndex = t.css("zIndex");
\r
1379 t.css('zIndex', o.zIndex);
\r
1381 stop: function(event, ui) {
\r
1382 var o = $(this).data("draggable").options;
\r
1383 if(o._zIndex) $(ui.helper).css('zIndex', o._zIndex);
\r
1389 * jQuery UI Droppable 1.8
\r
1391 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
1392 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
1393 * and GPL (GPL-LICENSE.txt) licenses.
\r
1395 * http://docs.jquery.com/UI/Droppables
\r
1398 * jquery.ui.core.js
\r
1399 * jquery.ui.widget.js
\r
1400 * jquery.ui.mouse.js
\r
1401 * jquery.ui.draggable.js
\r
1405 $.widget("ui.droppable", {
\r
1406 widgetEventPrefix: "drop",
\r
1409 activeClass: false,
\r
1412 hoverClass: false,
\r
1414 tolerance: 'intersect'
\r
1416 _create: function() {
\r
1418 var o = this.options, accept = o.accept;
\r
1419 this.isover = 0; this.isout = 1;
\r
1421 this.accept = $.isFunction(accept) ? accept : function(d) {
\r
1422 return d.is(accept);
\r
1425 //Store the droppable's proportions
\r
1426 this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight };
\r
1428 // Add the reference and positions to the manager
\r
1429 $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || [];
\r
1430 $.ui.ddmanager.droppables[o.scope].push(this);
\r
1432 (o.addClasses && this.element.addClass("ui-droppable"));
\r
1436 destroy: function() {
\r
1437 var drop = $.ui.ddmanager.droppables[this.options.scope];
\r
1438 for ( var i = 0; i < drop.length; i++ )
\r
1439 if ( drop[i] == this )
\r
1440 drop.splice(i, 1);
\r
1443 .removeClass("ui-droppable ui-droppable-disabled")
\r
1444 .removeData("droppable")
\r
1445 .unbind(".droppable");
\r
1450 _setOption: function(key, value) {
\r
1452 if(key == 'accept') {
\r
1453 this.accept = $.isFunction(value) ? value : function(d) {
\r
1454 return d.is(value);
\r
1457 $.Widget.prototype._setOption.apply(this, arguments);
\r
1460 _activate: function(event) {
\r
1461 var draggable = $.ui.ddmanager.current;
\r
1462 if(this.options.activeClass) this.element.addClass(this.options.activeClass);
\r
1463 (draggable && this._trigger('activate', event, this.ui(draggable)));
\r
1466 _deactivate: function(event) {
\r
1467 var draggable = $.ui.ddmanager.current;
\r
1468 if(this.options.activeClass) this.element.removeClass(this.options.activeClass);
\r
1469 (draggable && this._trigger('deactivate', event, this.ui(draggable)));
\r
1472 _over: function(event) {
\r
1474 var draggable = $.ui.ddmanager.current;
\r
1475 if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element
\r
1477 if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
\r
1478 if(this.options.hoverClass) this.element.addClass(this.options.hoverClass);
\r
1479 this._trigger('over', event, this.ui(draggable));
\r
1484 _out: function(event) {
\r
1486 var draggable = $.ui.ddmanager.current;
\r
1487 if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element
\r
1489 if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
\r
1490 if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass);
\r
1491 this._trigger('out', event, this.ui(draggable));
\r
1496 _drop: function(event,custom) {
\r
1498 var draggable = custom || $.ui.ddmanager.current;
\r
1499 if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element
\r
1501 var childrenIntersection = false;
\r
1502 this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function() {
\r
1503 var inst = $.data(this, 'droppable');
\r
1505 inst.options.greedy
\r
1506 && !inst.options.disabled
\r
1507 && inst.options.scope == draggable.options.scope
\r
1508 && inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element))
\r
1509 && $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)
\r
1510 ) { childrenIntersection = true; return false; }
\r
1512 if(childrenIntersection) return false;
\r
1514 if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
\r
1515 if(this.options.activeClass) this.element.removeClass(this.options.activeClass);
\r
1516 if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass);
\r
1517 this._trigger('drop', event, this.ui(draggable));
\r
1518 return this.element;
\r
1527 draggable: (c.currentItem || c.element),
\r
1529 position: c.position,
\r
1530 offset: c.positionAbs
\r
1536 $.extend($.ui.droppable, {
\r
1540 $.ui.intersect = function(draggable, droppable, toleranceMode) {
\r
1542 if (!droppable.offset) return false;
\r
1544 var x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width,
\r
1545 y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height;
\r
1546 var l = droppable.offset.left, r = l + droppable.proportions.width,
\r
1547 t = droppable.offset.top, b = t + droppable.proportions.height;
\r
1549 switch (toleranceMode) {
\r
1551 return (l < x1 && x2 < r
\r
1552 && t < y1 && y2 < b);
\r
1555 return (l < x1 + (draggable.helperProportions.width / 2) // Right Half
\r
1556 && x2 - (draggable.helperProportions.width / 2) < r // Left Half
\r
1557 && t < y1 + (draggable.helperProportions.height / 2) // Bottom Half
\r
1558 && y2 - (draggable.helperProportions.height / 2) < b ); // Top Half
\r
1561 var draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left),
\r
1562 draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top),
\r
1563 isOver = $.ui.isOver(draggableTop, draggableLeft, t, l, droppable.proportions.height, droppable.proportions.width);
\r
1568 (y1 >= t && y1 <= b) || // Top edge touching
\r
1569 (y2 >= t && y2 <= b) || // Bottom edge touching
\r
1570 (y1 < t && y2 > b) // Surrounded vertically
\r
1572 (x1 >= l && x1 <= r) || // Left edge touching
\r
1573 (x2 >= l && x2 <= r) || // Right edge touching
\r
1574 (x1 < l && x2 > r) // Surrounded horizontally
\r
1585 This manager tracks offsets of draggables and droppables
\r
1587 $.ui.ddmanager = {
\r
1589 droppables: { 'default': [] },
\r
1590 prepareOffsets: function(t, event) {
\r
1592 var m = $.ui.ddmanager.droppables[t.options.scope] || [];
\r
1593 var type = event ? event.type : null; // workaround for #2317
\r
1594 var list = (t.currentItem || t.element).find(":data(droppable)").andSelf();
\r
1596 droppablesLoop: for (var i = 0; i < m.length; i++) {
\r
1598 if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) continue; //No disabled and non-accepted
\r
1599 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
\r
1600 m[i].visible = m[i].element.css("display") != "none"; if(!m[i].visible) continue; //If the element is not visible, continue
\r
1602 m[i].offset = m[i].element.offset();
\r
1603 m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight };
\r
1605 if(type == "mousedown") m[i]._activate.call(m[i], event); //Activate the droppable if used directly from draggables
\r
1610 drop: function(draggable, event) {
\r
1612 var dropped = false;
\r
1613 $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
\r
1615 if(!this.options) return;
\r
1616 if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance))
\r
1617 dropped = dropped || this._drop.call(this, event);
\r
1619 if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
\r
1620 this.isout = 1; this.isover = 0;
\r
1621 this._deactivate.call(this, event);
\r
1628 drag: function(draggable, event) {
\r
1630 //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
\r
1631 if(draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event);
\r
1633 //Run through all droppables and check their positions based on specific tolerance options
\r
1634 $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
\r
1636 if(this.options.disabled || this.greedyChild || !this.visible) return;
\r
1637 var intersects = $.ui.intersect(draggable, this, this.options.tolerance);
\r
1639 var c = !intersects && this.isover == 1 ? 'isout' : (intersects && this.isover == 0 ? 'isover' : null);
\r
1642 var parentInstance;
\r
1643 if (this.options.greedy) {
\r
1644 var parent = this.element.parents(':data(droppable):eq(0)');
\r
1645 if (parent.length) {
\r
1646 parentInstance = $.data(parent[0], 'droppable');
\r
1647 parentInstance.greedyChild = (c == 'isover' ? 1 : 0);
\r
1651 // we just moved into a greedy child
\r
1652 if (parentInstance && c == 'isover') {
\r
1653 parentInstance['isover'] = 0;
\r
1654 parentInstance['isout'] = 1;
\r
1655 parentInstance._out.call(parentInstance, event);
\r
1658 this[c] = 1; this[c == 'isout' ? 'isover' : 'isout'] = 0;
\r
1659 this[c == "isover" ? "_over" : "_out"].call(this, event);
\r
1661 // we just moved out of a greedy child
\r
1662 if (parentInstance && c == 'isout') {
\r
1663 parentInstance['isout'] = 0;
\r
1664 parentInstance['isover'] = 1;
\r
1665 parentInstance._over.call(parentInstance, event);
\r
1674 * jQuery UI Resizable 1.8
\r
1676 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
1677 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
1678 * and GPL (GPL-LICENSE.txt) licenses.
\r
1680 * http://docs.jquery.com/UI/Resizables
\r
1683 * jquery.ui.core.js
\r
1684 * jquery.ui.mouse.js
\r
1685 * jquery.ui.widget.js
\r
1689 $.widget("ui.resizable", $.ui.mouse, {
\r
1690 widgetEventPrefix: "resize",
\r
1692 alsoResize: false,
\r
1694 animateDuration: "slow",
\r
1695 animateEasing: "swing",
\r
1696 aspectRatio: false,
\r
1698 containment: false,
\r
1701 handles: "e,s,se",
\r
1709 _create: function() {
\r
1711 var self = this, o = this.options;
\r
1712 this.element.addClass("ui-resizable");
\r
1715 _aspectRatio: !!(o.aspectRatio),
\r
1716 aspectRatio: o.aspectRatio,
\r
1717 originalElement: this.element,
\r
1718 _proportionallyResizeElements: [],
\r
1719 _helper: o.helper || o.ghost || o.animate ? o.helper || 'ui-resizable-helper' : null
\r
1722 //Wrap the element if it cannot hold child nodes
\r
1723 if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {
\r
1725 //Opera fix for relative positioning
\r
1726 if (/relative/.test(this.element.css('position')) && $.browser.opera)
\r
1727 this.element.css({ position: 'relative', top: 'auto', left: 'auto' });
\r
1729 //Create a wrapper element and set the wrapper to the new current internal element
\r
1730 this.element.wrap(
\r
1731 $('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({
\r
1732 position: this.element.css('position'),
\r
1733 width: this.element.outerWidth(),
\r
1734 height: this.element.outerHeight(),
\r
1735 top: this.element.css('top'),
\r
1736 left: this.element.css('left')
\r
1740 //Overwrite the original this.element
\r
1741 this.element = this.element.parent().data(
\r
1742 "resizable", this.element.data('resizable')
\r
1745 this.elementIsWrapper = true;
\r
1747 //Move margins to the wrapper
\r
1748 this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") });
\r
1749 this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});
\r
1751 //Prevent Safari textarea resize
\r
1752 this.originalResizeStyle = this.originalElement.css('resize');
\r
1753 this.originalElement.css('resize', 'none');
\r
1755 //Push the actual element to our proportionallyResize internal array
\r
1756 this._proportionallyResizeElements.push(this.originalElement.css({ position: 'static', zoom: 1, display: 'block' }));
\r
1758 // avoid IE jump (hard set the margin)
\r
1759 this.originalElement.css({ margin: this.originalElement.css('margin') });
\r
1761 // fix handlers offset
\r
1762 this._proportionallyResize();
\r
1766 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' });
\r
1767 if(this.handles.constructor == String) {
\r
1769 if(this.handles == 'all') this.handles = 'n,e,s,w,se,sw,ne,nw';
\r
1770 var n = this.handles.split(","); this.handles = {};
\r
1772 for(var i = 0; i < n.length; i++) {
\r
1774 var handle = $.trim(n[i]), hname = 'ui-resizable-'+handle;
\r
1775 var axis = $('<div class="ui-resizable-handle ' + hname + '"></div>');
\r
1777 // increase zIndex of sw, se, ne, nw axis
\r
1778 //TODO : this modifies original option
\r
1779 if(/sw|se|ne|nw/.test(handle)) axis.css({ zIndex: ++o.zIndex });
\r
1781 //TODO : What's going on here?
\r
1782 if ('se' == handle) {
\r
1783 axis.addClass('ui-icon ui-icon-gripsmall-diagonal-se');
\r
1786 //Insert into internal handles object and append to element
\r
1787 this.handles[handle] = '.ui-resizable-'+handle;
\r
1788 this.element.append(axis);
\r
1793 this._renderAxis = function(target) {
\r
1795 target = target || this.element;
\r
1797 for(var i in this.handles) {
\r
1799 if(this.handles[i].constructor == String)
\r
1800 this.handles[i] = $(this.handles[i], this.element).show();
\r
1802 //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)
\r
1803 if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {
\r
1805 var axis = $(this.handles[i], this.element), padWrapper = 0;
\r
1807 //Checking the correct pad and border
\r
1808 padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
\r
1810 //The padding type i have to apply...
\r
1811 var padPos = [ 'padding',
\r
1812 /ne|nw|n/.test(i) ? 'Top' :
\r
1813 /se|sw|s/.test(i) ? 'Bottom' :
\r
1814 /^e$/.test(i) ? 'Right' : 'Left' ].join("");
\r
1816 target.css(padPos, padWrapper);
\r
1818 this._proportionallyResize();
\r
1822 //TODO: What's that good for? There's not anything to be executed left
\r
1823 if(!$(this.handles[i]).length)
\r
1829 //TODO: make renderAxis a prototype function
\r
1830 this._renderAxis(this.element);
\r
1832 this._handles = $('.ui-resizable-handle', this.element)
\r
1833 .disableSelection();
\r
1835 //Matching axis name
\r
1836 this._handles.mouseover(function() {
\r
1837 if (!self.resizing) {
\r
1838 if (this.className)
\r
1839 var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
\r
1840 //Axis, default = se
\r
1841 self.axis = axis && axis[1] ? axis[1] : 'se';
\r
1845 //If we want to auto hide the elements
\r
1847 this._handles.hide();
\r
1849 .addClass("ui-resizable-autohide")
\r
1850 .hover(function() {
\r
1851 $(this).removeClass("ui-resizable-autohide");
\r
1852 self._handles.show();
\r
1855 if (!self.resizing) {
\r
1856 $(this).addClass("ui-resizable-autohide");
\r
1857 self._handles.hide();
\r
1862 //Initialize the mouse interaction
\r
1863 this._mouseInit();
\r
1867 destroy: function() {
\r
1869 this._mouseDestroy();
\r
1871 var _destroy = function(exp) {
\r
1872 $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
\r
1873 .removeData("resizable").unbind(".resizable").find('.ui-resizable-handle').remove();
\r
1876 //TODO: Unwrap at same DOM position
\r
1877 if (this.elementIsWrapper) {
\r
1878 _destroy(this.element);
\r
1879 var wrapper = this.element;
\r
1881 this.originalElement.css({
\r
1882 position: wrapper.css('position'),
\r
1883 width: wrapper.outerWidth(),
\r
1884 height: wrapper.outerHeight(),
\r
1885 top: wrapper.css('top'),
\r
1886 left: wrapper.css('left')
\r
1891 this.originalElement.css('resize', this.originalResizeStyle);
\r
1892 _destroy(this.originalElement);
\r
1897 _mouseCapture: function(event) {
\r
1898 var handle = false;
\r
1899 for (var i in this.handles) {
\r
1900 if ($(this.handles[i])[0] == event.target) {
\r
1905 return !this.options.disabled && handle;
\r
1908 _mouseStart: function(event) {
\r
1910 var o = this.options, iniPos = this.element.position(), el = this.element;
\r
1912 this.resizing = true;
\r
1913 this.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() };
\r
1915 // bugfix for http://dev.jquery.com/ticket/1749
\r
1916 if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) {
\r
1917 el.css({ position: 'absolute', top: iniPos.top, left: iniPos.left });
\r
1920 //Opera fixing relative position
\r
1921 if ($.browser.opera && (/relative/).test(el.css('position')))
\r
1922 el.css({ position: 'relative', top: 'auto', left: 'auto' });
\r
1924 this._renderProxy();
\r
1926 var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top'));
\r
1928 if (o.containment) {
\r
1929 curleft += $(o.containment).scrollLeft() || 0;
\r
1930 curtop += $(o.containment).scrollTop() || 0;
\r
1933 //Store needed variables
\r
1934 this.offset = this.helper.offset();
\r
1935 this.position = { left: curleft, top: curtop };
\r
1936 this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
\r
1937 this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
\r
1938 this.originalPosition = { left: curleft, top: curtop };
\r
1939 this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };
\r
1940 this.originalMousePosition = { left: event.pageX, top: event.pageY };
\r
1943 this.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1);
\r
1945 var cursor = $('.ui-resizable-' + this.axis).css('cursor');
\r
1946 $('body').css('cursor', cursor == 'auto' ? this.axis + '-resize' : cursor);
\r
1948 el.addClass("ui-resizable-resizing");
\r
1949 this._propagate("start", event);
\r
1953 _mouseDrag: function(event) {
\r
1955 //Increase performance, avoid regex
\r
1956 var el = this.helper, o = this.options, props = {},
\r
1957 self = this, smp = this.originalMousePosition, a = this.axis;
\r
1959 var dx = (event.pageX-smp.left)||0, dy = (event.pageY-smp.top)||0;
\r
1960 var trigger = this._change[a];
\r
1961 if (!trigger) return false;
\r
1963 // Calculate the attrs that will be change
\r
1964 var data = trigger.apply(this, [event, dx, dy]), ie6 = $.browser.msie && $.browser.version < 7, csdif = this.sizeDiff;
\r
1966 if (this._aspectRatio || event.shiftKey)
\r
1967 data = this._updateRatio(data, event);
\r
1969 data = this._respectSize(data, event);
\r
1971 // plugins callbacks need to be called first
\r
1972 this._propagate("resize", event);
\r
1975 top: this.position.top + "px", left: this.position.left + "px",
\r
1976 width: this.size.width + "px", height: this.size.height + "px"
\r
1979 if (!this._helper && this._proportionallyResizeElements.length)
\r
1980 this._proportionallyResize();
\r
1982 this._updateCache(data);
\r
1984 // calling the user callback at the end
\r
1985 this._trigger('resize', event, this.ui());
\r
1990 _mouseStop: function(event) {
\r
1992 this.resizing = false;
\r
1993 var o = this.options, self = this;
\r
1995 if(this._helper) {
\r
1996 var pr = this._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName),
\r
1997 soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height,
\r
1998 soffsetw = ista ? 0 : self.sizeDiff.width;
\r
2000 var s = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) },
\r
2001 left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null,
\r
2002 top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null;
\r
2005 this.element.css($.extend(s, { top: top, left: left }));
\r
2007 self.helper.height(self.size.height);
\r
2008 self.helper.width(self.size.width);
\r
2010 if (this._helper && !o.animate) this._proportionallyResize();
\r
2013 $('body').css('cursor', 'auto');
\r
2015 this.element.removeClass("ui-resizable-resizing");
\r
2017 this._propagate("stop", event);
\r
2019 if (this._helper) this.helper.remove();
\r
2024 _updateCache: function(data) {
\r
2025 var o = this.options;
\r
2026 this.offset = this.helper.offset();
\r
2027 if (isNumber(data.left)) this.position.left = data.left;
\r
2028 if (isNumber(data.top)) this.position.top = data.top;
\r
2029 if (isNumber(data.height)) this.size.height = data.height;
\r
2030 if (isNumber(data.width)) this.size.width = data.width;
\r
2033 _updateRatio: function(data, event) {
\r
2035 var o = this.options, cpos = this.position, csize = this.size, a = this.axis;
\r
2037 if (data.height) data.width = (csize.height * this.aspectRatio);
\r
2038 else if (data.width) data.height = (csize.width / this.aspectRatio);
\r
2041 data.left = cpos.left + (csize.width - data.width);
\r
2045 data.top = cpos.top + (csize.height - data.height);
\r
2046 data.left = cpos.left + (csize.width - data.width);
\r
2052 _respectSize: function(data, event) {
\r
2054 var el = this.helper, o = this.options, pRatio = this._aspectRatio || event.shiftKey, a = this.axis,
\r
2055 ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
\r
2056 isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height);
\r
2058 if (isminw) data.width = o.minWidth;
\r
2059 if (isminh) data.height = o.minHeight;
\r
2060 if (ismaxw) data.width = o.maxWidth;
\r
2061 if (ismaxh) data.height = o.maxHeight;
\r
2063 var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height;
\r
2064 var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
\r
2066 if (isminw && cw) data.left = dw - o.minWidth;
\r
2067 if (ismaxw && cw) data.left = dw - o.maxWidth;
\r
2068 if (isminh && ch) data.top = dh - o.minHeight;
\r
2069 if (ismaxh && ch) data.top = dh - o.maxHeight;
\r
2071 // fixing jump error on top/left - bug #2330
\r
2072 var isNotwh = !data.width && !data.height;
\r
2073 if (isNotwh && !data.left && data.top) data.top = null;
\r
2074 else if (isNotwh && !data.top && data.left) data.left = null;
\r
2079 _proportionallyResize: function() {
\r
2081 var o = this.options;
\r
2082 if (!this._proportionallyResizeElements.length) return;
\r
2083 var element = this.helper || this.element;
\r
2085 for (var i=0; i < this._proportionallyResizeElements.length; i++) {
\r
2087 var prel = this._proportionallyResizeElements[i];
\r
2089 if (!this.borderDif) {
\r
2090 var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')],
\r
2091 p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')];
\r
2093 this.borderDif = $.map(b, function(v, i) {
\r
2094 var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0;
\r
2095 return border + padding;
\r
2099 if ($.browser.msie && !(!($(element).is(':hidden') || $(element).parents(':hidden').length)))
\r
2103 height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0,
\r
2104 width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0
\r
2111 _renderProxy: function() {
\r
2113 var el = this.element, o = this.options;
\r
2114 this.elementOffset = el.offset();
\r
2116 if(this._helper) {
\r
2118 this.helper = this.helper || $('<div style="overflow:hidden;"></div>');
\r
2120 // fix ie6 offset TODO: This seems broken
\r
2121 var ie6 = $.browser.msie && $.browser.version < 7, ie6offset = (ie6 ? 1 : 0),
\r
2122 pxyoffset = ( ie6 ? 2 : -1 );
\r
2124 this.helper.addClass(this._helper).css({
\r
2125 width: this.element.outerWidth() + pxyoffset,
\r
2126 height: this.element.outerHeight() + pxyoffset,
\r
2127 position: 'absolute',
\r
2128 left: this.elementOffset.left - ie6offset +'px',
\r
2129 top: this.elementOffset.top - ie6offset +'px',
\r
2130 zIndex: ++o.zIndex //TODO: Don't modify option
\r
2135 .disableSelection();
\r
2138 this.helper = this.element;
\r
2144 e: function(event, dx, dy) {
\r
2145 return { width: this.originalSize.width + dx };
\r
2147 w: function(event, dx, dy) {
\r
2148 var o = this.options, cs = this.originalSize, sp = this.originalPosition;
\r
2149 return { left: sp.left + dx, width: cs.width - dx };
\r
2151 n: function(event, dx, dy) {
\r
2152 var o = this.options, cs = this.originalSize, sp = this.originalPosition;
\r
2153 return { top: sp.top + dy, height: cs.height - dy };
\r
2155 s: function(event, dx, dy) {
\r
2156 return { height: this.originalSize.height + dy };
\r
2158 se: function(event, dx, dy) {
\r
2159 return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
\r
2161 sw: function(event, dx, dy) {
\r
2162 return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
\r
2164 ne: function(event, dx, dy) {
\r
2165 return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
\r
2167 nw: function(event, dx, dy) {
\r
2168 return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
\r
2172 _propagate: function(n, event) {
\r
2173 $.ui.plugin.call(this, n, [event, this.ui()]);
\r
2174 (n != "resize" && this._trigger(n, event, this.ui()));
\r
2181 originalElement: this.originalElement,
\r
2182 element: this.element,
\r
2183 helper: this.helper,
\r
2184 position: this.position,
\r
2186 originalSize: this.originalSize,
\r
2187 originalPosition: this.originalPosition
\r
2193 $.extend($.ui.resizable, {
\r
2198 * Resizable Extensions
\r
2201 $.ui.plugin.add("resizable", "alsoResize", {
\r
2203 start: function(event, ui) {
\r
2205 var self = $(this).data("resizable"), o = self.options;
\r
2207 var _store = function(exp) {
\r
2208 $(exp).each(function() {
\r
2209 $(this).data("resizable-alsoresize", {
\r
2210 width: parseInt($(this).width(), 10), height: parseInt($(this).height(), 10),
\r
2211 left: parseInt($(this).css('left'), 10), top: parseInt($(this).css('top'), 10)
\r
2216 if (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) {
\r
2217 if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); }
\r
2218 else { $.each(o.alsoResize, function(exp, c) { _store(exp); }); }
\r
2220 _store(o.alsoResize);
\r
2224 resize: function(event, ui){
\r
2225 var self = $(this).data("resizable"), o = self.options, os = self.originalSize, op = self.originalPosition;
\r
2228 height: (self.size.height - os.height) || 0, width: (self.size.width - os.width) || 0,
\r
2229 top: (self.position.top - op.top) || 0, left: (self.position.left - op.left) || 0
\r
2232 _alsoResize = function(exp, c) {
\r
2233 $(exp).each(function() {
\r
2234 var el = $(this), start = $(this).data("resizable-alsoresize"), style = {}, css = c && c.length ? c : ['width', 'height', 'top', 'left'];
\r
2236 $.each(css || ['width', 'height', 'top', 'left'], function(i, prop) {
\r
2237 var sum = (start[prop]||0) + (delta[prop]||0);
\r
2238 if (sum && sum >= 0)
\r
2239 style[prop] = sum || null;
\r
2242 //Opera fixing relative position
\r
2243 if (/relative/.test(el.css('position')) && $.browser.opera) {
\r
2244 self._revertToRelativePosition = true;
\r
2245 el.css({ position: 'absolute', top: 'auto', left: 'auto' });
\r
2252 if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) {
\r
2253 $.each(o.alsoResize, function(exp, c) { _alsoResize(exp, c); });
\r
2255 _alsoResize(o.alsoResize);
\r
2259 stop: function(event, ui){
\r
2260 var self = $(this).data("resizable");
\r
2262 //Opera fixing relative position
\r
2263 if (self._revertToRelativePosition && $.browser.opera) {
\r
2264 self._revertToRelativePosition = false;
\r
2265 el.css({ position: 'relative' });
\r
2268 $(this).removeData("resizable-alsoresize-start");
\r
2272 $.ui.plugin.add("resizable", "animate", {
\r
2274 stop: function(event, ui) {
\r
2275 var self = $(this).data("resizable"), o = self.options;
\r
2277 var pr = self._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName),
\r
2278 soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height,
\r
2279 soffsetw = ista ? 0 : self.sizeDiff.width;
\r
2281 var style = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) },
\r
2282 left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null,
\r
2283 top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null;
\r
2285 self.element.animate(
\r
2286 $.extend(style, top && left ? { top: top, left: left } : {}), {
\r
2287 duration: o.animateDuration,
\r
2288 easing: o.animateEasing,
\r
2289 step: function() {
\r
2292 width: parseInt(self.element.css('width'), 10),
\r
2293 height: parseInt(self.element.css('height'), 10),
\r
2294 top: parseInt(self.element.css('top'), 10),
\r
2295 left: parseInt(self.element.css('left'), 10)
\r
2298 if (pr && pr.length) $(pr[0]).css({ width: data.width, height: data.height });
\r
2300 // propagating resize, and updating values for each animation step
\r
2301 self._updateCache(data);
\r
2302 self._propagate("resize", event);
\r
2311 $.ui.plugin.add("resizable", "containment", {
\r
2313 start: function(event, ui) {
\r
2314 var self = $(this).data("resizable"), o = self.options, el = self.element;
\r
2315 var oc = o.containment, ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc;
\r
2318 self.containerElement = $(ce);
\r
2320 if (/document/.test(oc) || oc == document) {
\r
2321 self.containerOffset = { left: 0, top: 0 };
\r
2322 self.containerPosition = { left: 0, top: 0 };
\r
2324 self.parentData = {
\r
2325 element: $(document), left: 0, top: 0,
\r
2326 width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight
\r
2330 // i'm a node, so compute top, left, right, bottom
\r
2332 var element = $(ce), p = [];
\r
2333 $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); });
\r
2335 self.containerOffset = element.offset();
\r
2336 self.containerPosition = element.position();
\r
2337 self.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) };
\r
2339 var co = self.containerOffset, ch = self.containerSize.height, cw = self.containerSize.width,
\r
2340 width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch);
\r
2342 self.parentData = {
\r
2343 element: ce, left: co.left, top: co.top, width: width, height: height
\r
2348 resize: function(event, ui) {
\r
2349 var self = $(this).data("resizable"), o = self.options,
\r
2350 ps = self.containerSize, co = self.containerOffset, cs = self.size, cp = self.position,
\r
2351 pRatio = self._aspectRatio || event.shiftKey, cop = { top:0, left:0 }, ce = self.containerElement;
\r
2353 if (ce[0] != document && (/static/).test(ce.css('position'))) cop = co;
\r
2355 if (cp.left < (self._helper ? co.left : 0)) {
\r
2356 self.size.width = self.size.width + (self._helper ? (self.position.left - co.left) : (self.position.left - cop.left));
\r
2357 if (pRatio) self.size.height = self.size.width / o.aspectRatio;
\r
2358 self.position.left = o.helper ? co.left : 0;
\r
2361 if (cp.top < (self._helper ? co.top : 0)) {
\r
2362 self.size.height = self.size.height + (self._helper ? (self.position.top - co.top) : self.position.top);
\r
2363 if (pRatio) self.size.width = self.size.height * o.aspectRatio;
\r
2364 self.position.top = self._helper ? co.top : 0;
\r
2367 self.offset.left = self.parentData.left+self.position.left;
\r
2368 self.offset.top = self.parentData.top+self.position.top;
\r
2370 var woset = Math.abs( (self._helper ? self.offset.left - cop.left : (self.offset.left - cop.left)) + self.sizeDiff.width ),
\r
2371 hoset = Math.abs( (self._helper ? self.offset.top - cop.top : (self.offset.top - co.top)) + self.sizeDiff.height );
\r
2373 var isParent = self.containerElement.get(0) == self.element.parent().get(0),
\r
2374 isOffsetRelative = /relative|absolute/.test(self.containerElement.css('position'));
\r
2376 if(isParent && isOffsetRelative) woset -= self.parentData.left;
\r
2378 if (woset + self.size.width >= self.parentData.width) {
\r
2379 self.size.width = self.parentData.width - woset;
\r
2380 if (pRatio) self.size.height = self.size.width / self.aspectRatio;
\r
2383 if (hoset + self.size.height >= self.parentData.height) {
\r
2384 self.size.height = self.parentData.height - hoset;
\r
2385 if (pRatio) self.size.width = self.size.height * self.aspectRatio;
\r
2389 stop: function(event, ui){
\r
2390 var self = $(this).data("resizable"), o = self.options, cp = self.position,
\r
2391 co = self.containerOffset, cop = self.containerPosition, ce = self.containerElement;
\r
2393 var helper = $(self.helper), ho = helper.offset(), w = helper.outerWidth() - self.sizeDiff.width, h = helper.outerHeight() - self.sizeDiff.height;
\r
2395 if (self._helper && !o.animate && (/relative/).test(ce.css('position')))
\r
2396 $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
\r
2398 if (self._helper && !o.animate && (/static/).test(ce.css('position')))
\r
2399 $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
\r
2404 $.ui.plugin.add("resizable", "ghost", {
\r
2406 start: function(event, ui) {
\r
2408 var self = $(this).data("resizable"), o = self.options, cs = self.size;
\r
2410 self.ghost = self.originalElement.clone();
\r
2412 .css({ opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 })
\r
2413 .addClass('ui-resizable-ghost')
\r
2414 .addClass(typeof o.ghost == 'string' ? o.ghost : '');
\r
2416 self.ghost.appendTo(self.helper);
\r
2420 resize: function(event, ui){
\r
2421 var self = $(this).data("resizable"), o = self.options;
\r
2422 if (self.ghost) self.ghost.css({ position: 'relative', height: self.size.height, width: self.size.width });
\r
2425 stop: function(event, ui){
\r
2426 var self = $(this).data("resizable"), o = self.options;
\r
2427 if (self.ghost && self.helper) self.helper.get(0).removeChild(self.ghost.get(0));
\r
2432 $.ui.plugin.add("resizable", "grid", {
\r
2434 resize: function(event, ui) {
\r
2435 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;
\r
2436 o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid;
\r
2437 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);
\r
2439 if (/^(se|s|e)$/.test(a)) {
\r
2440 self.size.width = os.width + ox;
\r
2441 self.size.height = os.height + oy;
\r
2443 else if (/^(ne)$/.test(a)) {
\r
2444 self.size.width = os.width + ox;
\r
2445 self.size.height = os.height + oy;
\r
2446 self.position.top = op.top - oy;
\r
2448 else if (/^(sw)$/.test(a)) {
\r
2449 self.size.width = os.width + ox;
\r
2450 self.size.height = os.height + oy;
\r
2451 self.position.left = op.left - ox;
\r
2454 self.size.width = os.width + ox;
\r
2455 self.size.height = os.height + oy;
\r
2456 self.position.top = op.top - oy;
\r
2457 self.position.left = op.left - ox;
\r
2463 var num = function(v) {
\r
2464 return parseInt(v, 10) || 0;
\r
2467 var isNumber = function(value) {
\r
2468 return !isNaN(parseInt(value, 10));
\r
2473 * jQuery UI Selectable 1.8
\r
2475 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
2476 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
2477 * and GPL (GPL-LICENSE.txt) licenses.
\r
2479 * http://docs.jquery.com/UI/Selectables
\r
2482 * jquery.ui.core.js
\r
2483 * jquery.ui.mouse.js
\r
2484 * jquery.ui.widget.js
\r
2488 $.widget("ui.selectable", $.ui.mouse, {
\r
2491 autoRefresh: true,
\r
2494 tolerance: 'touch'
\r
2496 _create: function() {
\r
2499 this.element.addClass("ui-selectable");
\r
2501 this.dragged = false;
\r
2503 // cache selectee children based on filter
\r
2505 this.refresh = function() {
\r
2506 selectees = $(self.options.filter, self.element[0]);
\r
2507 selectees.each(function() {
\r
2508 var $this = $(this);
\r
2509 var pos = $this.offset();
\r
2510 $.data(this, "selectable-item", {
\r
2515 right: pos.left + $this.outerWidth(),
\r
2516 bottom: pos.top + $this.outerHeight(),
\r
2517 startselected: false,
\r
2518 selected: $this.hasClass('ui-selected'),
\r
2519 selecting: $this.hasClass('ui-selecting'),
\r
2520 unselecting: $this.hasClass('ui-unselecting')
\r
2526 this.selectees = selectees.addClass("ui-selectee");
\r
2528 this._mouseInit();
\r
2530 this.helper = $(document.createElement('div'))
\r
2531 .css({border:'1px dotted black'})
\r
2532 .addClass("ui-selectable-helper");
\r
2535 destroy: function() {
\r
2537 .removeClass("ui-selectee")
\r
2538 .removeData("selectable-item");
\r
2540 .removeClass("ui-selectable ui-selectable-disabled")
\r
2541 .removeData("selectable")
\r
2542 .unbind(".selectable");
\r
2543 this._mouseDestroy();
\r
2548 _mouseStart: function(event) {
\r
2551 this.opos = [event.pageX, event.pageY];
\r
2553 if (this.options.disabled)
\r
2556 var options = this.options;
\r
2558 this.selectees = $(options.filter, this.element[0]);
\r
2560 this._trigger("start", event);
\r
2562 $(options.appendTo).append(this.helper);
\r
2563 // position helper (lasso)
\r
2566 "position": "absolute",
\r
2567 "left": event.clientX,
\r
2568 "top": event.clientY,
\r
2573 if (options.autoRefresh) {
\r
2577 this.selectees.filter('.ui-selected').each(function() {
\r
2578 var selectee = $.data(this, "selectable-item");
\r
2579 selectee.startselected = true;
\r
2580 if (!event.metaKey) {
\r
2581 selectee.$element.removeClass('ui-selected');
\r
2582 selectee.selected = false;
\r
2583 selectee.$element.addClass('ui-unselecting');
\r
2584 selectee.unselecting = true;
\r
2585 // selectable UNSELECTING callback
\r
2586 self._trigger("unselecting", event, {
\r
2587 unselecting: selectee.element
\r
2592 $(event.target).parents().andSelf().each(function() {
\r
2593 var selectee = $.data(this, "selectable-item");
\r
2595 selectee.$element.removeClass("ui-unselecting").addClass('ui-selecting');
\r
2596 selectee.unselecting = false;
\r
2597 selectee.selecting = true;
\r
2598 selectee.selected = true;
\r
2599 // selectable SELECTING callback
\r
2600 self._trigger("selecting", event, {
\r
2601 selecting: selectee.element
\r
2609 _mouseDrag: function(event) {
\r
2611 this.dragged = true;
\r
2613 if (this.options.disabled)
\r
2616 var options = this.options;
\r
2618 var x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY;
\r
2619 if (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; }
\r
2620 if (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; }
\r
2621 this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1});
\r
2623 this.selectees.each(function() {
\r
2624 var selectee = $.data(this, "selectable-item");
\r
2625 //prevent helper from being selected if appendTo: selectable
\r
2626 if (!selectee || selectee.element == self.element[0])
\r
2629 if (options.tolerance == 'touch') {
\r
2630 hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
\r
2631 } else if (options.tolerance == 'fit') {
\r
2632 hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
\r
2637 if (selectee.selected) {
\r
2638 selectee.$element.removeClass('ui-selected');
\r
2639 selectee.selected = false;
\r
2641 if (selectee.unselecting) {
\r
2642 selectee.$element.removeClass('ui-unselecting');
\r
2643 selectee.unselecting = false;
\r
2645 if (!selectee.selecting) {
\r
2646 selectee.$element.addClass('ui-selecting');
\r
2647 selectee.selecting = true;
\r
2648 // selectable SELECTING callback
\r
2649 self._trigger("selecting", event, {
\r
2650 selecting: selectee.element
\r
2655 if (selectee.selecting) {
\r
2656 if (event.metaKey && selectee.startselected) {
\r
2657 selectee.$element.removeClass('ui-selecting');
\r
2658 selectee.selecting = false;
\r
2659 selectee.$element.addClass('ui-selected');
\r
2660 selectee.selected = true;
\r
2662 selectee.$element.removeClass('ui-selecting');
\r
2663 selectee.selecting = false;
\r
2664 if (selectee.startselected) {
\r
2665 selectee.$element.addClass('ui-unselecting');
\r
2666 selectee.unselecting = true;
\r
2668 // selectable UNSELECTING callback
\r
2669 self._trigger("unselecting", event, {
\r
2670 unselecting: selectee.element
\r
2674 if (selectee.selected) {
\r
2675 if (!event.metaKey && !selectee.startselected) {
\r
2676 selectee.$element.removeClass('ui-selected');
\r
2677 selectee.selected = false;
\r
2679 selectee.$element.addClass('ui-unselecting');
\r
2680 selectee.unselecting = true;
\r
2681 // selectable UNSELECTING callback
\r
2682 self._trigger("unselecting", event, {
\r
2683 unselecting: selectee.element
\r
2693 _mouseStop: function(event) {
\r
2696 this.dragged = false;
\r
2698 var options = this.options;
\r
2700 $('.ui-unselecting', this.element[0]).each(function() {
\r
2701 var selectee = $.data(this, "selectable-item");
\r
2702 selectee.$element.removeClass('ui-unselecting');
\r
2703 selectee.unselecting = false;
\r
2704 selectee.startselected = false;
\r
2705 self._trigger("unselected", event, {
\r
2706 unselected: selectee.element
\r
2709 $('.ui-selecting', this.element[0]).each(function() {
\r
2710 var selectee = $.data(this, "selectable-item");
\r
2711 selectee.$element.removeClass('ui-selecting').addClass('ui-selected');
\r
2712 selectee.selecting = false;
\r
2713 selectee.selected = true;
\r
2714 selectee.startselected = true;
\r
2715 self._trigger("selected", event, {
\r
2716 selected: selectee.element
\r
2719 this._trigger("stop", event);
\r
2721 this.helper.remove();
\r
2728 $.extend($.ui.selectable, {
\r
2734 * jQuery UI Sortable 1.8
\r
2736 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
2737 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
2738 * and GPL (GPL-LICENSE.txt) licenses.
\r
2740 * http://docs.jquery.com/UI/Sortables
\r
2743 * jquery.ui.core.js
\r
2744 * jquery.ui.mouse.js
\r
2745 * jquery.ui.widget.js
\r
2749 $.widget("ui.sortable", $.ui.mouse, {
\r
2750 widgetEventPrefix: "sort",
\r
2752 appendTo: "parent",
\r
2754 connectWith: false,
\r
2755 containment: false,
\r
2758 dropOnEmpty: true,
\r
2759 forcePlaceholderSize: false,
\r
2760 forceHelperSize: false,
\r
2763 helper: "original",
\r
2766 placeholder: false,
\r
2769 scrollSensitivity: 20,
\r
2772 tolerance: "intersect",
\r
2775 _create: function() {
\r
2777 var o = this.options;
\r
2778 this.containerCache = {};
\r
2779 this.element.addClass("ui-sortable");
\r
2784 //Let's determine if the items are floating
\r
2785 this.floating = this.items.length ? (/left|right/).test(this.items[0].item.css('float')) : false;
\r
2787 //Let's determine the parent's offset
\r
2788 this.offset = this.element.offset();
\r
2790 //Initialize mouse events for interaction
\r
2791 this._mouseInit();
\r
2795 destroy: function() {
\r
2797 .removeClass("ui-sortable ui-sortable-disabled")
\r
2798 .removeData("sortable")
\r
2799 .unbind(".sortable");
\r
2800 this._mouseDestroy();
\r
2802 for ( var i = this.items.length - 1; i >= 0; i-- )
\r
2803 this.items[i].item.removeData("sortable-item");
\r
2808 _mouseCapture: function(event, overrideHandle) {
\r
2810 if (this.reverting) {
\r
2814 if(this.options.disabled || this.options.type == 'static') return false;
\r
2816 //We have to refresh the items data once first
\r
2817 this._refreshItems(event);
\r
2819 //Find out if the clicked node (or one of its parents) is a actual item in this.items
\r
2820 var currentItem = null, self = this, nodes = $(event.target).parents().each(function() {
\r
2821 if($.data(this, 'sortable-item') == self) {
\r
2822 currentItem = $(this);
\r
2826 if($.data(event.target, 'sortable-item') == self) currentItem = $(event.target);
\r
2828 if(!currentItem) return false;
\r
2829 if(this.options.handle && !overrideHandle) {
\r
2830 var validHandle = false;
\r
2832 $(this.options.handle, currentItem).find("*").andSelf().each(function() { if(this == event.target) validHandle = true; });
\r
2833 if(!validHandle) return false;
\r
2836 this.currentItem = currentItem;
\r
2837 this._removeCurrentsFromItems();
\r
2842 _mouseStart: function(event, overrideHandle, noActivation) {
\r
2844 var o = this.options, self = this;
\r
2845 this.currentContainer = this;
\r
2847 //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
\r
2848 this.refreshPositions();
\r
2850 //Create and append the visible helper
\r
2851 this.helper = this._createHelper(event);
\r
2853 //Cache the helper size
\r
2854 this._cacheHelperProportions();
\r
2857 * - Position generation -
\r
2858 * This block generates everything position related - it's the core of draggables.
\r
2861 //Cache the margins of the original element
\r
2862 this._cacheMargins();
\r
2864 //Get the next scrolling parent
\r
2865 this.scrollParent = this.helper.scrollParent();
\r
2867 //The element's absolute position on the page minus margins
\r
2868 this.offset = this.currentItem.offset();
\r
2870 top: this.offset.top - this.margins.top,
\r
2871 left: this.offset.left - this.margins.left
\r
2874 // Only after we got the offset, we can change the helper's position to absolute
\r
2875 // TODO: Still need to figure out a way to make relative sorting possible
\r
2876 this.helper.css("position", "absolute");
\r
2877 this.cssPosition = this.helper.css("position");
\r
2879 $.extend(this.offset, {
\r
2880 click: { //Where the click happened, relative to the element
\r
2881 left: event.pageX - this.offset.left,
\r
2882 top: event.pageY - this.offset.top
\r
2884 parent: this._getParentOffset(),
\r
2885 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
\r
2888 //Generate the original position
\r
2889 this.originalPosition = this._generatePosition(event);
\r
2890 this.originalPageX = event.pageX;
\r
2891 this.originalPageY = event.pageY;
\r
2893 //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
\r
2894 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
\r
2896 //Cache the former DOM position
\r
2897 this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
\r
2899 //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
\r
2900 if(this.helper[0] != this.currentItem[0]) {
\r
2901 this.currentItem.hide();
\r
2904 //Create the placeholder
\r
2905 this._createPlaceholder();
\r
2907 //Set a containment if given in the options
\r
2909 this._setContainment();
\r
2911 if(o.cursor) { // cursor option
\r
2912 if ($('body').css("cursor")) this._storedCursor = $('body').css("cursor");
\r
2913 $('body').css("cursor", o.cursor);
\r
2916 if(o.opacity) { // opacity option
\r
2917 if (this.helper.css("opacity")) this._storedOpacity = this.helper.css("opacity");
\r
2918 this.helper.css("opacity", o.opacity);
\r
2921 if(o.zIndex) { // zIndex option
\r
2922 if (this.helper.css("zIndex")) this._storedZIndex = this.helper.css("zIndex");
\r
2923 this.helper.css("zIndex", o.zIndex);
\r
2926 //Prepare scrolling
\r
2927 if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML')
\r
2928 this.overflowOffset = this.scrollParent.offset();
\r
2931 this._trigger("start", event, this._uiHash());
\r
2933 //Recache the helper size
\r
2934 if(!this._preserveHelperProportions)
\r
2935 this._cacheHelperProportions();
\r
2938 //Post 'activate' events to possible containers
\r
2939 if(!noActivation) {
\r
2940 for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i]._trigger("activate", event, self._uiHash(this)); }
\r
2943 //Prepare possible droppables
\r
2944 if($.ui.ddmanager)
\r
2945 $.ui.ddmanager.current = this;
\r
2947 if ($.ui.ddmanager && !o.dropBehaviour)
\r
2948 $.ui.ddmanager.prepareOffsets(this, event);
\r
2950 this.dragging = true;
\r
2952 this.helper.addClass("ui-sortable-helper");
\r
2953 this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
\r
2958 _mouseDrag: function(event) {
\r
2960 //Compute the helpers position
\r
2961 this.position = this._generatePosition(event);
\r
2962 this.positionAbs = this._convertPositionTo("absolute");
\r
2964 if (!this.lastPositionAbs) {
\r
2965 this.lastPositionAbs = this.positionAbs;
\r
2969 if(this.options.scroll) {
\r
2970 var o = this.options, scrolled = false;
\r
2971 if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') {
\r
2973 if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
\r
2974 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
\r
2975 else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity)
\r
2976 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
\r
2978 if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
\r
2979 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
\r
2980 else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity)
\r
2981 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
\r
2985 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
\r
2986 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
\r
2987 else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
\r
2988 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
\r
2990 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
\r
2991 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
\r
2992 else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
\r
2993 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
\r
2997 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
\r
2998 $.ui.ddmanager.prepareOffsets(this, event);
\r
3001 //Regenerate the absolute position used for position checks
\r
3002 this.positionAbs = this._convertPositionTo("absolute");
\r
3004 //Set the helper position
\r
3005 if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
\r
3006 if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
\r
3009 for (var i = this.items.length - 1; i >= 0; i--) {
\r
3011 //Cache variables and intersection, continue if no intersection
\r
3012 var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item);
\r
3013 if (!intersection) continue;
\r
3015 if(itemElement != this.currentItem[0] //cannot intersect with itself
\r
3016 && this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before
\r
3017 && !$.ui.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked
\r
3018 && (this.options.type == 'semi-dynamic' ? !$.ui.contains(this.element[0], itemElement) : true)
\r
3019 //&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container
\r
3022 this.direction = intersection == 1 ? "down" : "up";
\r
3024 if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) {
\r
3025 this._rearrange(event, item);
\r
3030 this._trigger("change", event, this._uiHash());
\r
3035 //Post events to containers
\r
3036 this._contactContainers(event);
\r
3038 //Interconnect with droppables
\r
3039 if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
\r
3042 this._trigger('sort', event, this._uiHash());
\r
3044 this.lastPositionAbs = this.positionAbs;
\r
3049 _mouseStop: function(event, noPropagation) {
\r
3051 if(!event) return;
\r
3053 //If we are using droppables, inform the manager about the drop
\r
3054 if ($.ui.ddmanager && !this.options.dropBehaviour)
\r
3055 $.ui.ddmanager.drop(this, event);
\r
3057 if(this.options.revert) {
\r
3059 var cur = self.placeholder.offset();
\r
3061 self.reverting = true;
\r
3063 $(this.helper).animate({
\r
3064 left: cur.left - this.offset.parent.left - self.margins.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft),
\r
3065 top: cur.top - this.offset.parent.top - self.margins.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop)
\r
3066 }, parseInt(this.options.revert, 10) || 500, function() {
\r
3067 self._clear(event);
\r
3070 this._clear(event, noPropagation);
\r
3077 cancel: function() {
\r
3081 if(this.dragging) {
\r
3085 if(this.options.helper == "original")
\r
3086 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
\r
3088 this.currentItem.show();
\r
3090 //Post deactivating events to containers
\r
3091 for (var i = this.containers.length - 1; i >= 0; i--){
\r
3092 this.containers[i]._trigger("deactivate", null, self._uiHash(this));
\r
3093 if(this.containers[i].containerCache.over) {
\r
3094 this.containers[i]._trigger("out", null, self._uiHash(this));
\r
3095 this.containers[i].containerCache.over = 0;
\r
3101 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
\r
3102 if(this.placeholder[0].parentNode) this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
\r
3103 if(this.options.helper != "original" && this.helper && this.helper[0].parentNode) this.helper.remove();
\r
3109 _noFinalSort: null
\r
3112 if(this.domPosition.prev) {
\r
3113 $(this.domPosition.prev).after(this.currentItem);
\r
3115 $(this.domPosition.parent).prepend(this.currentItem);
\r
3122 serialize: function(o) {
\r
3124 var items = this._getItemsAsjQuery(o && o.connected);
\r
3125 var str = []; o = o || {};
\r
3127 $(items).each(function() {
\r
3128 var res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
\r
3129 if(res) str.push((o.key || res[1]+'[]')+'='+(o.key && o.expression ? res[1] : res[2]));
\r
3132 return str.join('&');
\r
3136 toArray: function(o) {
\r
3138 var items = this._getItemsAsjQuery(o && o.connected);
\r
3139 var ret = []; o = o || {};
\r
3141 items.each(function() { ret.push($(o.item || this).attr(o.attribute || 'id') || ''); });
\r
3146 /* Be careful with the following core functions */
\r
3147 _intersectsWith: function(item) {
\r
3149 var x1 = this.positionAbs.left,
\r
3150 x2 = x1 + this.helperProportions.width,
\r
3151 y1 = this.positionAbs.top,
\r
3152 y2 = y1 + this.helperProportions.height;
\r
3154 var l = item.left,
\r
3155 r = l + item.width,
\r
3157 b = t + item.height;
\r
3159 var dyClick = this.offset.click.top,
\r
3160 dxClick = this.offset.click.left;
\r
3162 var isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r;
\r
3164 if( this.options.tolerance == "pointer"
\r
3165 || this.options.forcePointerForContainers
\r
3166 || (this.options.tolerance != "pointer" && this.helperProportions[this.floating ? 'width' : 'height'] > item[this.floating ? 'width' : 'height'])
\r
3168 return isOverElement;
\r
3171 return (l < x1 + (this.helperProportions.width / 2) // Right Half
\r
3172 && x2 - (this.helperProportions.width / 2) < r // Left Half
\r
3173 && t < y1 + (this.helperProportions.height / 2) // Bottom Half
\r
3174 && y2 - (this.helperProportions.height / 2) < b ); // Top Half
\r
3179 _intersectsWithPointer: function(item) {
\r
3181 var isOverElementHeight = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
\r
3182 isOverElementWidth = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
\r
3183 isOverElement = isOverElementHeight && isOverElementWidth,
\r
3184 verticalDirection = this._getDragVerticalDirection(),
\r
3185 horizontalDirection = this._getDragHorizontalDirection();
\r
3187 if (!isOverElement)
\r
3190 return this.floating ?
\r
3191 ( ((horizontalDirection && horizontalDirection == "right") || verticalDirection == "down") ? 2 : 1 )
\r
3192 : ( verticalDirection && (verticalDirection == "down" ? 2 : 1) );
\r
3196 _intersectsWithSides: function(item) {
\r
3198 var isOverBottomHalf = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
\r
3199 isOverRightHalf = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
\r
3200 verticalDirection = this._getDragVerticalDirection(),
\r
3201 horizontalDirection = this._getDragHorizontalDirection();
\r
3203 if (this.floating && horizontalDirection) {
\r
3204 return ((horizontalDirection == "right" && isOverRightHalf) || (horizontalDirection == "left" && !isOverRightHalf));
\r
3206 return verticalDirection && ((verticalDirection == "down" && isOverBottomHalf) || (verticalDirection == "up" && !isOverBottomHalf));
\r
3211 _getDragVerticalDirection: function() {
\r
3212 var delta = this.positionAbs.top - this.lastPositionAbs.top;
\r
3213 return delta != 0 && (delta > 0 ? "down" : "up");
\r
3216 _getDragHorizontalDirection: function() {
\r
3217 var delta = this.positionAbs.left - this.lastPositionAbs.left;
\r
3218 return delta != 0 && (delta > 0 ? "right" : "left");
\r
3221 refresh: function(event) {
\r
3222 this._refreshItems(event);
\r
3223 this.refreshPositions();
\r
3227 _connectWith: function() {
\r
3228 var options = this.options;
\r
3229 return options.connectWith.constructor == String
\r
3230 ? [options.connectWith]
\r
3231 : options.connectWith;
\r
3234 _getItemsAsjQuery: function(connected) {
\r
3239 var connectWith = this._connectWith();
\r
3241 if(connectWith && connected) {
\r
3242 for (var i = connectWith.length - 1; i >= 0; i--){
\r
3243 var cur = $(connectWith[i]);
\r
3244 for (var j = cur.length - 1; j >= 0; j--){
\r
3245 var inst = $.data(cur[j], 'sortable');
\r
3246 if(inst && inst != this && !inst.options.disabled) {
\r
3247 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]);
\r
3253 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]);
\r
3255 for (var i = queries.length - 1; i >= 0; i--){
\r
3256 queries[i][0].each(function() {
\r
3265 _removeCurrentsFromItems: function() {
\r
3267 var list = this.currentItem.find(":data(sortable-item)");
\r
3269 for (var i=0; i < this.items.length; i++) {
\r
3271 for (var j=0; j < list.length; j++) {
\r
3272 if(list[j] == this.items[i].item[0])
\r
3273 this.items.splice(i,1);
\r
3280 _refreshItems: function(event) {
\r
3283 this.containers = [this];
\r
3284 var items = this.items;
\r
3286 var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]];
\r
3287 var connectWith = this._connectWith();
\r
3290 for (var i = connectWith.length - 1; i >= 0; i--){
\r
3291 var cur = $(connectWith[i]);
\r
3292 for (var j = cur.length - 1; j >= 0; j--){
\r
3293 var inst = $.data(cur[j], 'sortable');
\r
3294 if(inst && inst != this && !inst.options.disabled) {
\r
3295 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
\r
3296 this.containers.push(inst);
\r
3302 for (var i = queries.length - 1; i >= 0; i--) {
\r
3303 var targetData = queries[i][1];
\r
3304 var _queries = queries[i][0];
\r
3306 for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) {
\r
3307 var item = $(_queries[j]);
\r
3309 item.data('sortable-item', targetData); // Data for target checking (mouse manager)
\r
3313 instance: targetData,
\r
3314 width: 0, height: 0,
\r
3322 refreshPositions: function(fast) {
\r
3324 //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
\r
3325 if(this.offsetParent && this.helper) {
\r
3326 this.offset.parent = this._getParentOffset();
\r
3329 for (var i = this.items.length - 1; i >= 0; i--){
\r
3330 var item = this.items[i];
\r
3332 var t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
\r
3335 item.width = t.outerWidth();
\r
3336 item.height = t.outerHeight();
\r
3339 var p = t.offset();
\r
3340 item.left = p.left;
\r
3344 if(this.options.custom && this.options.custom.refreshContainers) {
\r
3345 this.options.custom.refreshContainers.call(this);
\r
3347 for (var i = this.containers.length - 1; i >= 0; i--){
\r
3348 var p = this.containers[i].element.offset();
\r
3349 this.containers[i].containerCache.left = p.left;
\r
3350 this.containers[i].containerCache.top = p.top;
\r
3351 this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
\r
3352 this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
\r
3359 _createPlaceholder: function(that) {
\r
3361 var self = that || this, o = self.options;
\r
3363 if(!o.placeholder || o.placeholder.constructor == String) {
\r
3364 var className = o.placeholder;
\r
3366 element: function() {
\r
3368 var el = $(document.createElement(self.currentItem[0].nodeName))
\r
3369 .addClass(className || self.currentItem[0].className+" ui-sortable-placeholder")
\r
3370 .removeClass("ui-sortable-helper")[0];
\r
3373 el.style.visibility = "hidden";
\r
3377 update: function(container, p) {
\r
3379 // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
\r
3380 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
\r
3381 if(className && !o.forcePlaceholderSize) return;
\r
3383 //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
\r
3384 if(!p.height()) { p.height(self.currentItem.innerHeight() - parseInt(self.currentItem.css('paddingTop')||0, 10) - parseInt(self.currentItem.css('paddingBottom')||0, 10)); };
\r
3385 if(!p.width()) { p.width(self.currentItem.innerWidth() - parseInt(self.currentItem.css('paddingLeft')||0, 10) - parseInt(self.currentItem.css('paddingRight')||0, 10)); };
\r
3390 //Create the placeholder
\r
3391 self.placeholder = $(o.placeholder.element.call(self.element, self.currentItem));
\r
3393 //Append it after the actual current item
\r
3394 self.currentItem.after(self.placeholder);
\r
3396 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
\r
3397 o.placeholder.update(self, self.placeholder);
\r
3401 _contactContainers: function(event) {
\r
3403 // get innermost container that intersects with item
\r
3404 var innermostContainer = null, innermostIndex = null;
\r
3407 for (var i = this.containers.length - 1; i >= 0; i--){
\r
3409 // never consider a container that's located within the item itself
\r
3410 if($.ui.contains(this.currentItem[0], this.containers[i].element[0]))
\r
3413 if(this._intersectsWith(this.containers[i].containerCache)) {
\r
3415 // if we've already found a container and it's more "inner" than this, then continue
\r
3416 if(innermostContainer && $.ui.contains(this.containers[i].element[0], innermostContainer.element[0]))
\r
3419 innermostContainer = this.containers[i];
\r
3420 innermostIndex = i;
\r
3423 // container doesn't intersect. trigger "out" event if necessary
\r
3424 if(this.containers[i].containerCache.over) {
\r
3425 this.containers[i]._trigger("out", event, this._uiHash(this));
\r
3426 this.containers[i].containerCache.over = 0;
\r
3432 // if no intersecting containers found, return
\r
3433 if(!innermostContainer) return;
\r
3435 // move the item into the container if it's not there already
\r
3436 if(this.containers.length === 1) {
\r
3437 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
\r
3438 this.containers[innermostIndex].containerCache.over = 1;
\r
3439 } else if(this.currentContainer != this.containers[innermostIndex]) {
\r
3441 //When entering a new container, we will find the item with the least distance and append our item near it
\r
3442 var dist = 10000; var itemWithLeastDistance = null; var base = this.positionAbs[this.containers[innermostIndex].floating ? 'left' : 'top'];
\r
3443 for (var j = this.items.length - 1; j >= 0; j--) {
\r
3444 if(!$.ui.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) continue;
\r
3445 var cur = this.items[j][this.containers[innermostIndex].floating ? 'left' : 'top'];
\r
3446 if(Math.abs(cur - base) < dist) {
\r
3447 dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j];
\r
3451 if(!itemWithLeastDistance && !this.options.dropOnEmpty) //Check if dropOnEmpty is enabled
\r
3454 this.currentContainer = this.containers[innermostIndex];
\r
3455 itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
\r
3456 this._trigger("change", event, this._uiHash());
\r
3457 this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
\r
3459 //Update the placeholder
\r
3460 this.options.placeholder.update(this.currentContainer, this.placeholder);
\r
3462 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
\r
3463 this.containers[innermostIndex].containerCache.over = 1;
\r
3469 _createHelper: function(event) {
\r
3471 var o = this.options;
\r
3472 var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper == 'clone' ? this.currentItem.clone() : this.currentItem);
\r
3474 if(!helper.parents('body').length) //Add the helper to the DOM if that didn't happen already
\r
3475 $(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
\r
3477 if(helper[0] == this.currentItem[0])
\r
3478 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") };
\r
3480 if(helper[0].style.width == '' || o.forceHelperSize) helper.width(this.currentItem.width());
\r
3481 if(helper[0].style.height == '' || o.forceHelperSize) helper.height(this.currentItem.height());
\r
3487 _adjustOffsetFromHelper: function(obj) {
\r
3488 if (typeof obj == 'string') {
\r
3489 obj = obj.split(' ');
\r
3491 if ($.isArray(obj)) {
\r
3492 obj = {left: +obj[0], top: +obj[1] || 0};
\r
3494 if ('left' in obj) {
\r
3495 this.offset.click.left = obj.left + this.margins.left;
\r
3497 if ('right' in obj) {
\r
3498 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
\r
3500 if ('top' in obj) {
\r
3501 this.offset.click.top = obj.top + this.margins.top;
\r
3503 if ('bottom' in obj) {
\r
3504 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
\r
3508 _getParentOffset: function() {
\r
3511 //Get the offsetParent and cache its position
\r
3512 this.offsetParent = this.helper.offsetParent();
\r
3513 var po = this.offsetParent.offset();
\r
3515 // This is a special case where we need to modify a offset calculated on start, since the following happened:
\r
3516 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
\r
3517 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
\r
3518 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
\r
3519 if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) {
\r
3520 po.left += this.scrollParent.scrollLeft();
\r
3521 po.top += this.scrollParent.scrollTop();
\r
3524 if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information
\r
3525 || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix
\r
3526 po = { top: 0, left: 0 };
\r
3529 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
\r
3530 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
\r
3535 _getRelativeOffset: function() {
\r
3537 if(this.cssPosition == "relative") {
\r
3538 var p = this.currentItem.position();
\r
3540 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
\r
3541 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
\r
3544 return { top: 0, left: 0 };
\r
3549 _cacheMargins: function() {
\r
3551 left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
\r
3552 top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
\r
3556 _cacheHelperProportions: function() {
\r
3557 this.helperProportions = {
\r
3558 width: this.helper.outerWidth(),
\r
3559 height: this.helper.outerHeight()
\r
3563 _setContainment: function() {
\r
3565 var o = this.options;
\r
3566 if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
\r
3567 if(o.containment == 'document' || o.containment == 'window') this.containment = [
\r
3568 0 - this.offset.relative.left - this.offset.parent.left,
\r
3569 0 - this.offset.relative.top - this.offset.parent.top,
\r
3570 $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left,
\r
3571 ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
\r
3574 if(!(/^(document|window|parent)$/).test(o.containment)) {
\r
3575 var ce = $(o.containment)[0];
\r
3576 var co = $(o.containment).offset();
\r
3577 var over = ($(ce).css("overflow") != 'hidden');
\r
3579 this.containment = [
\r
3580 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
\r
3581 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
\r
3582 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,
\r
3583 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
\r
3589 _convertPositionTo: function(d, pos) {
\r
3591 if(!pos) pos = this.position;
\r
3592 var mod = d == "absolute" ? 1 : -1;
\r
3593 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);
\r
3597 pos.top // The absolute mouse position
\r
3598 + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent
\r
3599 + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border)
\r
3600 - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
\r
3603 pos.left // The absolute mouse position
\r
3604 + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent
\r
3605 + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border)
\r
3606 - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
\r
3612 _generatePosition: function(event) {
\r
3614 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);
\r
3616 // This is another very weird special case that only happens for relative elements:
\r
3617 // 1. If the css position is relative
\r
3618 // 2. and the scroll parent is the document or similar to the offset parent
\r
3619 // we have to refresh the relative offset during the scroll so there are no jumps
\r
3620 if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) {
\r
3621 this.offset.relative = this._getRelativeOffset();
\r
3624 var pageX = event.pageX;
\r
3625 var pageY = event.pageY;
\r
3628 * - Position constraining -
\r
3629 * Constrain the position to a mix of grid, containment.
\r
3632 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
\r
3634 if(this.containment) {
\r
3635 if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left;
\r
3636 if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top;
\r
3637 if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left;
\r
3638 if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top;
\r
3642 var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
\r
3643 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;
\r
3645 var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
\r
3646 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;
\r
3653 pageY // The absolute mouse position
\r
3654 - this.offset.click.top // Click offset (relative to the element)
\r
3655 - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent
\r
3656 - this.offset.parent.top // The offsetParent's offset without borders (offset + border)
\r
3657 + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
\r
3660 pageX // The absolute mouse position
\r
3661 - this.offset.click.left // Click offset (relative to the element)
\r
3662 - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent
\r
3663 - this.offset.parent.left // The offsetParent's offset without borders (offset + border)
\r
3664 + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
\r
3670 _rearrange: function(event, i, a, hardRefresh) {
\r
3672 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));
\r
3674 //Various things done here to improve the performance:
\r
3675 // 1. we create a setTimeout, that calls refreshPositions
\r
3676 // 2. on the instance, we have a counter variable, that get's higher after every append
\r
3677 // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
\r
3678 // 4. this lets only the last addition to the timeout stack through
\r
3679 this.counter = this.counter ? ++this.counter : 1;
\r
3680 var self = this, counter = this.counter;
\r
3682 window.setTimeout(function() {
\r
3683 if(counter == self.counter) self.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
\r
3688 _clear: function(event, noPropagation) {
\r
3690 this.reverting = false;
\r
3691 // We delay all events that have to be triggered to after the point where the placeholder has been removed and
\r
3692 // everything else normalized again
\r
3693 var delayedTriggers = [], self = this;
\r
3695 // We first have to update the dom position of the actual currentItem
\r
3696 // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
\r
3697 if(!this._noFinalSort && this.currentItem[0].parentNode) this.placeholder.before(this.currentItem);
\r
3698 this._noFinalSort = null;
\r
3700 if(this.helper[0] == this.currentItem[0]) {
\r
3701 for(var i in this._storedCSS) {
\r
3702 if(this._storedCSS[i] == 'auto' || this._storedCSS[i] == 'static') this._storedCSS[i] = '';
\r
3704 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
\r
3706 this.currentItem.show();
\r
3709 if(this.fromOutside && !noPropagation) delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
\r
3710 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
\r
3711 if(!$.ui.contains(this.element[0], this.currentItem[0])) { //Node was moved out of the current element
\r
3712 if(!noPropagation) delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
\r
3713 for (var i = this.containers.length - 1; i >= 0; i--){
\r
3714 if($.ui.contains(this.containers[i].element[0], this.currentItem[0]) && !noPropagation) {
\r
3715 delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
\r
3716 delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
\r
3721 //Post events to containers
\r
3722 for (var i = this.containers.length - 1; i >= 0; i--){
\r
3723 if(!noPropagation) delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
\r
3724 if(this.containers[i].containerCache.over) {
\r
3725 delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
\r
3726 this.containers[i].containerCache.over = 0;
\r
3730 //Do what was originally in plugins
\r
3731 if(this._storedCursor) $('body').css("cursor", this._storedCursor); //Reset cursor
\r
3732 if(this._storedOpacity) this.helper.css("opacity", this._storedOpacity); //Reset opacity
\r
3733 if(this._storedZIndex) this.helper.css("zIndex", this._storedZIndex == 'auto' ? '' : this._storedZIndex); //Reset z-index
\r
3735 this.dragging = false;
\r
3736 if(this.cancelHelperRemoval) {
\r
3737 if(!noPropagation) {
\r
3738 this._trigger("beforeStop", event, this._uiHash());
\r
3739 for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events
\r
3740 this._trigger("stop", event, this._uiHash());
\r
3745 if(!noPropagation) this._trigger("beforeStop", event, this._uiHash());
\r
3747 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
\r
3748 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
\r
3750 if(this.helper[0] != this.currentItem[0]) this.helper.remove(); this.helper = null;
\r
3752 if(!noPropagation) {
\r
3753 for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events
\r
3754 this._trigger("stop", event, this._uiHash());
\r
3757 this.fromOutside = false;
\r
3762 _trigger: function() {
\r
3763 if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
\r
3768 _uiHash: function(inst) {
\r
3769 var self = inst || this;
\r
3771 helper: self.helper,
\r
3772 placeholder: self.placeholder || $([]),
\r
3773 position: self.position,
\r
3774 originalPosition: self.originalPosition,
\r
3775 offset: self.positionAbs,
\r
3776 item: self.currentItem,
\r
3777 sender: inst ? inst.element : null
\r
3783 $.extend($.ui.sortable, {
\r
3789 * jQuery UI Effects 1.8
\r
3791 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
3792 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
3793 * and GPL (GPL-LICENSE.txt) licenses.
\r
3795 * http://docs.jquery.com/UI/Effects/
\r
3797 ;jQuery.effects || (function($) {
\r
3803 /******************************************************************************/
\r
3804 /****************************** COLOR ANIMATIONS ******************************/
\r
3805 /******************************************************************************/
\r
3807 // override the animation for color styles
\r
3808 $.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor',
\r
3809 'borderRightColor', 'borderTopColor', 'color', 'outlineColor'],
\r
3810 function(i, attr) {
\r
3811 $.fx.step[attr] = function(fx) {
\r
3812 if (!fx.colorInit) {
\r
3813 fx.start = getColor(fx.elem, attr);
\r
3814 fx.end = getRGB(fx.end);
\r
3815 fx.colorInit = true;
\r
3818 fx.elem.style[attr] = 'rgb(' +
\r
3819 Math.max(Math.min(parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0], 10), 255), 0) + ',' +
\r
3820 Math.max(Math.min(parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1], 10), 255), 0) + ',' +
\r
3821 Math.max(Math.min(parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2], 10), 255), 0) + ')';
\r
3825 // Color Conversion functions from highlightFade
\r
3826 // By Blair Mitchelmore
\r
3827 // http://jquery.offput.ca/highlightFade/
\r
3829 // Parse strings looking for color tuples [255,255,255]
\r
3830 function getRGB(color) {
\r
3833 // Check if we're already dealing with an array of colors
\r
3834 if ( color && color.constructor == Array && color.length == 3 )
\r
3837 // Look for rgb(num,num,num)
\r
3838 if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color))
\r
3839 return [parseInt(result[1],10), parseInt(result[2],10), parseInt(result[3],10)];
\r
3841 // Look for rgb(num%,num%,num%)
\r
3842 if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color))
\r
3843 return [parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55];
\r
3845 // Look for #a0b1c2
\r
3846 if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color))
\r
3847 return [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)];
\r
3850 if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color))
\r
3851 return [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)];
\r
3853 // Look for rgba(0, 0, 0, 0) == transparent in Safari 3
\r
3854 if (result = /rgba\(0, 0, 0, 0\)/.exec(color))
\r
3855 return colors['transparent'];
\r
3857 // Otherwise, we're most likely dealing with a named color
\r
3858 return colors[$.trim(color).toLowerCase()];
\r
3861 function getColor(elem, attr) {
\r
3865 color = $.curCSS(elem, attr);
\r
3867 // Keep going until we find an element that has color, or we hit the body
\r
3868 if ( color != '' && color != 'transparent' || $.nodeName(elem, "body") )
\r
3871 attr = "backgroundColor";
\r
3872 } while ( elem = elem.parentNode );
\r
3874 return getRGB(color);
\r
3877 // Some named colors to work with
\r
3878 // From Interface by Stefan Petre
\r
3879 // http://interface.eyecon.ro/
\r
3883 azure:[240,255,255],
\r
3884 beige:[245,245,220],
\r
3887 brown:[165,42,42],
\r
3889 darkblue:[0,0,139],
\r
3890 darkcyan:[0,139,139],
\r
3891 darkgrey:[169,169,169],
\r
3892 darkgreen:[0,100,0],
\r
3893 darkkhaki:[189,183,107],
\r
3894 darkmagenta:[139,0,139],
\r
3895 darkolivegreen:[85,107,47],
\r
3896 darkorange:[255,140,0],
\r
3897 darkorchid:[153,50,204],
\r
3898 darkred:[139,0,0],
\r
3899 darksalmon:[233,150,122],
\r
3900 darkviolet:[148,0,211],
\r
3901 fuchsia:[255,0,255],
\r
3904 indigo:[75,0,130],
\r
3905 khaki:[240,230,140],
\r
3906 lightblue:[173,216,230],
\r
3907 lightcyan:[224,255,255],
\r
3908 lightgreen:[144,238,144],
\r
3909 lightgrey:[211,211,211],
\r
3910 lightpink:[255,182,193],
\r
3911 lightyellow:[255,255,224],
\r
3913 magenta:[255,0,255],
\r
3916 olive:[128,128,0],
\r
3917 orange:[255,165,0],
\r
3918 pink:[255,192,203],
\r
3919 purple:[128,0,128],
\r
3920 violet:[128,0,128],
\r
3922 silver:[192,192,192],
\r
3923 white:[255,255,255],
\r
3924 yellow:[255,255,0],
\r
3925 transparent: [255,255,255]
\r
3930 /******************************************************************************/
\r
3931 /****************************** CLASS ANIMATIONS ******************************/
\r
3932 /******************************************************************************/
\r
3934 var classAnimationActions = ['add', 'remove', 'toggle'],
\r
3935 shorthandStyles = {
\r
3947 function getElementStyles() {
\r
3948 var style = document.defaultView
\r
3949 ? document.defaultView.getComputedStyle(this, null)
\r
3950 : this.currentStyle,
\r
3955 // webkit enumerates style porperties
\r
3956 if (style && style.length && style[0] && style[style[0]]) {
\r
3957 var len = style.length;
\r
3960 if (typeof style[key] == 'string') {
\r
3961 camelCase = key.replace(/\-(\w)/g, function(all, letter){
\r
3962 return letter.toUpperCase();
\r
3964 newStyle[camelCase] = style[key];
\r
3968 for (key in style) {
\r
3969 if (typeof style[key] === 'string') {
\r
3970 newStyle[key] = style[key];
\r
3978 function filterStyles(styles) {
\r
3980 for (name in styles) {
\r
3981 value = styles[name];
\r
3983 // ignore null and undefined values
\r
3985 // ignore functions (when does this occur?)
\r
3986 $.isFunction(value) ||
\r
3987 // shorthand styles that need to be expanded
\r
3988 name in shorthandStyles ||
\r
3989 // ignore scrollbars (break in IE)
\r
3990 (/scrollbar/).test(name) ||
\r
3992 // only colors or values that can be converted to numbers
\r
3993 (!(/color/i).test(name) && isNaN(parseFloat(value)))
\r
3995 delete styles[name];
\r
4002 function styleDifference(oldStyle, newStyle) {
\r
4003 var diff = { _: 0 }, // http://dev.jquery.com/ticket/5459
\r
4006 for (name in newStyle) {
\r
4007 if (oldStyle[name] != newStyle[name]) {
\r
4008 diff[name] = newStyle[name];
\r
4015 $.effects.animateClass = function(value, duration, easing, callback) {
\r
4016 if ($.isFunction(easing)) {
\r
4017 callback = easing;
\r
4021 return this.each(function() {
\r
4023 var that = $(this),
\r
4024 originalStyleAttr = that.attr('style') || ' ',
\r
4025 originalStyle = filterStyles(getElementStyles.call(this)),
\r
4027 className = that.attr('className');
\r
4029 $.each(classAnimationActions, function(i, action) {
\r
4030 if (value[action]) {
\r
4031 that[action + 'Class'](value[action]);
\r
4034 newStyle = filterStyles(getElementStyles.call(this));
\r
4035 that.attr('className', className);
\r
4037 that.animate(styleDifference(originalStyle, newStyle), duration, easing, function() {
\r
4038 $.each(classAnimationActions, function(i, action) {
\r
4039 if (value[action]) { that[action + 'Class'](value[action]); }
\r
4041 // work around bug in IE by clearing the cssText before setting it
\r
4042 if (typeof that.attr('style') == 'object') {
\r
4043 that.attr('style').cssText = '';
\r
4044 that.attr('style').cssText = originalStyleAttr;
\r
4046 that.attr('style', originalStyleAttr);
\r
4048 if (callback) { callback.apply(this, arguments); }
\r
4054 _addClass: $.fn.addClass,
\r
4055 addClass: function(classNames, speed, easing, callback) {
\r
4056 return speed ? $.effects.animateClass.apply(this, [{ add: classNames },speed,easing,callback]) : this._addClass(classNames);
\r
4059 _removeClass: $.fn.removeClass,
\r
4060 removeClass: function(classNames,speed,easing,callback) {
\r
4061 return speed ? $.effects.animateClass.apply(this, [{ remove: classNames },speed,easing,callback]) : this._removeClass(classNames);
\r
4064 _toggleClass: $.fn.toggleClass,
\r
4065 toggleClass: function(classNames, force, speed, easing, callback) {
\r
4066 if ( typeof force == "boolean" || force === undefined ) {
\r
4068 // without speed parameter;
\r
4069 return this._toggleClass(classNames, force);
\r
4071 return $.effects.animateClass.apply(this, [(force?{add:classNames}:{remove:classNames}),speed,easing,callback]);
\r
4074 // without switch parameter;
\r
4075 return $.effects.animateClass.apply(this, [{ toggle: classNames },force,speed,easing]);
\r
4079 switchClass: function(remove,add,speed,easing,callback) {
\r
4080 return $.effects.animateClass.apply(this, [{ add: add, remove: remove },speed,easing,callback]);
\r
4086 /******************************************************************************/
\r
4087 /*********************************** EFFECTS **********************************/
\r
4088 /******************************************************************************/
\r
4090 $.extend($.effects, {
\r
4093 // Saves a set of properties in a data storage
\r
4094 save: function(element, set) {
\r
4095 for(var i=0; i < set.length; i++) {
\r
4096 if(set[i] !== null) element.data("ec.storage."+set[i], element[0].style[set[i]]);
\r
4100 // Restores a set of previously saved properties from a data storage
\r
4101 restore: function(element, set) {
\r
4102 for(var i=0; i < set.length; i++) {
\r
4103 if(set[i] !== null) element.css(set[i], element.data("ec.storage."+set[i]));
\r
4107 setMode: function(el, mode) {
\r
4108 if (mode == 'toggle') mode = el.is(':hidden') ? 'show' : 'hide'; // Set for toggle
\r
4112 getBaseline: function(origin, original) { // Translates a [top,left] array into a baseline value
\r
4113 // this should be a little more flexible in the future to handle a string & hash
\r
4115 switch (origin[0]) {
\r
4116 case 'top': y = 0; break;
\r
4117 case 'middle': y = 0.5; break;
\r
4118 case 'bottom': y = 1; break;
\r
4119 default: y = origin[0] / original.height;
\r
4121 switch (origin[1]) {
\r
4122 case 'left': x = 0; break;
\r
4123 case 'center': x = 0.5; break;
\r
4124 case 'right': x = 1; break;
\r
4125 default: x = origin[1] / original.width;
\r
4127 return {x: x, y: y};
\r
4130 // Wraps the element around a wrapper that copies position properties
\r
4131 createWrapper: function(element) {
\r
4133 // if the element is already wrapped, return it
\r
4134 if (element.parent().is('.ui-effects-wrapper')) {
\r
4135 return element.parent();
\r
4138 // wrap the element
\r
4140 width: element.outerWidth(true),
\r
4141 height: element.outerHeight(true),
\r
4142 'float': element.css('float')
\r
4144 wrapper = $('<div></div>')
\r
4145 .addClass('ui-effects-wrapper')
\r
4148 background: 'transparent',
\r
4154 element.wrap(wrapper);
\r
4155 wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually loose the reference to the wrapped element
\r
4157 // transfer positioning properties to the wrapper
\r
4158 if (element.css('position') == 'static') {
\r
4159 wrapper.css({ position: 'relative' });
\r
4160 element.css({ position: 'relative' });
\r
4163 position: element.css('position'),
\r
4164 zIndex: element.css('z-index')
\r
4166 $.each(['top', 'left', 'bottom', 'right'], function(i, pos) {
\r
4167 props[pos] = element.css(pos);
\r
4168 if (isNaN(parseInt(props[pos], 10))) {
\r
4169 props[pos] = 'auto';
\r
4172 element.css({position: 'relative', top: 0, left: 0 });
\r
4175 return wrapper.css(props).show();
\r
4178 removeWrapper: function(element) {
\r
4179 if (element.parent().is('.ui-effects-wrapper'))
\r
4180 return element.parent().replaceWith(element);
\r
4184 setTransition: function(element, list, factor, value) {
\r
4185 value = value || {};
\r
4186 $.each(list, function(i, x){
\r
4187 unit = element.cssUnit(x);
\r
4188 if (unit[0] > 0) value[x] = unit[0] * factor + unit[1];
\r
4195 function _normalizeArguments(effect, options, speed, callback) {
\r
4196 // shift params for method overloading
\r
4197 if (typeof effect == 'object') {
\r
4198 callback = options;
\r
4201 effect = options.effect;
\r
4203 if ($.isFunction(options)) {
\r
4204 callback = options;
\r
4208 if ($.isFunction(speed)) {
\r
4212 if (typeof options == 'number' || $.fx.speeds[options]) {
\r
4218 options = options || {};
\r
4220 speed = speed || options.duration;
\r
4221 speed = $.fx.off ? 0 : typeof speed == 'number'
\r
4222 ? speed : $.fx.speeds[speed] || $.fx.speeds._default;
\r
4224 callback = callback || options.complete;
\r
4226 return [effect, options, speed, callback];
\r
4230 effect: function(effect, options, speed, callback) {
\r
4231 var args = _normalizeArguments.apply(this, arguments),
\r
4232 // TODO: make effects takes actual parameters instead of a hash
\r
4235 duration: args[2],
\r
4238 effectMethod = $.effects[effect];
\r
4240 return effectMethod && !$.fx.off ? effectMethod.call(this, args2) : this;
\r
4244 show: function(speed) {
\r
4245 if (!speed || typeof speed == 'number' || $.fx.speeds[speed]) {
\r
4246 return this._show.apply(this, arguments);
\r
4248 var args = _normalizeArguments.apply(this, arguments);
\r
4249 args[1].mode = 'show';
\r
4250 return this.effect.apply(this, args);
\r
4255 hide: function(speed) {
\r
4256 if (!speed || typeof speed == 'number' || $.fx.speeds[speed]) {
\r
4257 return this._hide.apply(this, arguments);
\r
4259 var args = _normalizeArguments.apply(this, arguments);
\r
4260 args[1].mode = 'hide';
\r
4261 return this.effect.apply(this, args);
\r
4265 // jQuery core overloads toggle and create _toggle
\r
4266 __toggle: $.fn.toggle,
\r
4267 toggle: function(speed) {
\r
4268 if (!speed || typeof speed == 'number' || $.fx.speeds[speed] ||
\r
4269 typeof speed == 'boolean' || $.isFunction(speed)) {
\r
4270 return this.__toggle.apply(this, arguments);
\r
4272 var args = _normalizeArguments.apply(this, arguments);
\r
4273 args[1].mode = 'toggle';
\r
4274 return this.effect.apply(this, args);
\r
4278 // helper functions
\r
4279 cssUnit: function(key) {
\r
4280 var style = this.css(key), val = [];
\r
4281 $.each( ['em','px','%','pt'], function(i, unit){
\r
4282 if(style.indexOf(unit) > 0)
\r
4283 val = [parseFloat(style), unit];
\r
4291 /******************************************************************************/
\r
4292 /*********************************** EASING ***********************************/
\r
4293 /******************************************************************************/
\r
4296 * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
\r
4298 * Uses the built in easing capabilities added In jQuery 1.1
\r
4299 * to offer multiple easing options
\r
4301 * TERMS OF USE - jQuery Easing
\r
4303 * Open source under the BSD License.
\r
4305 * Copyright 2008 George McGinley Smith
\r
4306 * All rights reserved.
\r
4308 * Redistribution and use in source and binary forms, with or without modification,
\r
4309 * are permitted provided that the following conditions are met:
\r
4311 * Redistributions of source code must retain the above copyright notice, this list of
\r
4312 * conditions and the following disclaimer.
\r
4313 * Redistributions in binary form must reproduce the above copyright notice, this list
\r
4314 * of conditions and the following disclaimer in the documentation and/or other materials
\r
4315 * provided with the distribution.
\r
4317 * Neither the name of the author nor the names of contributors may be used to endorse
\r
4318 * or promote products derived from this software without specific prior written permission.
\r
4320 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
\r
4321 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
4322 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
\r
4323 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
\r
4324 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
\r
4325 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
\r
4326 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
\r
4327 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
\r
4328 * OF THE POSSIBILITY OF SUCH DAMAGE.
\r
4332 // t: current time, b: begInnIng value, c: change In value, d: duration
\r
4333 $.easing.jswing = $.easing.swing;
\r
4335 $.extend($.easing,
\r
4337 def: 'easeOutQuad',
\r
4338 swing: function (x, t, b, c, d) {
\r
4339 //alert($.easing.default);
\r
4340 return $.easing[$.easing.def](x, t, b, c, d);
\r
4342 easeInQuad: function (x, t, b, c, d) {
\r
4343 return c*(t/=d)*t + b;
\r
4345 easeOutQuad: function (x, t, b, c, d) {
\r
4346 return -c *(t/=d)*(t-2) + b;
\r
4348 easeInOutQuad: function (x, t, b, c, d) {
\r
4349 if ((t/=d/2) < 1) return c/2*t*t + b;
\r
4350 return -c/2 * ((--t)*(t-2) - 1) + b;
\r
4352 easeInCubic: function (x, t, b, c, d) {
\r
4353 return c*(t/=d)*t*t + b;
\r
4355 easeOutCubic: function (x, t, b, c, d) {
\r
4356 return c*((t=t/d-1)*t*t + 1) + b;
\r
4358 easeInOutCubic: function (x, t, b, c, d) {
\r
4359 if ((t/=d/2) < 1) return c/2*t*t*t + b;
\r
4360 return c/2*((t-=2)*t*t + 2) + b;
\r
4362 easeInQuart: function (x, t, b, c, d) {
\r
4363 return c*(t/=d)*t*t*t + b;
\r
4365 easeOutQuart: function (x, t, b, c, d) {
\r
4366 return -c * ((t=t/d-1)*t*t*t - 1) + b;
\r
4368 easeInOutQuart: function (x, t, b, c, d) {
\r
4369 if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
\r
4370 return -c/2 * ((t-=2)*t*t*t - 2) + b;
\r
4372 easeInQuint: function (x, t, b, c, d) {
\r
4373 return c*(t/=d)*t*t*t*t + b;
\r
4375 easeOutQuint: function (x, t, b, c, d) {
\r
4376 return c*((t=t/d-1)*t*t*t*t + 1) + b;
\r
4378 easeInOutQuint: function (x, t, b, c, d) {
\r
4379 if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
\r
4380 return c/2*((t-=2)*t*t*t*t + 2) + b;
\r
4382 easeInSine: function (x, t, b, c, d) {
\r
4383 return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
\r
4385 easeOutSine: function (x, t, b, c, d) {
\r
4386 return c * Math.sin(t/d * (Math.PI/2)) + b;
\r
4388 easeInOutSine: function (x, t, b, c, d) {
\r
4389 return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
\r
4391 easeInExpo: function (x, t, b, c, d) {
\r
4392 return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
\r
4394 easeOutExpo: function (x, t, b, c, d) {
\r
4395 return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
\r
4397 easeInOutExpo: function (x, t, b, c, d) {
\r
4398 if (t==0) return b;
\r
4399 if (t==d) return b+c;
\r
4400 if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
\r
4401 return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
\r
4403 easeInCirc: function (x, t, b, c, d) {
\r
4404 return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
\r
4406 easeOutCirc: function (x, t, b, c, d) {
\r
4407 return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
\r
4409 easeInOutCirc: function (x, t, b, c, d) {
\r
4410 if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
\r
4411 return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
\r
4413 easeInElastic: function (x, t, b, c, d) {
\r
4414 var s=1.70158;var p=0;var a=c;
\r
4415 if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
\r
4416 if (a < Math.abs(c)) { a=c; var s=p/4; }
\r
4417 else var s = p/(2*Math.PI) * Math.asin (c/a);
\r
4418 return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
\r
4420 easeOutElastic: function (x, t, b, c, d) {
\r
4421 var s=1.70158;var p=0;var a=c;
\r
4422 if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
\r
4423 if (a < Math.abs(c)) { a=c; var s=p/4; }
\r
4424 else var s = p/(2*Math.PI) * Math.asin (c/a);
\r
4425 return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
\r
4427 easeInOutElastic: function (x, t, b, c, d) {
\r
4428 var s=1.70158;var p=0;var a=c;
\r
4429 if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5);
\r
4430 if (a < Math.abs(c)) { a=c; var s=p/4; }
\r
4431 else var s = p/(2*Math.PI) * Math.asin (c/a);
\r
4432 if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
\r
4433 return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
\r
4435 easeInBack: function (x, t, b, c, d, s) {
\r
4436 if (s == undefined) s = 1.70158;
\r
4437 return c*(t/=d)*t*((s+1)*t - s) + b;
\r
4439 easeOutBack: function (x, t, b, c, d, s) {
\r
4440 if (s == undefined) s = 1.70158;
\r
4441 return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
\r
4443 easeInOutBack: function (x, t, b, c, d, s) {
\r
4444 if (s == undefined) s = 1.70158;
\r
4445 if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
\r
4446 return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
\r
4448 easeInBounce: function (x, t, b, c, d) {
\r
4449 return c - $.easing.easeOutBounce (x, d-t, 0, c, d) + b;
\r
4451 easeOutBounce: function (x, t, b, c, d) {
\r
4452 if ((t/=d) < (1/2.75)) {
\r
4453 return c*(7.5625*t*t) + b;
\r
4454 } else if (t < (2/2.75)) {
\r
4455 return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
\r
4456 } else if (t < (2.5/2.75)) {
\r
4457 return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
\r
4459 return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
\r
4462 easeInOutBounce: function (x, t, b, c, d) {
\r
4463 if (t < d/2) return $.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
\r
4464 return $.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
\r
4470 * TERMS OF USE - EASING EQUATIONS
\r
4472 * Open source under the BSD License.
\r
4474 * Copyright 2001 Robert Penner
\r
4475 * All rights reserved.
\r
4477 * Redistribution and use in source and binary forms, with or without modification,
\r
4478 * are permitted provided that the following conditions are met:
\r
4480 * Redistributions of source code must retain the above copyright notice, this list of
\r
4481 * conditions and the following disclaimer.
\r
4482 * Redistributions in binary form must reproduce the above copyright notice, this list
\r
4483 * of conditions and the following disclaimer in the documentation and/or other materials
\r
4484 * provided with the distribution.
\r
4486 * Neither the name of the author nor the names of contributors may be used to endorse
\r
4487 * or promote products derived from this software without specific prior written permission.
\r
4489 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
\r
4490 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
4491 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
\r
4492 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
\r
4493 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
\r
4494 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
\r
4495 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
\r
4496 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
\r
4497 * OF THE POSSIBILITY OF SUCH DAMAGE.
\r
4503 * jQuery UI Effects Blind 1.8
\r
4505 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
4506 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
4507 * and GPL (GPL-LICENSE.txt) licenses.
\r
4509 * http://docs.jquery.com/UI/Effects/Blind
\r
4512 * jquery.effects.core.js
\r
4516 $.effects.blind = function(o) {
\r
4518 return this.queue(function() {
\r
4521 var el = $(this), props = ['position','top','left'];
\r
4524 var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode
\r
4525 var direction = o.options.direction || 'vertical'; // Default direction
\r
4528 $.effects.save(el, props); el.show(); // Save & Show
\r
4529 var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper
\r
4530 var ref = (direction == 'vertical') ? 'height' : 'width';
\r
4531 var distance = (direction == 'vertical') ? wrapper.height() : wrapper.width();
\r
4532 if(mode == 'show') wrapper.css(ref, 0); // Shift
\r
4535 var animation = {};
\r
4536 animation[ref] = mode == 'show' ? distance : 0;
\r
4539 wrapper.animate(animation, o.duration, o.options.easing, function() {
\r
4540 if(mode == 'hide') el.hide(); // Hide
\r
4541 $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
\r
4542 if(o.callback) o.callback.apply(el[0], arguments); // Callback
\r
4552 * jQuery UI Effects Bounce 1.8
\r
4554 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
4555 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
4556 * and GPL (GPL-LICENSE.txt) licenses.
\r
4558 * http://docs.jquery.com/UI/Effects/Bounce
\r
4561 * jquery.effects.core.js
\r
4565 $.effects.bounce = function(o) {
\r
4567 return this.queue(function() {
\r
4570 var el = $(this), props = ['position','top','left'];
\r
4573 var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode
\r
4574 var direction = o.options.direction || 'up'; // Default direction
\r
4575 var distance = o.options.distance || 20; // Default distance
\r
4576 var times = o.options.times || 5; // Default # of times
\r
4577 var speed = o.duration || 250; // Default speed per bounce
\r
4578 if (/show|hide/.test(mode)) props.push('opacity'); // Avoid touching opacity to prevent clearType and PNG issues in IE
\r
4581 $.effects.save(el, props); el.show(); // Save & Show
\r
4582 $.effects.createWrapper(el); // Create Wrapper
\r
4583 var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left';
\r
4584 var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg';
\r
4585 var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) / 3 : el.outerWidth({margin:true}) / 3);
\r
4586 if (mode == 'show') el.css('opacity', 0).css(ref, motion == 'pos' ? -distance : distance); // Shift
\r
4587 if (mode == 'hide') distance = distance / (times * 2);
\r
4588 if (mode != 'hide') times--;
\r
4591 if (mode == 'show') { // Show Bounce
\r
4592 var animation = {opacity: 1};
\r
4593 animation[ref] = (motion == 'pos' ? '+=' : '-=') + distance;
\r
4594 el.animate(animation, speed / 2, o.options.easing);
\r
4595 distance = distance / 2;
\r
4598 for (var i = 0; i < times; i++) { // Bounces
\r
4599 var animation1 = {}, animation2 = {};
\r
4600 animation1[ref] = (motion == 'pos' ? '-=' : '+=') + distance;
\r
4601 animation2[ref] = (motion == 'pos' ? '+=' : '-=') + distance;
\r
4602 el.animate(animation1, speed / 2, o.options.easing).animate(animation2, speed / 2, o.options.easing);
\r
4603 distance = (mode == 'hide') ? distance * 2 : distance / 2;
\r
4605 if (mode == 'hide') { // Last Bounce
\r
4606 var animation = {opacity: 0};
\r
4607 animation[ref] = (motion == 'pos' ? '-=' : '+=') + distance;
\r
4608 el.animate(animation, speed / 2, o.options.easing, function(){
\r
4609 el.hide(); // Hide
\r
4610 $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
\r
4611 if(o.callback) o.callback.apply(this, arguments); // Callback
\r
4614 var animation1 = {}, animation2 = {};
\r
4615 animation1[ref] = (motion == 'pos' ? '-=' : '+=') + distance;
\r
4616 animation2[ref] = (motion == 'pos' ? '+=' : '-=') + distance;
\r
4617 el.animate(animation1, speed / 2, o.options.easing).animate(animation2, speed / 2, o.options.easing, function(){
\r
4618 $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
\r
4619 if(o.callback) o.callback.apply(this, arguments); // Callback
\r
4622 el.queue('fx', function() { el.dequeue(); });
\r
4630 * jQuery UI Effects Clip 1.8
\r
4632 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
4633 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
4634 * and GPL (GPL-LICENSE.txt) licenses.
\r
4636 * http://docs.jquery.com/UI/Effects/Clip
\r
4639 * jquery.effects.core.js
\r
4643 $.effects.clip = function(o) {
\r
4645 return this.queue(function() {
\r
4648 var el = $(this), props = ['position','top','left','height','width'];
\r
4651 var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode
\r
4652 var direction = o.options.direction || 'vertical'; // Default direction
\r
4655 $.effects.save(el, props); el.show(); // Save & Show
\r
4656 var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper
\r
4657 var animate = el[0].tagName == 'IMG' ? wrapper : el;
\r
4659 size: (direction == 'vertical') ? 'height' : 'width',
\r
4660 position: (direction == 'vertical') ? 'top' : 'left'
\r
4662 var distance = (direction == 'vertical') ? animate.height() : animate.width();
\r
4663 if(mode == 'show') { animate.css(ref.size, 0); animate.css(ref.position, distance / 2); } // Shift
\r
4666 var animation = {};
\r
4667 animation[ref.size] = mode == 'show' ? distance : 0;
\r
4668 animation[ref.position] = mode == 'show' ? 0 : distance / 2;
\r
4671 animate.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() {
\r
4672 if(mode == 'hide') el.hide(); // Hide
\r
4673 $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
\r
4674 if(o.callback) o.callback.apply(el[0], arguments); // Callback
\r
4684 * jQuery UI Effects Drop 1.8
\r
4686 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
4687 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
4688 * and GPL (GPL-LICENSE.txt) licenses.
\r
4690 * http://docs.jquery.com/UI/Effects/Drop
\r
4693 * jquery.effects.core.js
\r
4697 $.effects.drop = function(o) {
\r
4699 return this.queue(function() {
\r
4702 var el = $(this), props = ['position','top','left','opacity'];
\r
4705 var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode
\r
4706 var direction = o.options.direction || 'left'; // Default Direction
\r
4709 $.effects.save(el, props); el.show(); // Save & Show
\r
4710 $.effects.createWrapper(el); // Create Wrapper
\r
4711 var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left';
\r
4712 var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg';
\r
4713 var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) / 2 : el.outerWidth({margin:true}) / 2);
\r
4714 if (mode == 'show') el.css('opacity', 0).css(ref, motion == 'pos' ? -distance : distance); // Shift
\r
4717 var animation = {opacity: mode == 'show' ? 1 : 0};
\r
4718 animation[ref] = (mode == 'show' ? (motion == 'pos' ? '+=' : '-=') : (motion == 'pos' ? '-=' : '+=')) + distance;
\r
4721 el.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() {
\r
4722 if(mode == 'hide') el.hide(); // Hide
\r
4723 $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
\r
4724 if(o.callback) o.callback.apply(this, arguments); // Callback
\r
4734 * jQuery UI Effects Explode 1.8
\r
4736 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
4737 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
4738 * and GPL (GPL-LICENSE.txt) licenses.
\r
4740 * http://docs.jquery.com/UI/Effects/Explode
\r
4743 * jquery.effects.core.js
\r
4747 $.effects.explode = function(o) {
\r
4749 return this.queue(function() {
\r
4751 var rows = o.options.pieces ? Math.round(Math.sqrt(o.options.pieces)) : 3;
\r
4752 var cells = o.options.pieces ? Math.round(Math.sqrt(o.options.pieces)) : 3;
\r
4754 o.options.mode = o.options.mode == 'toggle' ? ($(this).is(':visible') ? 'hide' : 'show') : o.options.mode;
\r
4755 var el = $(this).show().css('visibility', 'hidden');
\r
4756 var offset = el.offset();
\r
4758 //Substract the margins - not fixing the problem yet.
\r
4759 offset.top -= parseInt(el.css("marginTop"),10) || 0;
\r
4760 offset.left -= parseInt(el.css("marginLeft"),10) || 0;
\r
4762 var width = el.outerWidth(true);
\r
4763 var height = el.outerHeight(true);
\r
4765 for(var i=0;i<rows;i++) { // =
\r
4766 for(var j=0;j<cells;j++) { // ||
\r
4770 .wrap('<div></div>')
\r
4772 position: 'absolute',
\r
4773 visibility: 'visible',
\r
4774 left: -j*(width/cells),
\r
4775 top: -i*(height/rows)
\r
4778 .addClass('ui-effects-explode')
\r
4780 position: 'absolute',
\r
4781 overflow: 'hidden',
\r
4782 width: width/cells,
\r
4783 height: height/rows,
\r
4784 left: offset.left + j*(width/cells) + (o.options.mode == 'show' ? (j-Math.floor(cells/2))*(width/cells) : 0),
\r
4785 top: offset.top + i*(height/rows) + (o.options.mode == 'show' ? (i-Math.floor(rows/2))*(height/rows) : 0),
\r
4786 opacity: o.options.mode == 'show' ? 0 : 1
\r
4788 left: offset.left + j*(width/cells) + (o.options.mode == 'show' ? 0 : (j-Math.floor(cells/2))*(width/cells)),
\r
4789 top: offset.top + i*(height/rows) + (o.options.mode == 'show' ? 0 : (i-Math.floor(rows/2))*(height/rows)),
\r
4790 opacity: o.options.mode == 'show' ? 1 : 0
\r
4791 }, o.duration || 500);
\r
4795 // Set a timeout, to call the callback approx. when the other animations have finished
\r
4796 setTimeout(function() {
\r
4798 o.options.mode == 'show' ? el.css({ visibility: 'visible' }) : el.css({ visibility: 'visible' }).hide();
\r
4799 if(o.callback) o.callback.apply(el[0]); // Callback
\r
4802 $('div.ui-effects-explode').remove();
\r
4804 }, o.duration || 500);
\r
4813 * jQuery UI Effects Fade 1.8
\r
4815 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
4816 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
4817 * and GPL (GPL-LICENSE.txt) licenses.
\r
4819 * http://docs.jquery.com/UI/Effects/Fade
\r
4822 * jquery.effects.core.js
\r
4826 $.effects.fade = function(o) {
\r
4827 return this.queue(function() {
\r
4828 var elem = $(this),
\r
4829 mode = $.effects.setMode(elem, o.options.mode || 'hide');
\r
4831 elem.animate({ opacity: mode }, {
\r
4833 duration: o.duration,
\r
4834 easing: o.options.easing,
\r
4835 complete: function() {
\r
4836 (o.callback && o.callback.apply(this, arguments));
\r
4845 * jQuery UI Effects Fold 1.8
\r
4847 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
4848 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
4849 * and GPL (GPL-LICENSE.txt) licenses.
\r
4851 * http://docs.jquery.com/UI/Effects/Fold
\r
4854 * jquery.effects.core.js
\r
4858 $.effects.fold = function(o) {
\r
4860 return this.queue(function() {
\r
4863 var el = $(this), props = ['position','top','left'];
\r
4866 var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode
\r
4867 var size = o.options.size || 15; // Default fold size
\r
4868 var horizFirst = !(!o.options.horizFirst); // Ensure a boolean value
\r
4869 var duration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2;
\r
4872 $.effects.save(el, props); el.show(); // Save & Show
\r
4873 var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper
\r
4874 var widthFirst = ((mode == 'show') != horizFirst);
\r
4875 var ref = widthFirst ? ['width', 'height'] : ['height', 'width'];
\r
4876 var distance = widthFirst ? [wrapper.width(), wrapper.height()] : [wrapper.height(), wrapper.width()];
\r
4877 var percent = /([0-9]+)%/.exec(size);
\r
4878 if(percent) size = parseInt(percent[1],10) / 100 * distance[mode == 'hide' ? 0 : 1];
\r
4879 if(mode == 'show') wrapper.css(horizFirst ? {height: 0, width: size} : {height: size, width: 0}); // Shift
\r
4882 var animation1 = {}, animation2 = {};
\r
4883 animation1[ref[0]] = mode == 'show' ? distance[0] : size;
\r
4884 animation2[ref[1]] = mode == 'show' ? distance[1] : 0;
\r
4887 wrapper.animate(animation1, duration, o.options.easing)
\r
4888 .animate(animation2, duration, o.options.easing, function() {
\r
4889 if(mode == 'hide') el.hide(); // Hide
\r
4890 $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
\r
4891 if(o.callback) o.callback.apply(el[0], arguments); // Callback
\r
4901 * jQuery UI Effects Highlight 1.8
\r
4903 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
4904 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
4905 * and GPL (GPL-LICENSE.txt) licenses.
\r
4907 * http://docs.jquery.com/UI/Effects/Highlight
\r
4910 * jquery.effects.core.js
\r
4914 $.effects.highlight = function(o) {
\r
4915 return this.queue(function() {
\r
4916 var elem = $(this),
\r
4917 props = ['backgroundImage', 'backgroundColor', 'opacity'],
\r
4918 mode = $.effects.setMode(elem, o.options.mode || 'show'),
\r
4920 backgroundColor: elem.css('backgroundColor')
\r
4923 if (mode == 'hide') {
\r
4924 animation.opacity = 0;
\r
4927 $.effects.save(elem, props);
\r
4931 backgroundImage: 'none',
\r
4932 backgroundColor: o.options.color || '#ffff99'
\r
4934 .animate(animation, {
\r
4936 duration: o.duration,
\r
4937 easing: o.options.easing,
\r
4938 complete: function() {
\r
4939 (mode == 'hide' && elem.hide());
\r
4940 $.effects.restore(elem, props);
\r
4941 (mode == 'show' && !$.support.opacity && this.style.removeAttribute('filter'));
\r
4942 (o.callback && o.callback.apply(this, arguments));
\r
4951 * jQuery UI Effects Pulsate 1.8
\r
4953 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
4954 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
4955 * and GPL (GPL-LICENSE.txt) licenses.
\r
4957 * http://docs.jquery.com/UI/Effects/Pulsate
\r
4960 * jquery.effects.core.js
\r
4964 $.effects.pulsate = function(o) {
\r
4965 return this.queue(function() {
\r
4966 var elem = $(this),
\r
4967 mode = $.effects.setMode(elem, o.options.mode || 'show');
\r
4968 times = ((o.options.times || 5) * 2) - 1;
\r
4969 duration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2,
\r
4970 isVisible = elem.is(':visible'),
\r
4974 elem.css('opacity', 0).show();
\r
4978 if ((mode == 'hide' && isVisible) || (mode == 'show' && !isVisible)) {
\r
4982 for (var i = 0; i < times; i++) {
\r
4983 elem.animate({ opacity: animateTo }, duration, o.options.easing);
\r
4984 animateTo = (animateTo + 1) % 2;
\r
4987 elem.animate({ opacity: animateTo }, duration, o.options.easing, function() {
\r
4988 if (animateTo == 0) {
\r
4991 (o.callback && o.callback.apply(this, arguments));
\r
4995 .queue('fx', function() { elem.dequeue(); })
\r
5002 * jQuery UI Effects Scale 1.8
\r
5004 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
5005 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
5006 * and GPL (GPL-LICENSE.txt) licenses.
\r
5008 * http://docs.jquery.com/UI/Effects/Scale
\r
5011 * jquery.effects.core.js
\r
5015 $.effects.puff = function(o) {
\r
5016 return this.queue(function() {
\r
5017 var elem = $(this),
\r
5018 mode = $.effects.setMode(elem, o.options.mode || 'hide'),
\r
5019 percent = parseInt(o.options.percent, 10) || 150,
\r
5020 factor = percent / 100,
\r
5021 original = { height: elem.height(), width: elem.width() };
\r
5023 $.extend(o.options, {
\r
5026 percent: mode == 'hide' ? percent : 100,
\r
5027 from: mode == 'hide'
\r
5030 height: original.height * factor,
\r
5031 width: original.width * factor
\r
5035 elem.effect('scale', o.options, o.duration, o.callback);
\r
5040 $.effects.scale = function(o) {
\r
5042 return this.queue(function() {
\r
5048 var options = $.extend(true, {}, o.options);
\r
5049 var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode
\r
5050 var percent = parseInt(o.options.percent,10) || (parseInt(o.options.percent,10) == 0 ? 0 : (mode == 'hide' ? 0 : 100)); // Set default scaling percent
\r
5051 var direction = o.options.direction || 'both'; // Set default axis
\r
5052 var origin = o.options.origin; // The origin of the scaling
\r
5053 if (mode != 'effect') { // Set default origin and restore for show/hide
\r
5054 options.origin = origin || ['middle','center'];
\r
5055 options.restore = true;
\r
5057 var original = {height: el.height(), width: el.width()}; // Save original
\r
5058 el.from = o.options.from || (mode == 'show' ? {height: 0, width: 0} : original); // Default from state
\r
5061 var factor = { // Set scaling factor
\r
5062 y: direction != 'horizontal' ? (percent / 100) : 1,
\r
5063 x: direction != 'vertical' ? (percent / 100) : 1
\r
5065 el.to = {height: original.height * factor.y, width: original.width * factor.x}; // Set to state
\r
5067 if (o.options.fade) { // Fade option to support puff
\r
5068 if (mode == 'show') {el.from.opacity = 0; el.to.opacity = 1;};
\r
5069 if (mode == 'hide') {el.from.opacity = 1; el.to.opacity = 0;};
\r
5073 options.from = el.from; options.to = el.to; options.mode = mode;
\r
5076 el.effect('size', options, o.duration, o.callback);
\r
5082 $.effects.size = function(o) {
\r
5084 return this.queue(function() {
\r
5087 var el = $(this), props = ['position','top','left','width','height','overflow','opacity'];
\r
5088 var props1 = ['position','top','left','overflow','opacity']; // Always restore
\r
5089 var props2 = ['width','height','overflow']; // Copy for children
\r
5090 var cProps = ['fontSize'];
\r
5091 var vProps = ['borderTopWidth', 'borderBottomWidth', 'paddingTop', 'paddingBottom'];
\r
5092 var hProps = ['borderLeftWidth', 'borderRightWidth', 'paddingLeft', 'paddingRight'];
\r
5095 var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode
\r
5096 var restore = o.options.restore || false; // Default restore
\r
5097 var scale = o.options.scale || 'both'; // Default scale mode
\r
5098 var origin = o.options.origin; // The origin of the sizing
\r
5099 var original = {height: el.height(), width: el.width()}; // Save original
\r
5100 el.from = o.options.from || original; // Default from state
\r
5101 el.to = o.options.to || original; // Default to state
\r
5103 if (origin) { // Calculate baseline shifts
\r
5104 var baseline = $.effects.getBaseline(origin, original);
\r
5105 el.from.top = (original.height - el.from.height) * baseline.y;
\r
5106 el.from.left = (original.width - el.from.width) * baseline.x;
\r
5107 el.to.top = (original.height - el.to.height) * baseline.y;
\r
5108 el.to.left = (original.width - el.to.width) * baseline.x;
\r
5110 var factor = { // Set scaling factor
\r
5111 from: {y: el.from.height / original.height, x: el.from.width / original.width},
\r
5112 to: {y: el.to.height / original.height, x: el.to.width / original.width}
\r
5114 if (scale == 'box' || scale == 'both') { // Scale the css box
\r
5115 if (factor.from.y != factor.to.y) { // Vertical props scaling
\r
5116 props = props.concat(vProps);
\r
5117 el.from = $.effects.setTransition(el, vProps, factor.from.y, el.from);
\r
5118 el.to = $.effects.setTransition(el, vProps, factor.to.y, el.to);
\r
5120 if (factor.from.x != factor.to.x) { // Horizontal props scaling
\r
5121 props = props.concat(hProps);
\r
5122 el.from = $.effects.setTransition(el, hProps, factor.from.x, el.from);
\r
5123 el.to = $.effects.setTransition(el, hProps, factor.to.x, el.to);
\r
5126 if (scale == 'content' || scale == 'both') { // Scale the content
\r
5127 if (factor.from.y != factor.to.y) { // Vertical props scaling
\r
5128 props = props.concat(cProps);
\r
5129 el.from = $.effects.setTransition(el, cProps, factor.from.y, el.from);
\r
5130 el.to = $.effects.setTransition(el, cProps, factor.to.y, el.to);
\r
5133 $.effects.save(el, restore ? props : props1); el.show(); // Save & Show
\r
5134 $.effects.createWrapper(el); // Create Wrapper
\r
5135 el.css('overflow','hidden').css(el.from); // Shift
\r
5138 if (scale == 'content' || scale == 'both') { // Scale the children
\r
5139 vProps = vProps.concat(['marginTop','marginBottom']).concat(cProps); // Add margins/font-size
\r
5140 hProps = hProps.concat(['marginLeft','marginRight']); // Add margins
\r
5141 props2 = props.concat(vProps).concat(hProps); // Concat
\r
5142 el.find("*[width]").each(function(){
\r
5144 if (restore) $.effects.save(child, props2);
\r
5145 var c_original = {height: child.height(), width: child.width()}; // Save original
\r
5146 child.from = {height: c_original.height * factor.from.y, width: c_original.width * factor.from.x};
\r
5147 child.to = {height: c_original.height * factor.to.y, width: c_original.width * factor.to.x};
\r
5148 if (factor.from.y != factor.to.y) { // Vertical props scaling
\r
5149 child.from = $.effects.setTransition(child, vProps, factor.from.y, child.from);
\r
5150 child.to = $.effects.setTransition(child, vProps, factor.to.y, child.to);
\r
5152 if (factor.from.x != factor.to.x) { // Horizontal props scaling
\r
5153 child.from = $.effects.setTransition(child, hProps, factor.from.x, child.from);
\r
5154 child.to = $.effects.setTransition(child, hProps, factor.to.x, child.to);
\r
5156 child.css(child.from); // Shift children
\r
5157 child.animate(child.to, o.duration, o.options.easing, function(){
\r
5158 if (restore) $.effects.restore(child, props2); // Restore children
\r
5159 }); // Animate children
\r
5164 el.animate(el.to, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() {
\r
5165 if (el.to.opacity === 0) {
\r
5166 el.css('opacity', el.from.opacity);
\r
5168 if(mode == 'hide') el.hide(); // Hide
\r
5169 $.effects.restore(el, restore ? props : props1); $.effects.removeWrapper(el); // Restore
\r
5170 if(o.callback) o.callback.apply(this, arguments); // Callback
\r
5180 * jQuery UI Effects Shake 1.8
\r
5182 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
5183 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
5184 * and GPL (GPL-LICENSE.txt) licenses.
\r
5186 * http://docs.jquery.com/UI/Effects/Shake
\r
5189 * jquery.effects.core.js
\r
5193 $.effects.shake = function(o) {
\r
5195 return this.queue(function() {
\r
5198 var el = $(this), props = ['position','top','left'];
\r
5201 var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode
\r
5202 var direction = o.options.direction || 'left'; // Default direction
\r
5203 var distance = o.options.distance || 20; // Default distance
\r
5204 var times = o.options.times || 3; // Default # of times
\r
5205 var speed = o.duration || o.options.duration || 140; // Default speed per shake
\r
5208 $.effects.save(el, props); el.show(); // Save & Show
\r
5209 $.effects.createWrapper(el); // Create Wrapper
\r
5210 var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left';
\r
5211 var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg';
\r
5214 var animation = {}, animation1 = {}, animation2 = {};
\r
5215 animation[ref] = (motion == 'pos' ? '-=' : '+=') + distance;
\r
5216 animation1[ref] = (motion == 'pos' ? '+=' : '-=') + distance * 2;
\r
5217 animation2[ref] = (motion == 'pos' ? '-=' : '+=') + distance * 2;
\r
5220 el.animate(animation, speed, o.options.easing);
\r
5221 for (var i = 1; i < times; i++) { // Shakes
\r
5222 el.animate(animation1, speed, o.options.easing).animate(animation2, speed, o.options.easing);
\r
5224 el.animate(animation1, speed, o.options.easing).
\r
5225 animate(animation, speed / 2, o.options.easing, function(){ // Last shake
\r
5226 $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
\r
5227 if(o.callback) o.callback.apply(this, arguments); // Callback
\r
5229 el.queue('fx', function() { el.dequeue(); });
\r
5237 * jQuery UI Effects Slide 1.8
\r
5239 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
5240 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
5241 * and GPL (GPL-LICENSE.txt) licenses.
\r
5243 * http://docs.jquery.com/UI/Effects/Slide
\r
5246 * jquery.effects.core.js
\r
5250 $.effects.slide = function(o) {
\r
5252 return this.queue(function() {
\r
5255 var el = $(this), props = ['position','top','left'];
\r
5258 var mode = $.effects.setMode(el, o.options.mode || 'show'); // Set Mode
\r
5259 var direction = o.options.direction || 'left'; // Default Direction
\r
5262 $.effects.save(el, props); el.show(); // Save & Show
\r
5263 $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper
\r
5264 var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left';
\r
5265 var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg';
\r
5266 var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) : el.outerWidth({margin:true}));
\r
5267 if (mode == 'show') el.css(ref, motion == 'pos' ? -distance : distance); // Shift
\r
5270 var animation = {};
\r
5271 animation[ref] = (mode == 'show' ? (motion == 'pos' ? '+=' : '-=') : (motion == 'pos' ? '-=' : '+=')) + distance;
\r
5274 el.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() {
\r
5275 if(mode == 'hide') el.hide(); // Hide
\r
5276 $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
\r
5277 if(o.callback) o.callback.apply(this, arguments); // Callback
\r
5287 * jQuery UI Effects Transfer 1.8
\r
5289 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
5290 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
5291 * and GPL (GPL-LICENSE.txt) licenses.
\r
5293 * http://docs.jquery.com/UI/Effects/Transfer
\r
5296 * jquery.effects.core.js
\r
5300 $.effects.transfer = function(o) {
\r
5301 return this.queue(function() {
\r
5302 var elem = $(this),
\r
5303 target = $(o.options.to),
\r
5304 endPosition = target.offset(),
\r
5306 top: endPosition.top,
\r
5307 left: endPosition.left,
\r
5308 height: target.innerHeight(),
\r
5309 width: target.innerWidth()
\r
5311 startPosition = elem.offset(),
\r
5312 transfer = $('<div class="ui-effects-transfer"></div>')
\r
5313 .appendTo(document.body)
\r
5314 .addClass(o.options.className)
\r
5316 top: startPosition.top,
\r
5317 left: startPosition.left,
\r
5318 height: elem.innerHeight(),
\r
5319 width: elem.innerWidth(),
\r
5320 position: 'absolute'
\r
5322 .animate(animation, o.duration, o.options.easing, function() {
\r
5323 transfer.remove();
\r
5324 (o.callback && o.callback.apply(elem[0], arguments));
\r
5332 * jQuery UI Accordion 1.8
\r
5334 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
5335 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
5336 * and GPL (GPL-LICENSE.txt) licenses.
\r
5338 * http://docs.jquery.com/UI/Accordion
\r
5341 * jquery.ui.core.js
\r
5342 * jquery.ui.widget.js
\r
5346 $.widget("ui.accordion", {
\r
5349 animated: 'slide',
\r
5351 clearStyle: false,
\r
5352 collapsible: false,
\r
5355 header: "> li > :first-child,> :not(li):even",
\r
5357 header: "ui-icon-triangle-1-e",
\r
5358 headerSelected: "ui-icon-triangle-1-s"
\r
5360 navigation: false,
\r
5361 navigationFilter: function() {
\r
5362 return this.href.toLowerCase() == location.href.toLowerCase();
\r
5365 _create: function() {
\r
5367 var o = this.options, self = this;
\r
5370 this.element.addClass("ui-accordion ui-widget ui-helper-reset");
\r
5372 // in lack of child-selectors in CSS we need to mark top-LIs in a UL-accordion for some IE-fix
\r
5373 if (this.element[0].nodeName == "UL") {
\r
5374 this.element.children("li").addClass("ui-accordion-li-fix");
\r
5377 this.headers = this.element.find(o.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all")
\r
5378 .bind("mouseenter.accordion", function(){ $(this).addClass('ui-state-hover'); })
\r
5379 .bind("mouseleave.accordion", function(){ $(this).removeClass('ui-state-hover'); })
\r
5380 .bind("focus.accordion", function(){ $(this).addClass('ui-state-focus'); })
\r
5381 .bind("blur.accordion", function(){ $(this).removeClass('ui-state-focus'); });
\r
5385 .addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");
\r
5387 if ( o.navigation ) {
\r
5388 var current = this.element.find("a").filter(o.navigationFilter);
\r
5389 if ( current.length ) {
\r
5390 var header = current.closest(".ui-accordion-header");
\r
5391 if ( header.length ) {
\r
5392 // anchor within header
\r
5393 this.active = header;
\r
5395 // anchor within content
\r
5396 this.active = current.closest(".ui-accordion-content").prev();
\r
5401 this.active = this._findActive(this.active || o.active).toggleClass("ui-state-default").toggleClass("ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");
\r
5402 this.active.next().addClass('ui-accordion-content-active');
\r
5404 //Append icon elements
\r
5405 this._createIcons();
\r
5407 // IE7-/Win - Extra vertical space in lists fixed
\r
5408 if ($.browser.msie) {
\r
5409 this.element.find('a').css('zoom', '1');
\r
5415 this.element.attr('role','tablist');
\r
5418 .attr('role','tab')
\r
5419 .bind('keydown', function(event) { return self._keydown(event); })
\r
5421 .attr('role','tabpanel');
\r
5424 .not(this.active || "")
\r
5425 .attr('aria-expanded','false')
\r
5426 .attr("tabIndex", "-1")
\r
5430 // make sure at least one header is in the tab order
\r
5431 if (!this.active.length) {
\r
5432 this.headers.eq(0).attr('tabIndex','0');
\r
5435 .attr('aria-expanded','true')
\r
5436 .attr('tabIndex', '0');
\r
5439 // only need links in taborder for Safari
\r
5440 if (!$.browser.safari)
\r
5441 this.headers.find('a').attr('tabIndex','-1');
\r
5444 this.headers.bind((o.event) + ".accordion", function(event) {
\r
5445 self._clickHandler.call(self, event, this);
\r
5446 event.preventDefault();
\r
5452 _createIcons: function() {
\r
5453 var o = this.options;
\r
5455 $("<span/>").addClass("ui-icon " + o.icons.header).prependTo(this.headers);
\r
5456 this.active.find(".ui-icon").toggleClass(o.icons.header).toggleClass(o.icons.headerSelected);
\r
5457 this.element.addClass("ui-accordion-icons");
\r
5461 _destroyIcons: function() {
\r
5462 this.headers.children(".ui-icon").remove();
\r
5463 this.element.removeClass("ui-accordion-icons");
\r
5466 destroy: function() {
\r
5467 var o = this.options;
\r
5470 .removeClass("ui-accordion ui-widget ui-helper-reset")
\r
5471 .removeAttr("role")
\r
5472 .unbind('.accordion')
\r
5473 .removeData('accordion');
\r
5476 .unbind(".accordion")
\r
5477 .removeClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-corner-top")
\r
5478 .removeAttr("role").removeAttr("aria-expanded").removeAttr("tabindex");
\r
5480 this.headers.find("a").removeAttr("tabindex");
\r
5481 this._destroyIcons();
\r
5482 var contents = this.headers.next().css("display", "").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active");
\r
5483 if (o.autoHeight || o.fillHeight) {
\r
5484 contents.css("height", "");
\r
5490 _setOption: function(key, value) {
\r
5491 $.Widget.prototype._setOption.apply(this, arguments);
\r
5493 if (key == "active") {
\r
5494 this.activate(value);
\r
5496 if (key == "icons") {
\r
5497 this._destroyIcons();
\r
5499 this._createIcons();
\r
5505 _keydown: function(event) {
\r
5507 var o = this.options, keyCode = $.ui.keyCode;
\r
5509 if (o.disabled || event.altKey || event.ctrlKey)
\r
5512 var length = this.headers.length;
\r
5513 var currentIndex = this.headers.index(event.target);
\r
5514 var toFocus = false;
\r
5516 switch(event.keyCode) {
\r
5517 case keyCode.RIGHT:
\r
5518 case keyCode.DOWN:
\r
5519 toFocus = this.headers[(currentIndex + 1) % length];
\r
5521 case keyCode.LEFT:
\r
5523 toFocus = this.headers[(currentIndex - 1 + length) % length];
\r
5525 case keyCode.SPACE:
\r
5526 case keyCode.ENTER:
\r
5527 this._clickHandler({ target: event.target }, event.target);
\r
5528 event.preventDefault();
\r
5532 $(event.target).attr('tabIndex','-1');
\r
5533 $(toFocus).attr('tabIndex','0');
\r
5542 resize: function() {
\r
5544 var o = this.options, maxHeight;
\r
5546 if (o.fillSpace) {
\r
5548 if($.browser.msie) { var defOverflow = this.element.parent().css('overflow'); this.element.parent().css('overflow', 'hidden'); }
\r
5549 maxHeight = this.element.parent().height();
\r
5550 if($.browser.msie) { this.element.parent().css('overflow', defOverflow); }
\r
5552 this.headers.each(function() {
\r
5553 maxHeight -= $(this).outerHeight(true);
\r
5556 this.headers.next().each(function() {
\r
5557 $(this).height(Math.max(0, maxHeight - $(this).innerHeight() + $(this).height()));
\r
5558 }).css('overflow', 'auto');
\r
5560 } else if ( o.autoHeight ) {
\r
5562 this.headers.next().each(function() {
\r
5563 maxHeight = Math.max(maxHeight, $(this).height());
\r
5564 }).height(maxHeight);
\r
5570 activate: function(index) {
\r
5571 // TODO this gets called on init, changing the option without an explicit call for that
\r
5572 this.options.active = index;
\r
5573 // call clickHandler with custom event
\r
5574 var active = this._findActive(index)[0];
\r
5575 this._clickHandler({ target: active }, active);
\r
5580 _findActive: function(selector) {
\r
5582 ? typeof selector == "number"
\r
5583 ? this.headers.filter(":eq(" + selector + ")")
\r
5584 : this.headers.not(this.headers.not(selector))
\r
5585 : selector === false
\r
5587 : this.headers.filter(":eq(0)");
\r
5590 // TODO isn't event.target enough? why the seperate target argument?
\r
5591 _clickHandler: function(event, target) {
\r
5593 var o = this.options;
\r
5597 // called only when using activate(false) to close all parts programmatically
\r
5598 if (!event.target) {
\r
5599 if (!o.collapsible)
\r
5601 this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all")
\r
5602 .find(".ui-icon").removeClass(o.icons.headerSelected).addClass(o.icons.header);
\r
5603 this.active.next().addClass('ui-accordion-content-active');
\r
5604 var toHide = this.active.next(),
\r
5608 oldHeader: o.active,
\r
5609 newContent: $([]),
\r
5610 oldContent: toHide
\r
5612 toShow = (this.active = $([]));
\r
5613 this._toggle(toShow, toHide, data);
\r
5617 // get the click target
\r
5618 var clicked = $(event.currentTarget || target);
\r
5619 var clickedIsActive = clicked[0] == this.active[0];
\r
5621 // TODO the option is changed, is that correct?
\r
5622 // TODO if it is correct, shouldn't that happen after determining that the click is valid?
\r
5623 o.active = o.collapsible && clickedIsActive ? false : $('.ui-accordion-header', this.element).index(clicked);
\r
5625 // if animations are still active, or the active header is the target, ignore click
\r
5626 if (this.running || (!o.collapsible && clickedIsActive)) {
\r
5631 this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all")
\r
5632 .find(".ui-icon").removeClass(o.icons.headerSelected).addClass(o.icons.header);
\r
5633 if (!clickedIsActive) {
\r
5634 clicked.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top")
\r
5635 .find(".ui-icon").removeClass(o.icons.header).addClass(o.icons.headerSelected);
\r
5636 clicked.next().addClass('ui-accordion-content-active');
\r
5639 // find elements to show and hide
\r
5640 var toShow = clicked.next(),
\r
5641 toHide = this.active.next(),
\r
5644 newHeader: clickedIsActive && o.collapsible ? $([]) : clicked,
\r
5645 oldHeader: this.active,
\r
5646 newContent: clickedIsActive && o.collapsible ? $([]) : toShow,
\r
5647 oldContent: toHide
\r
5649 down = this.headers.index( this.active[0] ) > this.headers.index( clicked[0] );
\r
5651 this.active = clickedIsActive ? $([]) : clicked;
\r
5652 this._toggle(toShow, toHide, data, clickedIsActive, down);
\r
5658 _toggle: function(toShow, toHide, data, clickedIsActive, down) {
\r
5660 var o = this.options, self = this;
\r
5662 this.toShow = toShow;
\r
5663 this.toHide = toHide;
\r
5666 var complete = function() { if(!self) return; return self._completed.apply(self, arguments); };
\r
5668 // trigger changestart event
\r
5669 this._trigger("changestart", null, this.data);
\r
5671 // count elements to animate
\r
5672 this.running = toHide.size() === 0 ? toShow.size() : toHide.size();
\r
5676 var animOptions = {};
\r
5678 if ( o.collapsible && clickedIsActive ) {
\r
5682 complete: complete,
\r
5684 autoHeight: o.autoHeight || o.fillSpace
\r
5690 complete: complete,
\r
5692 autoHeight: o.autoHeight || o.fillSpace
\r
5697 o.proxied = o.animated;
\r
5700 if (!o.proxiedDuration) {
\r
5701 o.proxiedDuration = o.duration;
\r
5704 o.animated = $.isFunction(o.proxied) ?
\r
5705 o.proxied(animOptions) : o.proxied;
\r
5707 o.duration = $.isFunction(o.proxiedDuration) ?
\r
5708 o.proxiedDuration(animOptions) : o.proxiedDuration;
\r
5710 var animations = $.ui.accordion.animations,
\r
5711 duration = o.duration,
\r
5712 easing = o.animated;
\r
5714 if (easing && !animations[easing] && !$.easing[easing]) {
\r
5717 if (!animations[easing]) {
\r
5718 animations[easing] = function(options) {
\r
5719 this.slide(options, {
\r
5721 duration: duration || 700
\r
5726 animations[easing](animOptions);
\r
5730 if (o.collapsible && clickedIsActive) {
\r
5741 // TODO assert that the blur and focus triggers are really necessary, remove otherwise
\r
5742 toHide.prev().attr('aria-expanded','false').attr("tabIndex", "-1").blur();
\r
5743 toShow.prev().attr('aria-expanded','true').attr("tabIndex", "0").focus();
\r
5747 _completed: function(cancel) {
\r
5749 var o = this.options;
\r
5751 this.running = cancel ? 0 : --this.running;
\r
5752 if (this.running) return;
\r
5754 if (o.clearStyle) {
\r
5755 this.toShow.add(this.toHide).css({
\r
5761 // other classes are removed before the animation; this one needs to stay until completed
\r
5762 this.toHide.removeClass("ui-accordion-content-active");
\r
5764 this._trigger('change', null, this.data);
\r
5770 $.extend($.ui.accordion, {
\r
5773 slide: function(options, additions) {
\r
5774 options = $.extend({
\r
5777 }, options, additions);
\r
5778 if ( !options.toHide.size() ) {
\r
5779 options.toShow.animate({height: "show"}, options);
\r
5782 if ( !options.toShow.size() ) {
\r
5783 options.toHide.animate({height: "hide"}, options);
\r
5786 var overflow = options.toShow.css('overflow'),
\r
5790 fxAttrs = [ "height", "paddingTop", "paddingBottom" ],
\r
5792 // fix width before calculating height of hidden element
\r
5793 var s = options.toShow;
\r
5794 originalWidth = s[0].style.width;
\r
5795 s.width( parseInt(s.parent().width(),10) - parseInt(s.css("paddingLeft"),10) - parseInt(s.css("paddingRight"),10) - (parseInt(s.css("borderLeftWidth"),10) || 0) - (parseInt(s.css("borderRightWidth"),10) || 0) );
\r
5797 $.each(fxAttrs, function(i, prop) {
\r
5798 hideProps[prop] = 'hide';
\r
5800 var parts = ('' + $.css(options.toShow[0], prop)).match(/^([\d+-.]+)(.*)$/);
\r
5801 showProps[prop] = {
\r
5803 unit: parts[2] || 'px'
\r
5806 options.toShow.css({ height: 0, overflow: 'hidden' }).show();
\r
5807 options.toHide.filter(":hidden").each(options.complete).end().filter(":visible").animate(hideProps,{
\r
5808 step: function(now, settings) {
\r
5809 // only calculate the percent when animating height
\r
5810 // IE gets very inconsistent results when animating elements
\r
5811 // with small values, which is common for padding
\r
5812 if (settings.prop == 'height') {
\r
5813 percentDone = ( settings.end - settings.start === 0 ) ? 0 :
\r
5814 (settings.now - settings.start) / (settings.end - settings.start);
\r
5817 options.toShow[0].style[settings.prop] =
\r
5818 (percentDone * showProps[settings.prop].value) + showProps[settings.prop].unit;
\r
5820 duration: options.duration,
\r
5821 easing: options.easing,
\r
5822 complete: function() {
\r
5823 if ( !options.autoHeight ) {
\r
5824 options.toShow.css("height", "");
\r
5826 options.toShow.css("width", originalWidth);
\r
5827 options.toShow.css({overflow: overflow});
\r
5828 options.complete();
\r
5832 bounceslide: function(options) {
\r
5833 this.slide(options, {
\r
5834 easing: options.down ? "easeOutBounce" : "swing",
\r
5835 duration: options.down ? 1000 : 200
\r
5843 * jQuery UI Autocomplete 1.8
\r
5845 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
5846 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
5847 * and GPL (GPL-LICENSE.txt) licenses.
\r
5849 * http://docs.jquery.com/UI/Autocomplete
\r
5852 * jquery.ui.core.js
\r
5853 * jquery.ui.widget.js
\r
5854 * jquery.ui.position.js
\r
5858 $.widget( "ui.autocomplete", {
\r
5863 _create: function() {
\r
5865 doc = this.element[ 0 ].ownerDocument;
\r
5867 .addClass( "ui-autocomplete-input" )
\r
5868 .attr( "autocomplete", "off" )
\r
5869 // TODO verify these actually work as intended
\r
5872 "aria-autocomplete": "list",
\r
5873 "aria-haspopup": "true"
\r
5875 .bind( "keydown.autocomplete", function( event ) {
\r
5876 var keyCode = $.ui.keyCode;
\r
5877 switch( event.keyCode ) {
\r
5878 case keyCode.PAGE_UP:
\r
5879 self._move( "previousPage", event );
\r
5881 case keyCode.PAGE_DOWN:
\r
5882 self._move( "nextPage", event );
\r
5885 self._move( "previous", event );
\r
5886 // prevent moving cursor to beginning of text field in some browsers
\r
5887 event.preventDefault();
\r
5889 case keyCode.DOWN:
\r
5890 self._move( "next", event );
\r
5891 // prevent moving cursor to end of text field in some browsers
\r
5892 event.preventDefault();
\r
5894 case keyCode.ENTER:
\r
5895 // when menu is open or has focus
\r
5896 if ( self.menu.active ) {
\r
5897 event.preventDefault();
\r
5899 //passthrough - ENTER and TAB both select the current element
\r
5901 if ( !self.menu.active ) {
\r
5904 self.menu.select();
\r
5906 case keyCode.ESCAPE:
\r
5907 self.element.val( self.term );
\r
5908 self.close( event );
\r
5910 case keyCode.SHIFT:
\r
5911 case keyCode.CONTROL:
\r
5913 // ignore metakeys (shift, ctrl, alt)
\r
5916 // keypress is triggered before the input value is changed
\r
5917 clearTimeout( self.searching );
\r
5918 self.searching = setTimeout(function() {
\r
5919 self.search( null, event );
\r
5920 }, self.options.delay );
\r
5924 .bind( "focus.autocomplete", function() {
\r
5925 self.previous = self.element.val();
\r
5927 .bind( "blur.autocomplete", function( event ) {
\r
5928 clearTimeout( self.searching );
\r
5929 // clicks on the menu (or a button to trigger a search) will cause a blur event
\r
5930 // TODO try to implement this without a timeout, see clearTimeout in search()
\r
5931 self.closing = setTimeout(function() {
\r
5932 self.close( event );
\r
5935 this._initSource();
\r
5936 this.response = function() {
\r
5937 return self._response.apply( self, arguments );
\r
5939 this.menu = $( "<ul></ul>" )
\r
5940 .addClass( "ui-autocomplete" )
\r
5941 .appendTo( "body", doc )
\r
5943 focus: function( event, ui ) {
\r
5944 var item = ui.item.data( "item.autocomplete" );
\r
5945 if ( false !== self._trigger( "focus", null, { item: item } ) ) {
\r
5946 // use value to match what will end up in the input
\r
5947 self.element.val( item.value );
\r
5950 selected: function( event, ui ) {
\r
5951 var item = ui.item.data( "item.autocomplete" );
\r
5952 if ( false !== self._trigger( "select", event, { item: item } ) ) {
\r
5953 self.element.val( item.value );
\r
5955 self.close( event );
\r
5956 self.previous = self.element.val();
\r
5957 // only trigger when focus was lost (click on menu)
\r
5958 if ( self.element[0] !== doc.activeElement ) {
\r
5959 self.element.focus();
\r
5962 blur: function( event, ui ) {
\r
5963 if ( self.menu.element.is(":visible") ) {
\r
5964 self.element.val( self.term );
\r
5968 .zIndex( this.element.zIndex() + 1 )
\r
5969 // workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781
\r
5970 .css({ top: 0, left: 0 })
\r
5973 if ( $.fn.bgiframe ) {
\r
5974 this.menu.element.bgiframe();
\r
5978 destroy: function() {
\r
5980 .removeClass( "ui-autocomplete-input ui-widget ui-widget-content" )
\r
5981 .removeAttr( "autocomplete" )
\r
5982 .removeAttr( "role" )
\r
5983 .removeAttr( "aria-autocomplete" )
\r
5984 .removeAttr( "aria-haspopup" );
\r
5985 this.menu.element.remove();
\r
5986 $.Widget.prototype.destroy.call( this );
\r
5989 _setOption: function( key ) {
\r
5990 $.Widget.prototype._setOption.apply( this, arguments );
\r
5991 if ( key === "source" ) {
\r
5992 this._initSource();
\r
5996 _initSource: function() {
\r
5999 if ( $.isArray(this.options.source) ) {
\r
6000 array = this.options.source;
\r
6001 this.source = function( request, response ) {
\r
6002 // escape regex characters
\r
6003 var matcher = new RegExp( $.ui.autocomplete.escapeRegex(request.term), "i" );
\r
6004 response( $.grep( array, function(value) {
\r
6005 return matcher.test( value.label || value.value || value );
\r
6008 } else if ( typeof this.options.source === "string" ) {
\r
6009 url = this.options.source;
\r
6010 this.source = function( request, response ) {
\r
6011 $.getJSON( url, request, response );
\r
6014 this.source = this.options.source;
\r
6018 search: function( value, event ) {
\r
6019 value = value != null ? value : this.element.val();
\r
6020 if ( value.length < this.options.minLength ) {
\r
6021 return this.close( event );
\r
6024 clearTimeout( this.closing );
\r
6025 if ( this._trigger("search") === false ) {
\r
6029 return this._search( value );
\r
6032 _search: function( value ) {
\r
6033 this.term = this.element
\r
6034 .addClass( "ui-autocomplete-loading" )
\r
6035 // always save the actual value, not the one passed as an argument
\r
6038 this.source( { term: value }, this.response );
\r
6041 _response: function( content ) {
\r
6042 if ( content.length ) {
\r
6043 content = this._normalize( content );
\r
6044 this._suggest( content );
\r
6045 this._trigger( "open" );
\r
6049 this.element.removeClass( "ui-autocomplete-loading" );
\r
6052 close: function( event ) {
\r
6053 clearTimeout( this.closing );
\r
6054 if ( this.menu.element.is(":visible") ) {
\r
6055 this._trigger( "close", event );
\r
6056 this.menu.element.hide();
\r
6057 this.menu.deactivate();
\r
6059 if ( this.previous !== this.element.val() ) {
\r
6060 this._trigger( "change", event );
\r
6064 _normalize: function( items ) {
\r
6065 // assume all items have the right format when the first item is complete
\r
6066 if ( items.length && items[0].label && items[0].value ) {
\r
6069 return $.map( items, function(item) {
\r
6070 if ( typeof item === "string" ) {
\r
6077 label: item.label || item.value,
\r
6078 value: item.value || item.label
\r
6083 _suggest: function( items ) {
\r
6084 var ul = this.menu.element
\r
6086 .zIndex( this.element.zIndex() + 1 ),
\r
6089 this._renderMenu( ul, items );
\r
6090 // TODO refresh should check if the active item is still in the dom, removing the need for a manual deactivate
\r
6091 this.menu.deactivate();
\r
6092 this.menu.refresh();
\r
6093 this.menu.element.show().position({
\r
6095 at: "left bottom",
\r
6100 menuWidth = ul.width( "" ).width();
\r
6101 textWidth = this.element.width();
\r
6102 ul.width( Math.max( menuWidth, textWidth ) );
\r
6105 _renderMenu: function( ul, items ) {
\r
6107 $.each( items, function( index, item ) {
\r
6108 self._renderItem( ul, item );
\r
6112 _renderItem: function( ul, item) {
\r
6113 return $( "<li></li>" )
\r
6114 .data( "item.autocomplete", item )
\r
6115 .append( "<a>" + item.label + "</a>" )
\r
6119 _move: function( direction, event ) {
\r
6120 if ( !this.menu.element.is(":visible") ) {
\r
6121 this.search( null, event );
\r
6124 if ( this.menu.first() && /^previous/.test(direction) ||
\r
6125 this.menu.last() && /^next/.test(direction) ) {
\r
6126 this.element.val( this.term );
\r
6127 this.menu.deactivate();
\r
6130 this.menu[ direction ]();
\r
6133 widget: function() {
\r
6134 return this.menu.element;
\r
6138 $.extend( $.ui.autocomplete, {
\r
6139 escapeRegex: function( value ) {
\r
6140 return value.replace( /([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1" );
\r
6147 * jQuery UI Menu (not officially released)
\r
6149 * This widget isn't yet finished and the API is subject to change. We plan to finish
\r
6150 * it for the next release. You're welcome to give it a try anyway and give us feedback,
\r
6151 * as long as you're okay with migrating your code later on. We can help with that, too.
\r
6153 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
6154 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
6155 * and GPL (GPL-LICENSE.txt) licenses.
\r
6157 * http://docs.jquery.com/UI/Menu
\r
6160 * jquery.ui.core.js
\r
6161 * jquery.ui.widget.js
\r
6165 $.widget("ui.menu", {
\r
6166 _create: function() {
\r
6169 .addClass("ui-menu ui-widget ui-widget-content ui-corner-all")
\r
6172 "aria-activedescendant": "ui-active-menuitem"
\r
6174 .click(function(e) {
\r
6176 e.preventDefault();
\r
6182 refresh: function() {
\r
6185 // don't refresh list items that are already adapted
\r
6186 var items = this.element.children("li:not(.ui-menu-item):has(a)")
\r
6187 .addClass("ui-menu-item")
\r
6188 .attr("role", "menuitem");
\r
6190 items.children("a")
\r
6191 .addClass("ui-corner-all")
\r
6192 .attr("tabindex", -1)
\r
6193 // mouseenter doesn't work with event delegation
\r
6194 .mouseenter(function() {
\r
6195 self.activate($(this).parent());
\r
6197 .mouseleave(function() {
\r
6198 self.deactivate();
\r
6202 activate: function(item) {
\r
6203 this.deactivate();
\r
6204 if (this.hasScroll()) {
\r
6205 var offset = item.offset().top - this.element.offset().top,
\r
6206 scroll = this.element.attr("scrollTop"),
\r
6207 elementHeight = this.element.height();
\r
6209 this.element.attr("scrollTop", scroll + offset);
\r
6210 } else if (offset > elementHeight) {
\r
6211 this.element.attr("scrollTop", scroll + offset - elementHeight + item.height());
\r
6214 this.active = item.eq(0)
\r
6216 .addClass("ui-state-hover")
\r
6217 .attr("id", "ui-active-menuitem")
\r
6219 this._trigger("focus", null, { item: item });
\r
6222 deactivate: function() {
\r
6223 if (!this.active) { return; }
\r
6225 this.active.children("a")
\r
6226 .removeClass("ui-state-hover")
\r
6227 .removeAttr("id");
\r
6228 this._trigger("blur");
\r
6229 this.active = null;
\r
6232 next: function() {
\r
6233 this.move("next", "li:first");
\r
6236 previous: function() {
\r
6237 this.move("prev", "li:last");
\r
6240 first: function() {
\r
6241 return this.active && !this.active.prev().length;
\r
6244 last: function() {
\r
6245 return this.active && !this.active.next().length;
\r
6248 move: function(direction, edge) {
\r
6249 if (!this.active) {
\r
6250 this.activate(this.element.children(edge));
\r
6253 var next = this.active[direction]();
\r
6254 if (next.length) {
\r
6255 this.activate(next);
\r
6257 this.activate(this.element.children(edge));
\r
6261 // TODO merge with previousPage
\r
6262 nextPage: function() {
\r
6263 if (this.hasScroll()) {
\r
6264 // TODO merge with no-scroll-else
\r
6265 if (!this.active || this.last()) {
\r
6266 this.activate(this.element.children(":first"));
\r
6269 var base = this.active.offset().top,
\r
6270 height = this.element.height(),
\r
6271 result = this.element.children("li").filter(function() {
\r
6272 var close = $(this).offset().top - base - height + $(this).height();
\r
6273 // TODO improve approximation
\r
6274 return close < 10 && close > -10;
\r
6277 // TODO try to catch this earlier when scrollTop indicates the last page anyway
\r
6278 if (!result.length) {
\r
6279 result = this.element.children(":last");
\r
6281 this.activate(result);
\r
6283 this.activate(this.element.children(!this.active || this.last() ? ":first" : ":last"));
\r
6287 // TODO merge with nextPage
\r
6288 previousPage: function() {
\r
6289 if (this.hasScroll()) {
\r
6290 // TODO merge with no-scroll-else
\r
6291 if (!this.active || this.first()) {
\r
6292 this.activate(this.element.children(":last"));
\r
6296 var base = this.active.offset().top,
\r
6297 height = this.element.height();
\r
6298 result = this.element.children("li").filter(function() {
\r
6299 var close = $(this).offset().top - base + height - $(this).height();
\r
6300 // TODO improve approximation
\r
6301 return close < 10 && close > -10;
\r
6304 // TODO try to catch this earlier when scrollTop indicates the last page anyway
\r
6305 if (!result.length) {
\r
6306 result = this.element.children(":first");
\r
6308 this.activate(result);
\r
6310 this.activate(this.element.children(!this.active || this.first() ? ":last" : ":first"));
\r
6314 hasScroll: function() {
\r
6315 return this.element.height() < this.element.attr("scrollHeight");
\r
6318 select: function() {
\r
6319 this._trigger("selected", null, { item: this.active });
\r
6325 * jQuery UI Button 1.8
\r
6327 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
6328 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
6329 * and GPL (GPL-LICENSE.txt) licenses.
\r
6331 * http://docs.jquery.com/UI/Button
\r
6334 * jquery.ui.core.js
\r
6335 * jquery.ui.widget.js
\r
6340 baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
\r
6341 otherClasses = "ui-state-hover ui-state-active " +
\r
6342 "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon ui-button-text-only",
\r
6343 formResetHandler = function( event ) {
\r
6344 $( ":ui-button", event.target.form ).each(function() {
\r
6345 var inst = $( this ).data( "button" );
\r
6346 setTimeout(function() {
\r
6351 radioGroup = function( radio ) {
\r
6352 var name = radio.name,
\r
6353 form = radio.form,
\r
6357 radios = $( form ).find( "[name='" + name + "']" );
\r
6359 radios = $( "[name='" + name + "']", radio.ownerDocument )
\r
6360 .filter(function() {
\r
6361 return !this.form;
\r
6368 $.widget( "ui.button", {
\r
6377 _create: function() {
\r
6378 this.element.closest( "form" )
\r
6379 .unbind( "reset.button" )
\r
6380 .bind( "reset.button", formResetHandler );
\r
6382 this._determineButtonType();
\r
6383 this.hasTitle = !!this.buttonElement.attr( "title" );
\r
6386 options = this.options,
\r
6387 toggleButton = this.type === "checkbox" || this.type === "radio",
\r
6388 hoverClass = "ui-state-hover" + ( !toggleButton ? " ui-state-active" : "" ),
\r
6389 focusClass = "ui-state-focus";
\r
6391 if ( options.label === null ) {
\r
6392 options.label = this.buttonElement.html();
\r
6395 if ( this.element.is( ":disabled" ) ) {
\r
6396 options.disabled = true;
\r
6399 this.buttonElement
\r
6400 .addClass( baseClasses )
\r
6401 .attr( "role", "button" )
\r
6402 .bind( "mouseenter.button", function() {
\r
6403 if ( options.disabled ) {
\r
6406 $( this ).addClass( "ui-state-hover" );
\r
6407 if ( this === lastActive ) {
\r
6408 $( this ).addClass( "ui-state-active" );
\r
6411 .bind( "mouseleave.button", function() {
\r
6412 if ( options.disabled ) {
\r
6415 $( this ).removeClass( hoverClass );
\r
6417 .bind( "focus.button", function() {
\r
6418 // no need to check disabled, focus won't be triggered anyway
\r
6419 $( this ).addClass( focusClass );
\r
6421 .bind( "blur.button", function() {
\r
6422 $( this ).removeClass( focusClass );
\r
6425 if ( toggleButton ) {
\r
6426 this.element.bind( "change.button", function() {
\r
6431 if ( this.type === "checkbox" ) {
\r
6432 this.buttonElement.bind( "click.button", function() {
\r
6433 if ( options.disabled ) {
\r
6436 $( this ).toggleClass( "ui-state-active" );
\r
6437 self.buttonElement.attr( "aria-pressed", self.element[0].checked );
\r
6439 } else if ( this.type === "radio" ) {
\r
6440 this.buttonElement.bind( "click.button", function() {
\r
6441 if ( options.disabled ) {
\r
6444 $( this ).addClass( "ui-state-active" );
\r
6445 self.buttonElement.attr( "aria-pressed", true );
\r
6447 var radio = self.element[ 0 ];
\r
6448 radioGroup( radio )
\r
6451 return $( this ).button( "widget" )[ 0 ];
\r
6453 .removeClass( "ui-state-active" )
\r
6454 .attr( "aria-pressed", false );
\r
6457 this.buttonElement
\r
6458 .bind( "mousedown.button", function() {
\r
6459 if ( options.disabled ) {
\r
6462 $( this ).addClass( "ui-state-active" );
\r
6463 lastActive = this;
\r
6464 $( document ).one( "mouseup", function() {
\r
6465 lastActive = null;
\r
6468 .bind( "mouseup.button", function() {
\r
6469 if ( options.disabled ) {
\r
6472 $( this ).removeClass( "ui-state-active" );
\r
6474 .bind( "keydown.button", function(event) {
\r
6475 if ( options.disabled ) {
\r
6478 if ( event.keyCode == $.ui.keyCode.SPACE || event.keyCode == $.ui.keyCode.ENTER ) {
\r
6479 $( this ).addClass( "ui-state-active" );
\r
6482 .bind( "keyup.button", function() {
\r
6483 $( this ).removeClass( "ui-state-active" );
\r
6486 if ( this.buttonElement.is("a") ) {
\r
6487 this.buttonElement.keyup(function(event) {
\r
6488 if ( event.keyCode === $.ui.keyCode.SPACE ) {
\r
6489 // TODO pass through original event correctly (just as 2nd argument doesn't work)
\r
6490 $( this ).click();
\r
6496 // TODO: pull out $.Widget's handling for the disabled option into
\r
6497 // $.Widget.prototype._setOptionDisabled so it's easy to proxy and can
\r
6498 // be overridden by individual plugins
\r
6499 this._setOption( "disabled", options.disabled );
\r
6502 _determineButtonType: function() {
\r
6504 if ( this.element.is(":checkbox") ) {
\r
6505 this.type = "checkbox";
\r
6507 if ( this.element.is(":radio") ) {
\r
6508 this.type = "radio";
\r
6510 if ( this.element.is("input") ) {
\r
6511 this.type = "input";
\r
6513 this.type = "button";
\r
6518 if ( this.type === "checkbox" || this.type === "radio" ) {
\r
6519 // we don't search against the document in case the element
\r
6520 // is disconnected from the DOM
\r
6521 this.buttonElement = this.element.parents().last()
\r
6522 .find( "[for=" + this.element.attr("id") + "]" );
\r
6523 this.element.addClass( "ui-helper-hidden-accessible" );
\r
6525 var checked = this.element.is( ":checked" );
\r
6527 this.buttonElement.addClass( "ui-state-active" );
\r
6529 this.buttonElement.attr( "aria-pressed", checked );
\r
6531 this.buttonElement = this.element;
\r
6535 widget: function() {
\r
6536 return this.buttonElement;
\r
6539 destroy: function() {
\r
6541 .removeClass( "ui-helper-hidden-accessible" );
\r
6542 this.buttonElement
\r
6543 .removeClass( baseClasses + " " + otherClasses )
\r
6544 .removeAttr( "role" )
\r
6545 .removeAttr( "aria-pressed" )
\r
6546 .html( this.buttonElement.find(".ui-button-text").html() );
\r
6548 if ( !this.hasTitle ) {
\r
6549 this.buttonElement.removeAttr( "title" );
\r
6552 $.Widget.prototype.destroy.call( this );
\r
6555 _setOption: function( key, value ) {
\r
6556 $.Widget.prototype._setOption.apply( this, arguments );
\r
6557 if ( key === "disabled" ) {
\r
6559 this.element.attr( "disabled", true );
\r
6561 this.element.removeAttr( "disabled" );
\r
6564 this._resetButton();
\r
6567 refresh: function() {
\r
6568 var isDisabled = this.element.is( ":disabled" );
\r
6569 if ( isDisabled !== this.options.disabled ) {
\r
6570 this._setOption( "disabled", isDisabled );
\r
6572 if ( this.type === "radio" ) {
\r
6573 radioGroup( this.element[0] ).each(function() {
\r
6574 if ( $( this ).is( ":checked" ) ) {
\r
6575 $( this ).button( "widget" )
\r
6576 .addClass( "ui-state-active" )
\r
6577 .attr( "aria-pressed", true );
\r
6579 $( this ).button( "widget" )
\r
6580 .removeClass( "ui-state-active" )
\r
6581 .attr( "aria-pressed", false );
\r
6584 } else if ( this.type === "checkbox" ) {
\r
6585 if ( this.element.is( ":checked" ) ) {
\r
6586 this.buttonElement
\r
6587 .addClass( "ui-state-active" )
\r
6588 .attr( "aria-pressed", true );
\r
6590 this.buttonElement
\r
6591 .removeClass( "ui-state-active" )
\r
6592 .attr( "aria-pressed", false );
\r
6597 _resetButton: function() {
\r
6598 if ( this.type === "input" ) {
\r
6599 if ( this.options.label ) {
\r
6600 this.element.val( this.options.label );
\r
6604 var buttonElement = this.buttonElement,
\r
6605 buttonText = $( "<span></span>" )
\r
6606 .addClass( "ui-button-text" )
\r
6607 .html( this.options.label )
\r
6608 .appendTo( buttonElement.empty() )
\r
6610 icons = this.options.icons,
\r
6611 multipleIcons = icons.primary && icons.secondary;
\r
6612 if ( icons.primary || icons.secondary ) {
\r
6613 buttonElement.addClass( "ui-button-text-icon" +
\r
6614 ( multipleIcons ? "s" : "" ) );
\r
6615 if ( icons.primary ) {
\r
6616 buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
\r
6618 if ( icons.secondary ) {
\r
6619 buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
\r
6621 if ( !this.options.text ) {
\r
6623 .addClass( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" )
\r
6624 .removeClass( "ui-button-text-icons ui-button-text-icon" );
\r
6625 if ( !this.hasTitle ) {
\r
6626 buttonElement.attr( "title", buttonText );
\r
6630 buttonElement.addClass( "ui-button-text-only" );
\r
6635 $.widget( "ui.buttonset", {
\r
6636 _create: function() {
\r
6637 this.element.addClass( "ui-buttonset" );
\r
6641 _init: function() {
\r
6645 _setOption: function( key, value ) {
\r
6646 if ( key === "disabled" ) {
\r
6647 this.buttons.button( "option", key, value );
\r
6650 $.Widget.prototype._setOption.apply( this, arguments );
\r
6653 refresh: function() {
\r
6654 this.buttons = this.element.find( ":button, :submit, :reset, :checkbox, :radio, a, :data(button)" )
\r
6655 .filter( ":ui-button" )
\r
6656 .button( "refresh" )
\r
6658 .not( ":ui-button" )
\r
6662 return $( this ).button( "widget" )[ 0 ];
\r
6664 .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
\r
6665 .filter( ":first" )
\r
6666 .addClass( "ui-corner-left" )
\r
6668 .filter( ":last" )
\r
6669 .addClass( "ui-corner-right" )
\r
6674 destroy: function() {
\r
6675 this.element.removeClass( "ui-buttonset" );
\r
6678 return $( this ).button( "widget" )[ 0 ];
\r
6680 .removeClass( "ui-corner-left ui-corner-right" )
\r
6682 .button( "destroy" )
\r
6684 $.Widget.prototype.destroy.call( this );
\r
6690 * jQuery UI Datepicker 1.8
\r
6692 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
6693 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
6694 * and GPL (GPL-LICENSE.txt) licenses.
\r
6696 * http://docs.jquery.com/UI/Datepicker
\r
6699 * jquery.ui.core.js
\r
6702 (function($) { // hide the namespace
\r
6704 $.extend($.ui, { datepicker: { version: "1.8" } });
\r
6706 var PROP_NAME = 'datepicker';
\r
6707 var dpuuid = new Date().getTime();
\r
6709 /* Date picker manager.
\r
6710 Use the singleton instance of this class, $.datepicker, to interact with the date picker.
\r
6711 Settings for (groups of) date pickers are maintained in an instance object,
\r
6712 allowing multiple different settings on the same page. */
\r
6714 function Datepicker() {
\r
6715 this.debug = false; // Change this to true to start debugging
\r
6716 this._curInst = null; // The current instance in use
\r
6717 this._keyEvent = false; // If the last event was a key event
\r
6718 this._disabledInputs = []; // List of date picker inputs that have been disabled
\r
6719 this._datepickerShowing = false; // True if the popup picker is showing , false if not
\r
6720 this._inDialog = false; // True if showing within a "dialog", false if not
\r
6721 this._mainDivId = 'ui-datepicker-div'; // The ID of the main datepicker division
\r
6722 this._inlineClass = 'ui-datepicker-inline'; // The name of the inline marker class
\r
6723 this._appendClass = 'ui-datepicker-append'; // The name of the append marker class
\r
6724 this._triggerClass = 'ui-datepicker-trigger'; // The name of the trigger marker class
\r
6725 this._dialogClass = 'ui-datepicker-dialog'; // The name of the dialog marker class
\r
6726 this._disableClass = 'ui-datepicker-disabled'; // The name of the disabled covering marker class
\r
6727 this._unselectableClass = 'ui-datepicker-unselectable'; // The name of the unselectable cell marker class
\r
6728 this._currentClass = 'ui-datepicker-current-day'; // The name of the current day marker class
\r
6729 this._dayOverClass = 'ui-datepicker-days-cell-over'; // The name of the day hover marker class
\r
6730 this.regional = []; // Available regional settings, indexed by language code
\r
6731 this.regional[''] = { // Default regional settings
\r
6732 closeText: 'Done', // Display text for close link
\r
6733 prevText: 'Prev', // Display text for previous month link
\r
6734 nextText: 'Next', // Display text for next month link
\r
6735 currentText: 'Today', // Display text for current month link
\r
6736 monthNames: ['January','February','March','April','May','June',
\r
6737 'July','August','September','October','November','December'], // Names of months for drop-down and formatting
\r
6738 monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting
\r
6739 dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting
\r
6740 dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting
\r
6741 dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday
\r
6742 weekHeader: 'Wk', // Column header for week of the year
\r
6743 dateFormat: 'mm/dd/yy', // See format options on parseDate
\r
6744 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
\r
6745 isRTL: false, // True if right-to-left language, false if left-to-right
\r
6746 showMonthAfterYear: false, // True if the year select precedes month, false for month then year
\r
6747 yearSuffix: '' // Additional text to append to the year in the month headers
\r
6749 this._defaults = { // Global defaults for all the date picker instances
\r
6750 showOn: 'focus', // 'focus' for popup on focus,
\r
6751 // 'button' for trigger button, or 'both' for either
\r
6752 showAnim: 'show', // Name of jQuery animation for popup
\r
6753 showOptions: {}, // Options for enhanced animations
\r
6754 defaultDate: null, // Used when field is blank: actual date,
\r
6755 // +/-number for offset from today, null for today
\r
6756 appendText: '', // Display text following the input box, e.g. showing the format
\r
6757 buttonText: '...', // Text for trigger button
\r
6758 buttonImage: '', // URL for trigger button image
\r
6759 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
\r
6760 hideIfNoPrevNext: false, // True to hide next/previous month links
\r
6761 // if not applicable, false to just disable them
\r
6762 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
\r
6763 gotoCurrent: false, // True if today link goes back to current selection instead
\r
6764 changeMonth: false, // True if month can be selected directly, false if only prev/next
\r
6765 changeYear: false, // True if year can be selected directly, false if only prev/next
\r
6766 yearRange: 'c-10:c+10', // Range of years to display in drop-down,
\r
6767 // either relative to today's year (-nn:+nn), relative to currently displayed year
\r
6768 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
\r
6769 showOtherMonths: false, // True to show dates in other months, false to leave blank
\r
6770 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
\r
6771 showWeek: false, // True to show week of the year, false to not show it
\r
6772 calculateWeek: this.iso8601Week, // How to calculate the week of the year,
\r
6773 // takes a Date and returns the number of the week for it
\r
6774 shortYearCutoff: '+10', // Short year values < this are in the current century,
\r
6775 // > this are in the previous century,
\r
6776 // string value starting with '+' for current year + value
\r
6777 minDate: null, // The earliest selectable date, or null for no limit
\r
6778 maxDate: null, // The latest selectable date, or null for no limit
\r
6779 duration: '_default', // Duration of display/closure
\r
6780 beforeShowDay: null, // Function that takes a date and returns an array with
\r
6781 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '',
\r
6782 // [2] = cell title (optional), e.g. $.datepicker.noWeekends
\r
6783 beforeShow: null, // Function that takes an input field and
\r
6784 // returns a set of custom settings for the date picker
\r
6785 onSelect: null, // Define a callback function when a date is selected
\r
6786 onChangeMonthYear: null, // Define a callback function when the month or year is changed
\r
6787 onClose: null, // Define a callback function when the datepicker is closed
\r
6788 numberOfMonths: 1, // Number of months to show at a time
\r
6789 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
\r
6790 stepMonths: 1, // Number of months to step back/forward
\r
6791 stepBigMonths: 12, // Number of months to step back/forward for the big links
\r
6792 altField: '', // Selector for an alternate field to store selected dates into
\r
6793 altFormat: '', // The date format to use for the alternate field
\r
6794 constrainInput: true, // The input is constrained by the current date format
\r
6795 showButtonPanel: false, // True to show button panel, false to not show it
\r
6796 autoSize: false // True to size the input for the date format, false to leave as is
\r
6798 $.extend(this._defaults, this.regional['']);
\r
6799 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>');
\r
6802 $.extend(Datepicker.prototype, {
\r
6803 /* Class name added to elements to indicate already configured with a date picker. */
\r
6804 markerClassName: 'hasDatepicker',
\r
6806 /* Debug logging (if enabled). */
\r
6807 log: function () {
\r
6809 console.log.apply('', arguments);
\r
6812 // TODO rename to "widget" when switching to widget factory
\r
6813 _widgetDatepicker: function() {
\r
6814 return this.dpDiv;
\r
6817 /* Override the default settings for all instances of the date picker.
\r
6818 @param settings object - the new settings to use as defaults (anonymous object)
\r
6819 @return the manager object */
\r
6820 setDefaults: function(settings) {
\r
6821 extendRemove(this._defaults, settings || {});
\r
6825 /* Attach the date picker to a jQuery selection.
\r
6826 @param target element - the target input field or division or span
\r
6827 @param settings object - the new settings to use for this date picker instance (anonymous) */
\r
6828 _attachDatepicker: function(target, settings) {
\r
6829 // check for settings on the control itself - in namespace 'date:'
\r
6830 var inlineSettings = null;
\r
6831 for (var attrName in this._defaults) {
\r
6832 var attrValue = target.getAttribute('date:' + attrName);
\r
6834 inlineSettings = inlineSettings || {};
\r
6836 inlineSettings[attrName] = eval(attrValue);
\r
6838 inlineSettings[attrName] = attrValue;
\r
6842 var nodeName = target.nodeName.toLowerCase();
\r
6843 var inline = (nodeName == 'div' || nodeName == 'span');
\r
6845 target.id = 'dp' + (++this.uuid);
\r
6846 var inst = this._newInst($(target), inline);
\r
6847 inst.settings = $.extend({}, settings || {}, inlineSettings || {});
\r
6848 if (nodeName == 'input') {
\r
6849 this._connectDatepicker(target, inst);
\r
6850 } else if (inline) {
\r
6851 this._inlineDatepicker(target, inst);
\r
6855 /* Create a new instance object. */
\r
6856 _newInst: function(target, inline) {
\r
6857 var id = target[0].id.replace(/([^A-Za-z0-9_])/g, '\\\\$1'); // escape jQuery meta chars
\r
6858 return {id: id, input: target, // associated target
\r
6859 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
\r
6860 drawMonth: 0, drawYear: 0, // month being drawn
\r
6861 inline: inline, // is datepicker inline or not
\r
6862 dpDiv: (!inline ? this.dpDiv : // presentation div
\r
6863 $('<div class="' + this._inlineClass + ' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))};
\r
6866 /* Attach the date picker to an input field. */
\r
6867 _connectDatepicker: function(target, inst) {
\r
6868 var input = $(target);
\r
6869 inst.append = $([]);
\r
6870 inst.trigger = $([]);
\r
6871 if (input.hasClass(this.markerClassName))
\r
6873 this._attachments(input, inst);
\r
6874 input.addClass(this.markerClassName).keydown(this._doKeyDown).
\r
6875 keypress(this._doKeyPress).keyup(this._doKeyUp).
\r
6876 bind("setData.datepicker", function(event, key, value) {
\r
6877 inst.settings[key] = value;
\r
6878 }).bind("getData.datepicker", function(event, key) {
\r
6879 return this._get(inst, key);
\r
6881 this._autoSize(inst);
\r
6882 $.data(target, PROP_NAME, inst);
\r
6885 /* Make attachments based on settings. */
\r
6886 _attachments: function(input, inst) {
\r
6887 var appendText = this._get(inst, 'appendText');
\r
6888 var isRTL = this._get(inst, 'isRTL');
\r
6890 inst.append.remove();
\r
6892 inst.append = $('<span class="' + this._appendClass + '">' + appendText + '</span>');
\r
6893 input[isRTL ? 'before' : 'after'](inst.append);
\r
6895 input.unbind('focus', this._showDatepicker);
\r
6897 inst.trigger.remove();
\r
6898 var showOn = this._get(inst, 'showOn');
\r
6899 if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field
\r
6900 input.focus(this._showDatepicker);
\r
6901 if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked
\r
6902 var buttonText = this._get(inst, 'buttonText');
\r
6903 var buttonImage = this._get(inst, 'buttonImage');
\r
6904 inst.trigger = $(this._get(inst, 'buttonImageOnly') ?
\r
6905 $('<img/>').addClass(this._triggerClass).
\r
6906 attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
\r
6907 $('<button type="button"></button>').addClass(this._triggerClass).
\r
6908 html(buttonImage == '' ? buttonText : $('<img/>').attr(
\r
6909 { src:buttonImage, alt:buttonText, title:buttonText })));
\r
6910 input[isRTL ? 'before' : 'after'](inst.trigger);
\r
6911 inst.trigger.click(function() {
\r
6912 if ($.datepicker._datepickerShowing && $.datepicker._lastInput == input[0])
\r
6913 $.datepicker._hideDatepicker();
\r
6915 $.datepicker._showDatepicker(input[0]);
\r
6921 /* Apply the maximum length for the date format. */
\r
6922 _autoSize: function(inst) {
\r
6923 if (this._get(inst, 'autoSize') && !inst.inline) {
\r
6924 var date = new Date(2009, 12 - 1, 20); // Ensure double digits
\r
6925 var dateFormat = this._get(inst, 'dateFormat');
\r
6926 if (dateFormat.match(/[DM]/)) {
\r
6927 var findMax = function(names) {
\r
6930 for (var i = 0; i < names.length; i++) {
\r
6931 if (names[i].length > max) {
\r
6932 max = names[i].length;
\r
6938 date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
\r
6939 'monthNames' : 'monthNamesShort'))));
\r
6940 date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
\r
6941 'dayNames' : 'dayNamesShort'))) + 20 - date.getDay());
\r
6943 inst.input.attr('size', this._formatDate(inst, date).length);
\r
6947 /* Attach an inline date picker to a div. */
\r
6948 _inlineDatepicker: function(target, inst) {
\r
6949 var divSpan = $(target);
\r
6950 if (divSpan.hasClass(this.markerClassName))
\r
6952 divSpan.addClass(this.markerClassName).append(inst.dpDiv).
\r
6953 bind("setData.datepicker", function(event, key, value){
\r
6954 inst.settings[key] = value;
\r
6955 }).bind("getData.datepicker", function(event, key){
\r
6956 return this._get(inst, key);
\r
6958 $.data(target, PROP_NAME, inst);
\r
6959 this._setDate(inst, this._getDefaultDate(inst), true);
\r
6960 this._updateDatepicker(inst);
\r
6961 this._updateAlternate(inst);
\r
6964 /* Pop-up the date picker in a "dialog" box.
\r
6965 @param input element - ignored
\r
6966 @param date string or Date - the initial date to display
\r
6967 @param onSelect function - the function to call when a date is selected
\r
6968 @param settings object - update the dialog date picker instance's settings (anonymous object)
\r
6969 @param pos int[2] - coordinates for the dialog's position within the screen or
\r
6970 event - with x/y coordinates or
\r
6971 leave empty for default (screen centre)
\r
6972 @return the manager object */
\r
6973 _dialogDatepicker: function(input, date, onSelect, settings, pos) {
\r
6974 var inst = this._dialogInst; // internal instance
\r
6976 var id = 'dp' + (++this.uuid);
\r
6977 this._dialogInput = $('<input type="text" id="' + id +
\r
6978 '" style="position: absolute; top: -100px; width: 0px; z-index: -10;"/>');
\r
6979 this._dialogInput.keydown(this._doKeyDown);
\r
6980 $('body').append(this._dialogInput);
\r
6981 inst = this._dialogInst = this._newInst(this._dialogInput, false);
\r
6982 inst.settings = {};
\r
6983 $.data(this._dialogInput[0], PROP_NAME, inst);
\r
6985 extendRemove(inst.settings, settings || {});
\r
6986 date = (date && date.constructor == Date ? this._formatDate(inst, date) : date);
\r
6987 this._dialogInput.val(date);
\r
6989 this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
\r
6991 var browserWidth = document.documentElement.clientWidth;
\r
6992 var browserHeight = document.documentElement.clientHeight;
\r
6993 var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
\r
6994 var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
\r
6995 this._pos = // should use actual width/height below
\r
6996 [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
\r
6999 // move input on screen for focus, but hidden behind dialog
\r
7000 this._dialogInput.css('left', (this._pos[0] + 20) + 'px').css('top', this._pos[1] + 'px');
\r
7001 inst.settings.onSelect = onSelect;
\r
7002 this._inDialog = true;
\r
7003 this.dpDiv.addClass(this._dialogClass);
\r
7004 this._showDatepicker(this._dialogInput[0]);
\r
7006 $.blockUI(this.dpDiv);
\r
7007 $.data(this._dialogInput[0], PROP_NAME, inst);
\r
7011 /* Detach a datepicker from its control.
\r
7012 @param target element - the target input field or division or span */
\r
7013 _destroyDatepicker: function(target) {
\r
7014 var $target = $(target);
\r
7015 var inst = $.data(target, PROP_NAME);
\r
7016 if (!$target.hasClass(this.markerClassName)) {
\r
7019 var nodeName = target.nodeName.toLowerCase();
\r
7020 $.removeData(target, PROP_NAME);
\r
7021 if (nodeName == 'input') {
\r
7022 inst.append.remove();
\r
7023 inst.trigger.remove();
\r
7024 $target.removeClass(this.markerClassName).
\r
7025 unbind('focus', this._showDatepicker).
\r
7026 unbind('keydown', this._doKeyDown).
\r
7027 unbind('keypress', this._doKeyPress).
\r
7028 unbind('keyup', this._doKeyUp);
\r
7029 } else if (nodeName == 'div' || nodeName == 'span')
\r
7030 $target.removeClass(this.markerClassName).empty();
\r
7033 /* Enable the date picker to a jQuery selection.
\r
7034 @param target element - the target input field or division or span */
\r
7035 _enableDatepicker: function(target) {
\r
7036 var $target = $(target);
\r
7037 var inst = $.data(target, PROP_NAME);
\r
7038 if (!$target.hasClass(this.markerClassName)) {
\r
7041 var nodeName = target.nodeName.toLowerCase();
\r
7042 if (nodeName == 'input') {
\r
7043 target.disabled = false;
\r
7044 inst.trigger.filter('button').
\r
7045 each(function() { this.disabled = false; }).end().
\r
7046 filter('img').css({opacity: '1.0', cursor: ''});
\r
7048 else if (nodeName == 'div' || nodeName == 'span') {
\r
7049 var inline = $target.children('.' + this._inlineClass);
\r
7050 inline.children().removeClass('ui-state-disabled');
\r
7052 this._disabledInputs = $.map(this._disabledInputs,
\r
7053 function(value) { return (value == target ? null : value); }); // delete entry
\r
7056 /* Disable the date picker to a jQuery selection.
\r
7057 @param target element - the target input field or division or span */
\r
7058 _disableDatepicker: function(target) {
\r
7059 var $target = $(target);
\r
7060 var inst = $.data(target, PROP_NAME);
\r
7061 if (!$target.hasClass(this.markerClassName)) {
\r
7064 var nodeName = target.nodeName.toLowerCase();
\r
7065 if (nodeName == 'input') {
\r
7066 target.disabled = true;
\r
7067 inst.trigger.filter('button').
\r
7068 each(function() { this.disabled = true; }).end().
\r
7069 filter('img').css({opacity: '0.5', cursor: 'default'});
\r
7071 else if (nodeName == 'div' || nodeName == 'span') {
\r
7072 var inline = $target.children('.' + this._inlineClass);
\r
7073 inline.children().addClass('ui-state-disabled');
\r
7075 this._disabledInputs = $.map(this._disabledInputs,
\r
7076 function(value) { return (value == target ? null : value); }); // delete entry
\r
7077 this._disabledInputs[this._disabledInputs.length] = target;
\r
7080 /* Is the first field in a jQuery collection disabled as a datepicker?
\r
7081 @param target element - the target input field or division or span
\r
7082 @return boolean - true if disabled, false if enabled */
\r
7083 _isDisabledDatepicker: function(target) {
\r
7087 for (var i = 0; i < this._disabledInputs.length; i++) {
\r
7088 if (this._disabledInputs[i] == target)
\r
7094 /* Retrieve the instance data for the target control.
\r
7095 @param target element - the target input field or division or span
\r
7096 @return object - the associated instance data
\r
7097 @throws error if a jQuery problem getting data */
\r
7098 _getInst: function(target) {
\r
7100 return $.data(target, PROP_NAME);
\r
7103 throw 'Missing instance data for this datepicker';
\r
7107 /* Update or retrieve the settings for a date picker attached to an input field or division.
\r
7108 @param target element - the target input field or division or span
\r
7109 @param name object - the new settings to update or
\r
7110 string - the name of the setting to change or retrieve,
\r
7111 when retrieving also 'all' for all instance settings or
\r
7112 'defaults' for all global defaults
\r
7113 @param value any - the new value for the setting
\r
7114 (omit if above is an object or to retrieve a value) */
\r
7115 _optionDatepicker: function(target, name, value) {
\r
7116 var inst = this._getInst(target);
\r
7117 if (arguments.length == 2 && typeof name == 'string') {
\r
7118 return (name == 'defaults' ? $.extend({}, $.datepicker._defaults) :
\r
7119 (inst ? (name == 'all' ? $.extend({}, inst.settings) :
\r
7120 this._get(inst, name)) : null));
\r
7122 var settings = name || {};
\r
7123 if (typeof name == 'string') {
\r
7125 settings[name] = value;
\r
7128 if (this._curInst == inst) {
\r
7129 this._hideDatepicker();
\r
7131 var date = this._getDateDatepicker(target, true);
\r
7132 extendRemove(inst.settings, settings);
\r
7133 this._attachments($(target), inst);
\r
7134 this._autoSize(inst);
\r
7135 this._setDateDatepicker(target, date);
\r
7136 this._updateDatepicker(inst);
\r
7140 // change method deprecated
\r
7141 _changeDatepicker: function(target, name, value) {
\r
7142 this._optionDatepicker(target, name, value);
\r
7145 /* Redraw the date picker attached to an input field or division.
\r
7146 @param target element - the target input field or division or span */
\r
7147 _refreshDatepicker: function(target) {
\r
7148 var inst = this._getInst(target);
\r
7150 this._updateDatepicker(inst);
\r
7154 /* Set the dates for a jQuery selection.
\r
7155 @param target element - the target input field or division or span
\r
7156 @param date Date - the new date */
\r
7157 _setDateDatepicker: function(target, date) {
\r
7158 var inst = this._getInst(target);
\r
7160 this._setDate(inst, date);
\r
7161 this._updateDatepicker(inst);
\r
7162 this._updateAlternate(inst);
\r
7166 /* Get the date(s) for the first entry in a jQuery selection.
\r
7167 @param target element - the target input field or division or span
\r
7168 @param noDefault boolean - true if no default date is to be used
\r
7169 @return Date - the current date */
\r
7170 _getDateDatepicker: function(target, noDefault) {
\r
7171 var inst = this._getInst(target);
\r
7172 if (inst && !inst.inline)
\r
7173 this._setDateFromField(inst, noDefault);
\r
7174 return (inst ? this._getDate(inst) : null);
\r
7177 /* Handle keystrokes. */
\r
7178 _doKeyDown: function(event) {
\r
7179 var inst = $.datepicker._getInst(event.target);
\r
7180 var handled = true;
\r
7181 var isRTL = inst.dpDiv.is('.ui-datepicker-rtl');
\r
7182 inst._keyEvent = true;
\r
7183 if ($.datepicker._datepickerShowing)
\r
7184 switch (event.keyCode) {
\r
7185 case 9: $.datepicker._hideDatepicker();
\r
7187 break; // hide on tab out
\r
7188 case 13: var sel = $('td.' + $.datepicker._dayOverClass, inst.dpDiv).
\r
7189 add($('td.' + $.datepicker._currentClass, inst.dpDiv));
\r
7191 $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
\r
7193 $.datepicker._hideDatepicker();
\r
7194 return false; // don't submit the form
\r
7195 break; // select the value on enter
\r
7196 case 27: $.datepicker._hideDatepicker();
\r
7197 break; // hide on escape
\r
7198 case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
\r
7199 -$.datepicker._get(inst, 'stepBigMonths') :
\r
7200 -$.datepicker._get(inst, 'stepMonths')), 'M');
\r
7201 break; // previous month/year on page up/+ ctrl
\r
7202 case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
\r
7203 +$.datepicker._get(inst, 'stepBigMonths') :
\r
7204 +$.datepicker._get(inst, 'stepMonths')), 'M');
\r
7205 break; // next month/year on page down/+ ctrl
\r
7206 case 35: if (event.ctrlKey || event.metaKey) $.datepicker._clearDate(event.target);
\r
7207 handled = event.ctrlKey || event.metaKey;
\r
7208 break; // clear on ctrl or command +end
\r
7209 case 36: if (event.ctrlKey || event.metaKey) $.datepicker._gotoToday(event.target);
\r
7210 handled = event.ctrlKey || event.metaKey;
\r
7211 break; // current on ctrl or command +home
\r
7212 case 37: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), 'D');
\r
7213 handled = event.ctrlKey || event.metaKey;
\r
7214 // -1 day on ctrl or command +left
\r
7215 if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ?
\r
7216 -$.datepicker._get(inst, 'stepBigMonths') :
\r
7217 -$.datepicker._get(inst, 'stepMonths')), 'M');
\r
7218 // next month/year on alt +left on Mac
\r
7220 case 38: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, -7, 'D');
\r
7221 handled = event.ctrlKey || event.metaKey;
\r
7222 break; // -1 week on ctrl or command +up
\r
7223 case 39: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), 'D');
\r
7224 handled = event.ctrlKey || event.metaKey;
\r
7225 // +1 day on ctrl or command +right
\r
7226 if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ?
\r
7227 +$.datepicker._get(inst, 'stepBigMonths') :
\r
7228 +$.datepicker._get(inst, 'stepMonths')), 'M');
\r
7229 // next month/year on alt +right
\r
7231 case 40: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, +7, 'D');
\r
7232 handled = event.ctrlKey || event.metaKey;
\r
7233 break; // +1 week on ctrl or command +down
\r
7234 default: handled = false;
\r
7236 else if (event.keyCode == 36 && event.ctrlKey) // display the date picker on ctrl+home
\r
7237 $.datepicker._showDatepicker(this);
\r
7242 event.preventDefault();
\r
7243 event.stopPropagation();
\r
7247 /* Filter entered characters - based on date format. */
\r
7248 _doKeyPress: function(event) {
\r
7249 var inst = $.datepicker._getInst(event.target);
\r
7250 if ($.datepicker._get(inst, 'constrainInput')) {
\r
7251 var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat'));
\r
7252 var chr = String.fromCharCode(event.charCode == undefined ? event.keyCode : event.charCode);
\r
7253 return event.ctrlKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1);
\r
7257 /* Synchronise manual entry and field/alternate field. */
\r
7258 _doKeyUp: function(event) {
\r
7259 var inst = $.datepicker._getInst(event.target);
\r
7260 if (inst.input.val() != inst.lastVal) {
\r
7262 var date = $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'),
\r
7263 (inst.input ? inst.input.val() : null),
\r
7264 $.datepicker._getFormatConfig(inst));
\r
7265 if (date) { // only if valid
\r
7266 $.datepicker._setDateFromField(inst);
\r
7267 $.datepicker._updateAlternate(inst);
\r
7268 $.datepicker._updateDatepicker(inst);
\r
7272 $.datepicker.log(event);
\r
7278 /* Pop-up the date picker for a given input field.
\r
7279 @param input element - the input field attached to the date picker or
\r
7280 event - if triggered by focus */
\r
7281 _showDatepicker: function(input) {
\r
7282 input = input.target || input;
\r
7283 if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger
\r
7284 input = $('input', input.parentNode)[0];
\r
7285 if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here
\r
7287 var inst = $.datepicker._getInst(input);
\r
7288 if ($.datepicker._curInst && $.datepicker._curInst != inst) {
\r
7289 $.datepicker._curInst.dpDiv.stop(true, true);
\r
7291 var beforeShow = $.datepicker._get(inst, 'beforeShow');
\r
7292 extendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {}));
\r
7293 inst.lastVal = null;
\r
7294 $.datepicker._lastInput = input;
\r
7295 $.datepicker._setDateFromField(inst);
\r
7296 if ($.datepicker._inDialog) // hide cursor
\r
7298 if (!$.datepicker._pos) { // position below input
\r
7299 $.datepicker._pos = $.datepicker._findPos(input);
\r
7300 $.datepicker._pos[1] += input.offsetHeight; // add the height
\r
7302 var isFixed = false;
\r
7303 $(input).parents().each(function() {
\r
7304 isFixed |= $(this).css('position') == 'fixed';
\r
7307 if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled
\r
7308 $.datepicker._pos[0] -= document.documentElement.scrollLeft;
\r
7309 $.datepicker._pos[1] -= document.documentElement.scrollTop;
\r
7311 var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
\r
7312 $.datepicker._pos = null;
\r
7313 // determine sizing offscreen
\r
7314 inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'});
\r
7315 $.datepicker._updateDatepicker(inst);
\r
7316 // fix width for dynamic number of date pickers
\r
7317 // and adjust position before showing
\r
7318 offset = $.datepicker._checkOffset(inst, offset, isFixed);
\r
7319 inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
\r
7320 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none',
\r
7321 left: offset.left + 'px', top: offset.top + 'px'});
\r
7322 if (!inst.inline) {
\r
7323 var showAnim = $.datepicker._get(inst, 'showAnim');
\r
7324 var duration = $.datepicker._get(inst, 'duration');
\r
7325 var postProcess = function() {
\r
7326 $.datepicker._datepickerShowing = true;
\r
7327 var borders = $.datepicker._getBorders(inst.dpDiv);
\r
7328 inst.dpDiv.find('iframe.ui-datepicker-cover'). // IE6- only
\r
7329 css({left: -borders[0], top: -borders[1],
\r
7330 width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()});
\r
7332 inst.dpDiv.zIndex($(input).zIndex()+1);
\r
7333 if ($.effects && $.effects[showAnim])
\r
7334 inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);
\r
7336 inst.dpDiv[showAnim || 'show']((showAnim ? duration : null), postProcess);
\r
7337 if (!showAnim || !duration)
\r
7339 if (inst.input.is(':visible') && !inst.input.is(':disabled'))
\r
7340 inst.input.focus();
\r
7341 $.datepicker._curInst = inst;
\r
7345 /* Generate the date picker content. */
\r
7346 _updateDatepicker: function(inst) {
\r
7348 var borders = $.datepicker._getBorders(inst.dpDiv);
\r
7349 inst.dpDiv.empty().append(this._generateHTML(inst))
\r
7350 .find('iframe.ui-datepicker-cover') // IE6- only
\r
7351 .css({left: -borders[0], top: -borders[1],
\r
7352 width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()})
\r
7354 .find('button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a')
\r
7355 .bind('mouseout', function(){
\r
7356 $(this).removeClass('ui-state-hover');
\r
7357 if(this.className.indexOf('ui-datepicker-prev') != -1) $(this).removeClass('ui-datepicker-prev-hover');
\r
7358 if(this.className.indexOf('ui-datepicker-next') != -1) $(this).removeClass('ui-datepicker-next-hover');
\r
7360 .bind('mouseover', function(){
\r
7361 if (!self._isDisabledDatepicker( inst.inline ? inst.dpDiv.parent()[0] : inst.input[0])) {
\r
7362 $(this).parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover');
\r
7363 $(this).addClass('ui-state-hover');
\r
7364 if(this.className.indexOf('ui-datepicker-prev') != -1) $(this).addClass('ui-datepicker-prev-hover');
\r
7365 if(this.className.indexOf('ui-datepicker-next') != -1) $(this).addClass('ui-datepicker-next-hover');
\r
7369 .find('.' + this._dayOverClass + ' a')
\r
7370 .trigger('mouseover')
\r
7372 var numMonths = this._getNumberOfMonths(inst);
\r
7373 var cols = numMonths[1];
\r
7376 inst.dpDiv.addClass('ui-datepicker-multi-' + cols).css('width', (width * cols) + 'em');
\r
7378 inst.dpDiv.removeClass('ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4').width('');
\r
7379 inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') +
\r
7380 'Class']('ui-datepicker-multi');
\r
7381 inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') +
\r
7382 'Class']('ui-datepicker-rtl');
\r
7383 if (inst == $.datepicker._curInst && $.datepicker._datepickerShowing && inst.input &&
\r
7384 inst.input.is(':visible') && !inst.input.is(':disabled'))
\r
7385 inst.input.focus();
\r
7388 /* Retrieve the size of left and top borders for an element.
\r
7389 @param elem (jQuery object) the element of interest
\r
7390 @return (number[2]) the left and top borders */
\r
7391 _getBorders: function(elem) {
\r
7392 var convert = function(value) {
\r
7393 return {thin: 1, medium: 2, thick: 3}[value] || value;
\r
7395 return [parseFloat(convert(elem.css('border-left-width'))),
\r
7396 parseFloat(convert(elem.css('border-top-width')))];
\r
7399 /* Check positioning to remain on screen. */
\r
7400 _checkOffset: function(inst, offset, isFixed) {
\r
7401 var dpWidth = inst.dpDiv.outerWidth();
\r
7402 var dpHeight = inst.dpDiv.outerHeight();
\r
7403 var inputWidth = inst.input ? inst.input.outerWidth() : 0;
\r
7404 var inputHeight = inst.input ? inst.input.outerHeight() : 0;
\r
7405 var viewWidth = document.documentElement.clientWidth + $(document).scrollLeft();
\r
7406 var viewHeight = document.documentElement.clientHeight + $(document).scrollTop();
\r
7408 offset.left -= (this._get(inst, 'isRTL') ? (dpWidth - inputWidth) : 0);
\r
7409 offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0;
\r
7410 offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
\r
7412 // now check if datepicker is showing outside window viewport - move to a better place if so.
\r
7413 offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
\r
7414 Math.abs(offset.left + dpWidth - viewWidth) : 0);
\r
7415 offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
\r
7416 Math.abs(dpHeight + inputHeight) : 0);
\r
7421 /* Find an object's position on the screen. */
\r
7422 _findPos: function(obj) {
\r
7423 var inst = this._getInst(obj);
\r
7424 var isRTL = this._get(inst, 'isRTL');
\r
7425 while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) {
\r
7426 obj = obj[isRTL ? 'previousSibling' : 'nextSibling'];
\r
7428 var position = $(obj).offset();
\r
7429 return [position.left, position.top];
\r
7432 /* Hide the date picker from view.
\r
7433 @param input element - the input field attached to the date picker */
\r
7434 _hideDatepicker: function(input) {
\r
7435 var inst = this._curInst;
\r
7436 if (!inst || (input && inst != $.data(input, PROP_NAME)))
\r
7438 if (this._datepickerShowing) {
\r
7439 var showAnim = this._get(inst, 'showAnim');
\r
7440 var duration = this._get(inst, 'duration');
\r
7441 var postProcess = function() {
\r
7442 $.datepicker._tidyDialog(inst);
\r
7443 this._curInst = null;
\r
7445 if ($.effects && $.effects[showAnim])
\r
7446 inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);
\r
7448 inst.dpDiv[(showAnim == 'slideDown' ? 'slideUp' :
\r
7449 (showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))]((showAnim ? duration : null), postProcess);
\r
7452 var onClose = this._get(inst, 'onClose');
\r
7454 onClose.apply((inst.input ? inst.input[0] : null),
\r
7455 [(inst.input ? inst.input.val() : ''), inst]); // trigger custom callback
\r
7456 this._datepickerShowing = false;
\r
7457 this._lastInput = null;
\r
7458 if (this._inDialog) {
\r
7459 this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' });
\r
7462 $('body').append(this.dpDiv);
\r
7465 this._inDialog = false;
\r
7469 /* Tidy up after a dialog display. */
\r
7470 _tidyDialog: function(inst) {
\r
7471 inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker-calendar');
\r
7474 /* Close date picker if clicked elsewhere. */
\r
7475 _checkExternalClick: function(event) {
\r
7476 if (!$.datepicker._curInst)
\r
7478 var $target = $(event.target);
\r
7479 if ($target[0].id != $.datepicker._mainDivId &&
\r
7480 $target.parents('#' + $.datepicker._mainDivId).length == 0 &&
\r
7481 !$target.hasClass($.datepicker.markerClassName) &&
\r
7482 !$target.hasClass($.datepicker._triggerClass) &&
\r
7483 $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI))
\r
7484 $.datepicker._hideDatepicker();
\r
7487 /* Adjust one of the date sub-fields. */
\r
7488 _adjustDate: function(id, offset, period) {
\r
7489 var target = $(id);
\r
7490 var inst = this._getInst(target[0]);
\r
7491 if (this._isDisabledDatepicker(target[0])) {
\r
7494 this._adjustInstDate(inst, offset +
\r
7495 (period == 'M' ? this._get(inst, 'showCurrentAtPos') : 0), // undo positioning
\r
7497 this._updateDatepicker(inst);
\r
7500 /* Action for current link. */
\r
7501 _gotoToday: function(id) {
\r
7502 var target = $(id);
\r
7503 var inst = this._getInst(target[0]);
\r
7504 if (this._get(inst, 'gotoCurrent') && inst.currentDay) {
\r
7505 inst.selectedDay = inst.currentDay;
\r
7506 inst.drawMonth = inst.selectedMonth = inst.currentMonth;
\r
7507 inst.drawYear = inst.selectedYear = inst.currentYear;
\r
7510 var date = new Date();
\r
7511 inst.selectedDay = date.getDate();
\r
7512 inst.drawMonth = inst.selectedMonth = date.getMonth();
\r
7513 inst.drawYear = inst.selectedYear = date.getFullYear();
\r
7515 this._notifyChange(inst);
\r
7516 this._adjustDate(target);
\r
7519 /* Action for selecting a new month/year. */
\r
7520 _selectMonthYear: function(id, select, period) {
\r
7521 var target = $(id);
\r
7522 var inst = this._getInst(target[0]);
\r
7523 inst._selectingMonthYear = false;
\r
7524 inst['selected' + (period == 'M' ? 'Month' : 'Year')] =
\r
7525 inst['draw' + (period == 'M' ? 'Month' : 'Year')] =
\r
7526 parseInt(select.options[select.selectedIndex].value,10);
\r
7527 this._notifyChange(inst);
\r
7528 this._adjustDate(target);
\r
7531 /* Restore input focus after not changing month/year. */
\r
7532 _clickMonthYear: function(id) {
\r
7533 var target = $(id);
\r
7534 var inst = this._getInst(target[0]);
\r
7535 if (inst.input && inst._selectingMonthYear && !$.browser.msie)
\r
7536 inst.input.focus();
\r
7537 inst._selectingMonthYear = !inst._selectingMonthYear;
\r
7540 /* Action for selecting a day. */
\r
7541 _selectDay: function(id, month, year, td) {
\r
7542 var target = $(id);
\r
7543 if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
\r
7546 var inst = this._getInst(target[0]);
\r
7547 inst.selectedDay = inst.currentDay = $('a', td).html();
\r
7548 inst.selectedMonth = inst.currentMonth = month;
\r
7549 inst.selectedYear = inst.currentYear = year;
\r
7550 this._selectDate(id, this._formatDate(inst,
\r
7551 inst.currentDay, inst.currentMonth, inst.currentYear));
\r
7554 /* Erase the input field and hide the date picker. */
\r
7555 _clearDate: function(id) {
\r
7556 var target = $(id);
\r
7557 var inst = this._getInst(target[0]);
\r
7558 this._selectDate(target, '');
\r
7561 /* Update the input field with the selected date. */
\r
7562 _selectDate: function(id, dateStr) {
\r
7563 var target = $(id);
\r
7564 var inst = this._getInst(target[0]);
\r
7565 dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
\r
7567 inst.input.val(dateStr);
\r
7568 this._updateAlternate(inst);
\r
7569 var onSelect = this._get(inst, 'onSelect');
\r
7571 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
\r
7572 else if (inst.input)
\r
7573 inst.input.trigger('change'); // fire the change event
\r
7575 this._updateDatepicker(inst);
\r
7577 this._hideDatepicker();
\r
7578 this._lastInput = inst.input[0];
\r
7579 if (typeof(inst.input[0]) != 'object')
\r
7580 inst.input.focus(); // restore focus
\r
7581 this._lastInput = null;
\r
7585 /* Update any alternate field to synchronise with the main field. */
\r
7586 _updateAlternate: function(inst) {
\r
7587 var altField = this._get(inst, 'altField');
\r
7588 if (altField) { // update alternate field too
\r
7589 var altFormat = this._get(inst, 'altFormat') || this._get(inst, 'dateFormat');
\r
7590 var date = this._getDate(inst);
\r
7591 var dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
\r
7592 $(altField).each(function() { $(this).val(dateStr); });
\r
7596 /* Set as beforeShowDay function to prevent selection of weekends.
\r
7597 @param date Date - the date to customise
\r
7598 @return [boolean, string] - is this date selectable?, what is its CSS class? */
\r
7599 noWeekends: function(date) {
\r
7600 var day = date.getDay();
\r
7601 return [(day > 0 && day < 6), ''];
\r
7604 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
\r
7605 @param date Date - the date to get the week for
\r
7606 @return number - the number of the week within the year that contains this date */
\r
7607 iso8601Week: function(date) {
\r
7608 var checkDate = new Date(date.getTime());
\r
7609 // Find Thursday of this week starting on Monday
\r
7610 checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
\r
7611 var time = checkDate.getTime();
\r
7612 checkDate.setMonth(0); // Compare with Jan 1
\r
7613 checkDate.setDate(1);
\r
7614 return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
\r
7617 /* Parse a string value into a date object.
\r
7618 See formatDate below for the possible formats.
\r
7620 @param format string - the expected format of the date
\r
7621 @param value string - the date in the above format
\r
7622 @param settings Object - attributes include:
\r
7623 shortYearCutoff number - the cutoff year for determining the century (optional)
\r
7624 dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
\r
7625 dayNames string[7] - names of the days from Sunday (optional)
\r
7626 monthNamesShort string[12] - abbreviated names of the months (optional)
\r
7627 monthNames string[12] - names of the months (optional)
\r
7628 @return Date - the extracted date value or null if value is blank */
\r
7629 parseDate: function (format, value, settings) {
\r
7630 if (format == null || value == null)
\r
7631 throw 'Invalid arguments';
\r
7632 value = (typeof value == 'object' ? value.toString() : value + '');
\r
7635 var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff;
\r
7636 var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
\r
7637 var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
\r
7638 var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
\r
7639 var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
\r
7644 var literal = false;
\r
7645 // Check whether a format character is doubled
\r
7646 var lookAhead = function(match) {
\r
7647 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
\r
7652 // Extract a number from the string value
\r
7653 var getNumber = function(match) {
\r
7655 var size = (match == '@' ? 14 : (match == '!' ? 20 :
\r
7656 (match == 'y' ? 4 : (match == 'o' ? 3 : 2))));
\r
7657 var digits = new RegExp('^\\d{1,' + size + '}');
\r
7658 var num = value.substring(iValue).match(digits);
\r
7660 throw 'Missing number at position ' + iValue;
\r
7661 iValue += num[0].length;
\r
7662 return parseInt(num[0], 10);
\r
7664 // Extract a name from the string value and convert to an index
\r
7665 var getName = function(match, shortNames, longNames) {
\r
7666 var names = (lookAhead(match) ? longNames : shortNames);
\r
7667 for (var i = 0; i < names.length; i++) {
\r
7668 if (value.substr(iValue, names[i].length) == names[i]) {
\r
7669 iValue += names[i].length;
\r
7673 throw 'Unknown name at position ' + iValue;
\r
7675 // Confirm that a literal character matches the string value
\r
7676 var checkLiteral = function() {
\r
7677 if (value.charAt(iValue) != format.charAt(iFormat))
\r
7678 throw 'Unexpected literal at position ' + iValue;
\r
7682 for (var iFormat = 0; iFormat < format.length; iFormat++) {
\r
7684 if (format.charAt(iFormat) == "'" && !lookAhead("'"))
\r
7689 switch (format.charAt(iFormat)) {
\r
7691 day = getNumber('d');
\r
7694 getName('D', dayNamesShort, dayNames);
\r
7697 doy = getNumber('o');
\r
7700 month = getNumber('m');
\r
7703 month = getName('M', monthNamesShort, monthNames);
\r
7706 year = getNumber('y');
\r
7709 var date = new Date(getNumber('@'));
\r
7710 year = date.getFullYear();
\r
7711 month = date.getMonth() + 1;
\r
7712 day = date.getDate();
\r
7715 var date = new Date((getNumber('!') - this._ticksTo1970) / 10000);
\r
7716 year = date.getFullYear();
\r
7717 month = date.getMonth() + 1;
\r
7718 day = date.getDate();
\r
7721 if (lookAhead("'"))
\r
7731 year = new Date().getFullYear();
\r
7732 else if (year < 100)
\r
7733 year += new Date().getFullYear() - new Date().getFullYear() % 100 +
\r
7734 (year <= shortYearCutoff ? 0 : -100);
\r
7739 var dim = this._getDaysInMonth(year, month - 1);
\r
7746 var date = this._daylightSavingAdjust(new Date(year, month - 1, day));
\r
7747 if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day)
\r
7748 throw 'Invalid date'; // E.g. 31/02/*
\r
7752 /* Standard date formats. */
\r
7753 ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601)
\r
7754 COOKIE: 'D, dd M yy',
\r
7755 ISO_8601: 'yy-mm-dd',
\r
7756 RFC_822: 'D, d M y',
\r
7757 RFC_850: 'DD, dd-M-y',
\r
7758 RFC_1036: 'D, d M y',
\r
7759 RFC_1123: 'D, d M yy',
\r
7760 RFC_2822: 'D, d M yy',
\r
7761 RSS: 'D, d M y', // RFC 822
\r
7764 W3C: 'yy-mm-dd', // ISO 8601
\r
7766 _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
\r
7767 Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
\r
7769 /* Format a date object into a string value.
\r
7770 The format can be combinations of the following:
\r
7771 d - day of month (no leading zero)
\r
7772 dd - day of month (two digit)
\r
7773 o - day of year (no leading zeros)
\r
7774 oo - day of year (three digit)
\r
7775 D - day name short
\r
7776 DD - day name long
\r
7777 m - month of year (no leading zero)
\r
7778 mm - month of year (two digit)
\r
7779 M - month name short
\r
7780 MM - month name long
\r
7781 y - year (two digit)
\r
7782 yy - year (four digit)
\r
7783 @ - Unix timestamp (ms since 01/01/1970)
\r
7784 ! - Windows ticks (100ns since 01/01/0001)
\r
7785 '...' - literal text
\r
7788 @param format string - the desired format of the date
\r
7789 @param date Date - the date value to format
\r
7790 @param settings Object - attributes include:
\r
7791 dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
\r
7792 dayNames string[7] - names of the days from Sunday (optional)
\r
7793 monthNamesShort string[12] - abbreviated names of the months (optional)
\r
7794 monthNames string[12] - names of the months (optional)
\r
7795 @return string - the date in the above format */
\r
7796 formatDate: function (format, date, settings) {
\r
7799 var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
\r
7800 var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
\r
7801 var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
\r
7802 var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
\r
7803 // Check whether a format character is doubled
\r
7804 var lookAhead = function(match) {
\r
7805 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
\r
7810 // Format a number, with leading zero if necessary
\r
7811 var formatNumber = function(match, value, len) {
\r
7812 var num = '' + value;
\r
7813 if (lookAhead(match))
\r
7814 while (num.length < len)
\r
7818 // Format a name, short or long as requested
\r
7819 var formatName = function(match, value, shortNames, longNames) {
\r
7820 return (lookAhead(match) ? longNames[value] : shortNames[value]);
\r
7823 var literal = false;
\r
7825 for (var iFormat = 0; iFormat < format.length; iFormat++) {
\r
7827 if (format.charAt(iFormat) == "'" && !lookAhead("'"))
\r
7830 output += format.charAt(iFormat);
\r
7832 switch (format.charAt(iFormat)) {
\r
7834 output += formatNumber('d', date.getDate(), 2);
\r
7837 output += formatName('D', date.getDay(), dayNamesShort, dayNames);
\r
7840 output += formatNumber('o',
\r
7841 (date.getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000, 3);
\r
7844 output += formatNumber('m', date.getMonth() + 1, 2);
\r
7847 output += formatName('M', date.getMonth(), monthNamesShort, monthNames);
\r
7850 output += (lookAhead('y') ? date.getFullYear() :
\r
7851 (date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100);
\r
7854 output += date.getTime();
\r
7857 output += date.getTime() * 10000 + this._ticksTo1970;
\r
7860 if (lookAhead("'"))
\r
7866 output += format.charAt(iFormat);
\r
7872 /* Extract all possible characters from the date format. */
\r
7873 _possibleChars: function (format) {
\r
7875 var literal = false;
\r
7876 // Check whether a format character is doubled
\r
7877 var lookAhead = function(match) {
\r
7878 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
\r
7883 for (var iFormat = 0; iFormat < format.length; iFormat++)
\r
7885 if (format.charAt(iFormat) == "'" && !lookAhead("'"))
\r
7888 chars += format.charAt(iFormat);
\r
7890 switch (format.charAt(iFormat)) {
\r
7891 case 'd': case 'm': case 'y': case '@':
\r
7892 chars += '0123456789';
\r
7894 case 'D': case 'M':
\r
7895 return null; // Accept anything
\r
7897 if (lookAhead("'"))
\r
7903 chars += format.charAt(iFormat);
\r
7908 /* Get a setting value, defaulting if necessary. */
\r
7909 _get: function(inst, name) {
\r
7910 return inst.settings[name] !== undefined ?
\r
7911 inst.settings[name] : this._defaults[name];
\r
7914 /* Parse existing date and initialise date picker. */
\r
7915 _setDateFromField: function(inst, noDefault) {
\r
7916 if (inst.input.val() == inst.lastVal) {
\r
7919 var dateFormat = this._get(inst, 'dateFormat');
\r
7920 var dates = inst.lastVal = inst.input ? inst.input.val() : null;
\r
7921 var date, defaultDate;
\r
7922 date = defaultDate = this._getDefaultDate(inst);
\r
7923 var settings = this._getFormatConfig(inst);
\r
7925 date = this.parseDate(dateFormat, dates, settings) || defaultDate;
\r
7928 dates = (noDefault ? '' : dates);
\r
7930 inst.selectedDay = date.getDate();
\r
7931 inst.drawMonth = inst.selectedMonth = date.getMonth();
\r
7932 inst.drawYear = inst.selectedYear = date.getFullYear();
\r
7933 inst.currentDay = (dates ? date.getDate() : 0);
\r
7934 inst.currentMonth = (dates ? date.getMonth() : 0);
\r
7935 inst.currentYear = (dates ? date.getFullYear() : 0);
\r
7936 this._adjustInstDate(inst);
\r
7939 /* Retrieve the default date shown on opening. */
\r
7940 _getDefaultDate: function(inst) {
\r
7941 return this._restrictMinMax(inst,
\r
7942 this._determineDate(inst, this._get(inst, 'defaultDate'), new Date()));
\r
7945 /* A date may be specified as an exact value or a relative one. */
\r
7946 _determineDate: function(inst, date, defaultDate) {
\r
7947 var offsetNumeric = function(offset) {
\r
7948 var date = new Date();
\r
7949 date.setDate(date.getDate() + offset);
\r
7952 var offsetString = function(offset) {
\r
7954 return $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'),
\r
7955 offset, $.datepicker._getFormatConfig(inst));
\r
7960 var date = (offset.toLowerCase().match(/^c/) ?
\r
7961 $.datepicker._getDate(inst) : null) || new Date();
\r
7962 var year = date.getFullYear();
\r
7963 var month = date.getMonth();
\r
7964 var day = date.getDate();
\r
7965 var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g;
\r
7966 var matches = pattern.exec(offset);
\r
7968 switch (matches[2] || 'd') {
\r
7969 case 'd' : case 'D' :
\r
7970 day += parseInt(matches[1],10); break;
\r
7971 case 'w' : case 'W' :
\r
7972 day += parseInt(matches[1],10) * 7; break;
\r
7973 case 'm' : case 'M' :
\r
7974 month += parseInt(matches[1],10);
\r
7975 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
\r
7977 case 'y': case 'Y' :
\r
7978 year += parseInt(matches[1],10);
\r
7979 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
\r
7982 matches = pattern.exec(offset);
\r
7984 return new Date(year, month, day);
\r
7986 date = (date == null ? defaultDate : (typeof date == 'string' ? offsetString(date) :
\r
7987 (typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : date)));
\r
7988 date = (date && date.toString() == 'Invalid Date' ? defaultDate : date);
\r
7991 date.setMinutes(0);
\r
7992 date.setSeconds(0);
\r
7993 date.setMilliseconds(0);
\r
7995 return this._daylightSavingAdjust(date);
\r
7998 /* Handle switch to/from daylight saving.
\r
7999 Hours may be non-zero on daylight saving cut-over:
\r
8000 > 12 when midnight changeover, but then cannot generate
\r
8001 midnight datetime, so jump to 1AM, otherwise reset.
\r
8002 @param date (Date) the date to check
\r
8003 @return (Date) the corrected date */
\r
8004 _daylightSavingAdjust: function(date) {
\r
8005 if (!date) return null;
\r
8006 date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
\r
8010 /* Set the date(s) directly. */
\r
8011 _setDate: function(inst, date, noChange) {
\r
8012 var clear = !(date);
\r
8013 var origMonth = inst.selectedMonth;
\r
8014 var origYear = inst.selectedYear;
\r
8015 date = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
\r
8016 inst.selectedDay = inst.currentDay = date.getDate();
\r
8017 inst.drawMonth = inst.selectedMonth = inst.currentMonth = date.getMonth();
\r
8018 inst.drawYear = inst.selectedYear = inst.currentYear = date.getFullYear();
\r
8019 if ((origMonth != inst.selectedMonth || origYear != inst.selectedYear) && !noChange)
\r
8020 this._notifyChange(inst);
\r
8021 this._adjustInstDate(inst);
\r
8023 inst.input.val(clear ? '' : this._formatDate(inst));
\r
8027 /* Retrieve the date(s) directly. */
\r
8028 _getDate: function(inst) {
\r
8029 var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null :
\r
8030 this._daylightSavingAdjust(new Date(
\r
8031 inst.currentYear, inst.currentMonth, inst.currentDay)));
\r
8035 /* Generate the HTML for the current state of the date picker. */
\r
8036 _generateHTML: function(inst) {
\r
8037 var today = new Date();
\r
8038 today = this._daylightSavingAdjust(
\r
8039 new Date(today.getFullYear(), today.getMonth(), today.getDate())); // clear time
\r
8040 var isRTL = this._get(inst, 'isRTL');
\r
8041 var showButtonPanel = this._get(inst, 'showButtonPanel');
\r
8042 var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext');
\r
8043 var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat');
\r
8044 var numMonths = this._getNumberOfMonths(inst);
\r
8045 var showCurrentAtPos = this._get(inst, 'showCurrentAtPos');
\r
8046 var stepMonths = this._get(inst, 'stepMonths');
\r
8047 var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1);
\r
8048 var currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
\r
8049 new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
\r
8050 var minDate = this._getMinMaxDate(inst, 'min');
\r
8051 var maxDate = this._getMinMaxDate(inst, 'max');
\r
8052 var drawMonth = inst.drawMonth - showCurrentAtPos;
\r
8053 var drawYear = inst.drawYear;
\r
8054 if (drawMonth < 0) {
\r
8059 var maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
\r
8060 maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
\r
8061 maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
\r
8062 while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
\r
8064 if (drawMonth < 0) {
\r
8070 inst.drawMonth = drawMonth;
\r
8071 inst.drawYear = drawYear;
\r
8072 var prevText = this._get(inst, 'prevText');
\r
8073 prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
\r
8074 this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
\r
8075 this._getFormatConfig(inst)));
\r
8076 var prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
\r
8077 '<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery_' + dpuuid +
\r
8078 '.datepicker._adjustDate(\'#' + inst.id + '\', -' + stepMonths + ', \'M\');"' +
\r
8079 ' title="' + prevText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'e' : 'w') + '">' + prevText + '</span></a>' :
\r
8080 (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>'));
\r
8081 var nextText = this._get(inst, 'nextText');
\r
8082 nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
\r
8083 this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
\r
8084 this._getFormatConfig(inst)));
\r
8085 var next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
\r
8086 '<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery_' + dpuuid +
\r
8087 '.datepicker._adjustDate(\'#' + inst.id + '\', +' + stepMonths + ', \'M\');"' +
\r
8088 ' title="' + nextText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'w' : 'e') + '">' + nextText + '</span></a>' :
\r
8089 (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>'));
\r
8090 var currentText = this._get(inst, 'currentText');
\r
8091 var gotoDate = (this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today);
\r
8092 currentText = (!navigationAsDateFormat ? currentText :
\r
8093 this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
\r
8094 var controls = (!inst.inline ? '<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery_' + dpuuid +
\r
8095 '.datepicker._hideDatepicker();">' + this._get(inst, 'closeText') + '</button>' : '');
\r
8096 var buttonPanel = (showButtonPanel) ? '<div class="ui-datepicker-buttonpane ui-widget-content">' + (isRTL ? controls : '') +
\r
8097 (this._isInRange(inst, gotoDate) ? '<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery_' + dpuuid +
\r
8098 '.datepicker._gotoToday(\'#' + inst.id + '\');"' +
\r
8099 '>' + currentText + '</button>' : '') + (isRTL ? '' : controls) + '</div>' : '';
\r
8100 var firstDay = parseInt(this._get(inst, 'firstDay'),10);
\r
8101 firstDay = (isNaN(firstDay) ? 0 : firstDay);
\r
8102 var showWeek = this._get(inst, 'showWeek');
\r
8103 var dayNames = this._get(inst, 'dayNames');
\r
8104 var dayNamesShort = this._get(inst, 'dayNamesShort');
\r
8105 var dayNamesMin = this._get(inst, 'dayNamesMin');
\r
8106 var monthNames = this._get(inst, 'monthNames');
\r
8107 var monthNamesShort = this._get(inst, 'monthNamesShort');
\r
8108 var beforeShowDay = this._get(inst, 'beforeShowDay');
\r
8109 var showOtherMonths = this._get(inst, 'showOtherMonths');
\r
8110 var selectOtherMonths = this._get(inst, 'selectOtherMonths');
\r
8111 var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week;
\r
8112 var defaultDate = this._getDefaultDate(inst);
\r
8114 for (var row = 0; row < numMonths[0]; row++) {
\r
8116 for (var col = 0; col < numMonths[1]; col++) {
\r
8117 var selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
\r
8118 var cornerClass = ' ui-corner-all';
\r
8119 var calender = '';
\r
8120 if (isMultiMonth) {
\r
8121 calender += '<div class="ui-datepicker-group';
\r
8122 if (numMonths[1] > 1)
\r
8124 case 0: calender += ' ui-datepicker-group-first';
\r
8125 cornerClass = ' ui-corner-' + (isRTL ? 'right' : 'left'); break;
\r
8126 case numMonths[1]-1: calender += ' ui-datepicker-group-last';
\r
8127 cornerClass = ' ui-corner-' + (isRTL ? 'left' : 'right'); break;
\r
8128 default: calender += ' ui-datepicker-group-middle'; cornerClass = ''; break;
\r
8132 calender += '<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix' + cornerClass + '">' +
\r
8133 (/all|left/.test(cornerClass) && row == 0 ? (isRTL ? next : prev) : '') +
\r
8134 (/all|right/.test(cornerClass) && row == 0 ? (isRTL ? prev : next) : '') +
\r
8135 this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
\r
8136 row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
\r
8137 '</div><table class="ui-datepicker-calendar"><thead>' +
\r
8139 var thead = (showWeek ? '<th class="ui-datepicker-week-col">' + this._get(inst, 'weekHeader') + '</th>' : '');
\r
8140 for (var dow = 0; dow < 7; dow++) { // days of the week
\r
8141 var day = (dow + firstDay) % 7;
\r
8142 thead += '<th' + ((dow + firstDay + 6) % 7 >= 5 ? ' class="ui-datepicker-week-end"' : '') + '>' +
\r
8143 '<span title="' + dayNames[day] + '">' + dayNamesMin[day] + '</span></th>';
\r
8145 calender += thead + '</tr></thead><tbody>';
\r
8146 var daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
\r
8147 if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth)
\r
8148 inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
\r
8149 var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
\r
8150 var numRows = (isMultiMonth ? 6 : Math.ceil((leadDays + daysInMonth) / 7)); // calculate the number of rows to generate
\r
8151 var printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
\r
8152 for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows
\r
8153 calender += '<tr>';
\r
8154 var tbody = (!showWeek ? '' : '<td class="ui-datepicker-week-col">' +
\r
8155 this._get(inst, 'calculateWeek')(printDate) + '</td>');
\r
8156 for (var dow = 0; dow < 7; dow++) { // create date picker days
\r
8157 var daySettings = (beforeShowDay ?
\r
8158 beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']);
\r
8159 var otherMonth = (printDate.getMonth() != drawMonth);
\r
8160 var unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
\r
8161 (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
\r
8162 tbody += '<td class="' +
\r
8163 ((dow + firstDay + 6) % 7 >= 5 ? ' ui-datepicker-week-end' : '') + // highlight weekends
\r
8164 (otherMonth ? ' ui-datepicker-other-month' : '') + // highlight days from other months
\r
8165 ((printDate.getTime() == selectedDate.getTime() && drawMonth == inst.selectedMonth && inst._keyEvent) || // user pressed key
\r
8166 (defaultDate.getTime() == printDate.getTime() && defaultDate.getTime() == selectedDate.getTime()) ?
\r
8167 // or defaultDate is current printedDate and defaultDate is selectedDate
\r
8168 ' ' + this._dayOverClass : '') + // highlight selected day
\r
8169 (unselectable ? ' ' + this._unselectableClass + ' ui-state-disabled': '') + // highlight unselectable days
\r
8170 (otherMonth && !showOtherMonths ? '' : ' ' + daySettings[1] + // highlight custom dates
\r
8171 (printDate.getTime() == currentDate.getTime() ? ' ' + this._currentClass : '') + // highlight selected day
\r
8172 (printDate.getTime() == today.getTime() ? ' ui-datepicker-today' : '')) + '"' + // highlight today (if different)
\r
8173 ((!otherMonth || showOtherMonths) && daySettings[2] ? ' title="' + daySettings[2] + '"' : '') + // cell title
\r
8174 (unselectable ? '' : ' onclick="DP_jQuery_' + dpuuid + '.datepicker._selectDay(\'#' +
\r
8175 inst.id + '\',' + printDate.getMonth() + ',' + printDate.getFullYear() + ', this);return false;"') + '>' + // actions
\r
8176 (otherMonth && !showOtherMonths ? ' ' : // display for other months
\r
8177 (unselectable ? '<span class="ui-state-default">' + printDate.getDate() + '</span>' : '<a class="ui-state-default' +
\r
8178 (printDate.getTime() == today.getTime() ? ' ui-state-highlight' : '') +
\r
8179 (printDate.getTime() == currentDate.getTime() ? ' ui-state-active' : '') + // highlight selected day
\r
8180 (otherMonth ? ' ui-priority-secondary' : '') + // distinguish dates from other months
\r
8181 '" href="#">' + printDate.getDate() + '</a>')) + '</td>'; // display selectable date
\r
8182 printDate.setDate(printDate.getDate() + 1);
\r
8183 printDate = this._daylightSavingAdjust(printDate);
\r
8185 calender += tbody + '</tr>';
\r
8188 if (drawMonth > 11) {
\r
8192 calender += '</tbody></table>' + (isMultiMonth ? '</div>' +
\r
8193 ((numMonths[0] > 0 && col == numMonths[1]-1) ? '<div class="ui-datepicker-row-break"></div>' : '') : '');
\r
8194 group += calender;
\r
8198 html += buttonPanel + ($.browser.msie && parseInt($.browser.version,10) < 7 && !inst.inline ?
\r
8199 '<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>' : '');
\r
8200 inst._keyEvent = false;
\r
8204 /* Generate the month and year header. */
\r
8205 _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
\r
8206 secondary, monthNames, monthNamesShort) {
\r
8207 var changeMonth = this._get(inst, 'changeMonth');
\r
8208 var changeYear = this._get(inst, 'changeYear');
\r
8209 var showMonthAfterYear = this._get(inst, 'showMonthAfterYear');
\r
8210 var html = '<div class="ui-datepicker-title">';
\r
8211 var monthHtml = '';
\r
8212 // month selection
\r
8213 if (secondary || !changeMonth)
\r
8214 monthHtml += '<span class="ui-datepicker-month">' + monthNames[drawMonth] + '</span>';
\r
8216 var inMinYear = (minDate && minDate.getFullYear() == drawYear);
\r
8217 var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear);
\r
8218 monthHtml += '<select class="ui-datepicker-month" ' +
\r
8219 'onchange="DP_jQuery_' + dpuuid + '.datepicker._selectMonthYear(\'#' + inst.id + '\', this, \'M\');" ' +
\r
8220 'onclick="DP_jQuery_' + dpuuid + '.datepicker._clickMonthYear(\'#' + inst.id + '\');"' +
\r
8222 for (var month = 0; month < 12; month++) {
\r
8223 if ((!inMinYear || month >= minDate.getMonth()) &&
\r
8224 (!inMaxYear || month <= maxDate.getMonth()))
\r
8225 monthHtml += '<option value="' + month + '"' +
\r
8226 (month == drawMonth ? ' selected="selected"' : '') +
\r
8227 '>' + monthNamesShort[month] + '</option>';
\r
8229 monthHtml += '</select>';
\r
8231 if (!showMonthAfterYear)
\r
8232 html += monthHtml + (secondary || !(changeMonth && changeYear) ? ' ' : '');
\r
8234 if (secondary || !changeYear)
\r
8235 html += '<span class="ui-datepicker-year">' + drawYear + '</span>';
\r
8237 // determine range of years to display
\r
8238 var years = this._get(inst, 'yearRange').split(':');
\r
8239 var thisYear = new Date().getFullYear();
\r
8240 var determineYear = function(value) {
\r
8241 var year = (value.match(/c[+-].*/) ? drawYear + parseInt(value.substring(1), 10) :
\r
8242 (value.match(/[+-].*/) ? thisYear + parseInt(value, 10) :
\r
8243 parseInt(value, 10)));
\r
8244 return (isNaN(year) ? thisYear : year);
\r
8246 var year = determineYear(years[0]);
\r
8247 var endYear = Math.max(year, determineYear(years[1] || ''));
\r
8248 year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
\r
8249 endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
\r
8250 html += '<select class="ui-datepicker-year" ' +
\r
8251 'onchange="DP_jQuery_' + dpuuid + '.datepicker._selectMonthYear(\'#' + inst.id + '\', this, \'Y\');" ' +
\r
8252 'onclick="DP_jQuery_' + dpuuid + '.datepicker._clickMonthYear(\'#' + inst.id + '\');"' +
\r
8254 for (; year <= endYear; year++) {
\r
8255 html += '<option value="' + year + '"' +
\r
8256 (year == drawYear ? ' selected="selected"' : '') +
\r
8257 '>' + year + '</option>';
\r
8259 html += '</select>';
\r
8261 html += this._get(inst, 'yearSuffix');
\r
8262 if (showMonthAfterYear)
\r
8263 html += (secondary || !(changeMonth && changeYear) ? ' ' : '') + monthHtml;
\r
8264 html += '</div>'; // Close datepicker_header
\r
8268 /* Adjust one of the date sub-fields. */
\r
8269 _adjustInstDate: function(inst, offset, period) {
\r
8270 var year = inst.drawYear + (period == 'Y' ? offset : 0);
\r
8271 var month = inst.drawMonth + (period == 'M' ? offset : 0);
\r
8272 var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) +
\r
8273 (period == 'D' ? offset : 0);
\r
8274 var date = this._restrictMinMax(inst,
\r
8275 this._daylightSavingAdjust(new Date(year, month, day)));
\r
8276 inst.selectedDay = date.getDate();
\r
8277 inst.drawMonth = inst.selectedMonth = date.getMonth();
\r
8278 inst.drawYear = inst.selectedYear = date.getFullYear();
\r
8279 if (period == 'M' || period == 'Y')
\r
8280 this._notifyChange(inst);
\r
8283 /* Ensure a date is within any min/max bounds. */
\r
8284 _restrictMinMax: function(inst, date) {
\r
8285 var minDate = this._getMinMaxDate(inst, 'min');
\r
8286 var maxDate = this._getMinMaxDate(inst, 'max');
\r
8287 date = (minDate && date < minDate ? minDate : date);
\r
8288 date = (maxDate && date > maxDate ? maxDate : date);
\r
8292 /* Notify change of month/year. */
\r
8293 _notifyChange: function(inst) {
\r
8294 var onChange = this._get(inst, 'onChangeMonthYear');
\r
8296 onChange.apply((inst.input ? inst.input[0] : null),
\r
8297 [inst.selectedYear, inst.selectedMonth + 1, inst]);
\r
8300 /* Determine the number of months to show. */
\r
8301 _getNumberOfMonths: function(inst) {
\r
8302 var numMonths = this._get(inst, 'numberOfMonths');
\r
8303 return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths));
\r
8306 /* Determine the current maximum date - ensure no time components are set. */
\r
8307 _getMinMaxDate: function(inst, minMax) {
\r
8308 return this._determineDate(inst, this._get(inst, minMax + 'Date'), null);
\r
8311 /* Find the number of days in a given month. */
\r
8312 _getDaysInMonth: function(year, month) {
\r
8313 return 32 - new Date(year, month, 32).getDate();
\r
8316 /* Find the day of the week of the first of a month. */
\r
8317 _getFirstDayOfMonth: function(year, month) {
\r
8318 return new Date(year, month, 1).getDay();
\r
8321 /* Determines if we should allow a "next/prev" month display change. */
\r
8322 _canAdjustMonth: function(inst, offset, curYear, curMonth) {
\r
8323 var numMonths = this._getNumberOfMonths(inst);
\r
8324 var date = this._daylightSavingAdjust(new Date(curYear,
\r
8325 curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
\r
8327 date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
\r
8328 return this._isInRange(inst, date);
\r
8331 /* Is the given date in the accepted range? */
\r
8332 _isInRange: function(inst, date) {
\r
8333 var minDate = this._getMinMaxDate(inst, 'min');
\r
8334 var maxDate = this._getMinMaxDate(inst, 'max');
\r
8335 return ((!minDate || date.getTime() >= minDate.getTime()) &&
\r
8336 (!maxDate || date.getTime() <= maxDate.getTime()));
\r
8339 /* Provide the configuration settings for formatting/parsing. */
\r
8340 _getFormatConfig: function(inst) {
\r
8341 var shortYearCutoff = this._get(inst, 'shortYearCutoff');
\r
8342 shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff :
\r
8343 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
\r
8344 return {shortYearCutoff: shortYearCutoff,
\r
8345 dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'),
\r
8346 monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')};
\r
8349 /* Format the given date for display. */
\r
8350 _formatDate: function(inst, day, month, year) {
\r
8352 inst.currentDay = inst.selectedDay;
\r
8353 inst.currentMonth = inst.selectedMonth;
\r
8354 inst.currentYear = inst.selectedYear;
\r
8356 var date = (day ? (typeof day == 'object' ? day :
\r
8357 this._daylightSavingAdjust(new Date(year, month, day))) :
\r
8358 this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
\r
8359 return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst));
\r
8363 /* jQuery extend now ignores nulls! */
\r
8364 function extendRemove(target, props) {
\r
8365 $.extend(target, props);
\r
8366 for (var name in props)
\r
8367 if (props[name] == null || props[name] == undefined)
\r
8368 target[name] = props[name];
\r
8372 /* Determine whether an object is an array. */
\r
8373 function isArray(a) {
\r
8374 return (a && (($.browser.safari && typeof a == 'object' && a.length) ||
\r
8375 (a.constructor && a.constructor.toString().match(/\Array\(\)/))));
\r
8378 /* Invoke the datepicker functionality.
\r
8379 @param options string - a command, optionally followed by additional parameters or
\r
8380 Object - settings for attaching new datepicker functionality
\r
8381 @return jQuery object */
\r
8382 $.fn.datepicker = function(options){
\r
8384 /* Initialise the date picker. */
\r
8385 if (!$.datepicker.initialized) {
\r
8386 $(document).mousedown($.datepicker._checkExternalClick).
\r
8387 find('body').append($.datepicker.dpDiv);
\r
8388 $.datepicker.initialized = true;
\r
8391 var otherArgs = Array.prototype.slice.call(arguments, 1);
\r
8392 if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate' || options == 'widget'))
\r
8393 return $.datepicker['_' + options + 'Datepicker'].
\r
8394 apply($.datepicker, [this[0]].concat(otherArgs));
\r
8395 if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string')
\r
8396 return $.datepicker['_' + options + 'Datepicker'].
\r
8397 apply($.datepicker, [this[0]].concat(otherArgs));
\r
8398 return this.each(function() {
\r
8399 typeof options == 'string' ?
\r
8400 $.datepicker['_' + options + 'Datepicker'].
\r
8401 apply($.datepicker, [this].concat(otherArgs)) :
\r
8402 $.datepicker._attachDatepicker(this, options);
\r
8406 $.datepicker = new Datepicker(); // singleton instance
\r
8407 $.datepicker.initialized = false;
\r
8408 $.datepicker.uuid = new Date().getTime();
\r
8409 $.datepicker.version = "1.8";
\r
8411 // Workaround for #4055
\r
8412 // Add another global to avoid noConflict issues with inline event handlers
\r
8413 window['DP_jQuery_' + dpuuid] = $;
\r
8417 * jQuery UI Dialog 1.8
\r
8419 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
8420 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
8421 * and GPL (GPL-LICENSE.txt) licenses.
\r
8423 * http://docs.jquery.com/UI/Dialog
\r
8426 * jquery.ui.core.js
\r
8427 * jquery.ui.widget.js
\r
8428 * jquery.ui.button.js
\r
8429 * jquery.ui.draggable.js
\r
8430 * jquery.ui.mouse.js
\r
8431 * jquery.ui.position.js
\r
8432 * jquery.ui.resizable.js
\r
8436 var uiDialogClasses =
\r
8439 'ui-widget-content ' +
\r
8442 $.widget("ui.dialog", {
\r
8446 closeOnEscape: true,
\r
8447 closeText: 'close',
\r
8457 position: 'center',
\r
8465 _create: function() {
\r
8466 this.originalTitle = this.element.attr('title');
\r
8469 options = self.options,
\r
8471 title = options.title || self.originalTitle || ' ',
\r
8472 titleId = $.ui.dialog.getTitleId(self.element),
\r
8474 uiDialog = (self.uiDialog = $('<div></div>'))
\r
8475 .appendTo(document.body)
\r
8477 .addClass(uiDialogClasses + options.dialogClass)
\r
8479 zIndex: options.zIndex
\r
8481 // setting tabIndex makes the div focusable
\r
8482 // setting outline to 0 prevents a border on focus in Mozilla
\r
8483 .attr('tabIndex', -1).css('outline', 0).keydown(function(event) {
\r
8484 if (options.closeOnEscape && event.keyCode &&
\r
8485 event.keyCode === $.ui.keyCode.ESCAPE) {
\r
8487 self.close(event);
\r
8488 event.preventDefault();
\r
8493 'aria-labelledby': titleId
\r
8495 .mousedown(function(event) {
\r
8496 self.moveToTop(false, event);
\r
8499 uiDialogContent = self.element
\r
8501 .removeAttr('title')
\r
8503 'ui-dialog-content ' +
\r
8504 'ui-widget-content')
\r
8505 .appendTo(uiDialog),
\r
8507 uiDialogTitlebar = (self.uiDialogTitlebar = $('<div></div>'))
\r
8509 'ui-dialog-titlebar ' +
\r
8510 'ui-widget-header ' +
\r
8511 'ui-corner-all ' +
\r
8512 'ui-helper-clearfix'
\r
8514 .prependTo(uiDialog),
\r
8516 uiDialogTitlebarClose = $('<a href="#"></a>')
\r
8518 'ui-dialog-titlebar-close ' +
\r
8521 .attr('role', 'button')
\r
8524 uiDialogTitlebarClose.addClass('ui-state-hover');
\r
8527 uiDialogTitlebarClose.removeClass('ui-state-hover');
\r
8530 .focus(function() {
\r
8531 uiDialogTitlebarClose.addClass('ui-state-focus');
\r
8533 .blur(function() {
\r
8534 uiDialogTitlebarClose.removeClass('ui-state-focus');
\r
8536 .click(function(event) {
\r
8537 self.close(event);
\r
8540 .appendTo(uiDialogTitlebar),
\r
8542 uiDialogTitlebarCloseText = (self.uiDialogTitlebarCloseText = $('<span></span>'))
\r
8545 'ui-icon-closethick'
\r
8547 .text(options.closeText)
\r
8548 .appendTo(uiDialogTitlebarClose),
\r
8550 uiDialogTitle = $('<span></span>')
\r
8551 .addClass('ui-dialog-title')
\r
8552 .attr('id', titleId)
\r
8554 .prependTo(uiDialogTitlebar);
\r
8556 //handling of deprecated beforeclose (vs beforeClose) option
\r
8557 //Ticket #4669 http://dev.jqueryui.com/ticket/4669
\r
8558 //TODO: remove in 1.9pre
\r
8559 if ($.isFunction(options.beforeclose) && !$.isFunction(options.beforeClose)) {
\r
8560 options.beforeClose = options.beforeclose;
\r
8563 uiDialogTitlebar.find("*").add(uiDialogTitlebar).disableSelection();
\r
8565 if (options.draggable && $.fn.draggable) {
\r
8566 self._makeDraggable();
\r
8568 if (options.resizable && $.fn.resizable) {
\r
8569 self._makeResizable();
\r
8572 self._createButtons(options.buttons);
\r
8573 self._isOpen = false;
\r
8575 if ($.fn.bgiframe) {
\r
8576 uiDialog.bgiframe();
\r
8579 _init: function() {
\r
8580 if ( this.options.autoOpen ) {
\r
8585 destroy: function() {
\r
8588 if (self.overlay) {
\r
8589 self.overlay.destroy();
\r
8591 self.uiDialog.hide();
\r
8593 .unbind('.dialog')
\r
8594 .removeData('dialog')
\r
8595 .removeClass('ui-dialog-content ui-widget-content')
\r
8596 .hide().appendTo('body');
\r
8597 self.uiDialog.remove();
\r
8599 if (self.originalTitle) {
\r
8600 self.element.attr('title', self.originalTitle);
\r
8606 widget: function() {
\r
8607 return this.uiDialog;
\r
8610 close: function(event) {
\r
8614 if (false === self._trigger('beforeClose', event)) {
\r
8618 if (self.overlay) {
\r
8619 self.overlay.destroy();
\r
8621 self.uiDialog.unbind('keypress.ui-dialog');
\r
8623 self._isOpen = false;
\r
8625 if (self.options.hide) {
\r
8626 self.uiDialog.hide(self.options.hide, function() {
\r
8627 self._trigger('close', event);
\r
8630 self.uiDialog.hide();
\r
8631 self._trigger('close', event);
\r
8634 $.ui.dialog.overlay.resize();
\r
8636 // adjust the maxZ to allow other modal dialogs to continue to work (see #4309)
\r
8637 if (self.options.modal) {
\r
8639 $('.ui-dialog').each(function() {
\r
8640 if (this !== self.uiDialog[0]) {
\r
8641 maxZ = Math.max(maxZ, $(this).css('z-index'));
\r
8644 $.ui.dialog.maxZ = maxZ;
\r
8650 isOpen: function() {
\r
8651 return this._isOpen;
\r
8654 // the force parameter allows us to move modal dialogs to their correct
\r
8655 // position on open
\r
8656 moveToTop: function(force, event) {
\r
8658 options = self.options,
\r
8661 if ((options.modal && !force) ||
\r
8662 (!options.stack && !options.modal)) {
\r
8663 return self._trigger('focus', event);
\r
8666 if (options.zIndex > $.ui.dialog.maxZ) {
\r
8667 $.ui.dialog.maxZ = options.zIndex;
\r
8669 if (self.overlay) {
\r
8670 $.ui.dialog.maxZ += 1;
\r
8671 self.overlay.$el.css('z-index', $.ui.dialog.overlay.maxZ = $.ui.dialog.maxZ);
\r
8674 //Save and then restore scroll since Opera 9.5+ resets when parent z-Index is changed.
\r
8675 // http://ui.jquery.com/bugs/ticket/3193
\r
8676 saveScroll = { scrollTop: self.element.attr('scrollTop'), scrollLeft: self.element.attr('scrollLeft') };
\r
8677 $.ui.dialog.maxZ += 1;
\r
8678 self.uiDialog.css('z-index', $.ui.dialog.maxZ);
\r
8679 self.element.attr(saveScroll);
\r
8680 self._trigger('focus', event);
\r
8685 open: function() {
\r
8686 if (this._isOpen) { return; }
\r
8689 options = self.options,
\r
8690 uiDialog = self.uiDialog;
\r
8692 self.overlay = options.modal ? new $.ui.dialog.overlay(self) : null;
\r
8693 if (uiDialog.next().length) {
\r
8694 uiDialog.appendTo('body');
\r
8697 self._position(options.position);
\r
8698 uiDialog.show(options.show);
\r
8699 self.moveToTop(true);
\r
8701 // prevent tabbing out of modal dialogs
\r
8702 if (options.modal) {
\r
8703 uiDialog.bind('keypress.ui-dialog', function(event) {
\r
8704 if (event.keyCode !== $.ui.keyCode.TAB) {
\r
8708 var tabbables = $(':tabbable', this),
\r
8709 first = tabbables.filter(':first'),
\r
8710 last = tabbables.filter(':last');
\r
8712 if (event.target === last[0] && !event.shiftKey) {
\r
8715 } else if (event.target === first[0] && event.shiftKey) {
\r
8722 // set focus to the first tabbable element in the content area or the first button
\r
8723 // if there are no tabbable elements, set focus on the dialog itself
\r
8725 .add(uiDialog.find('.ui-dialog-content :tabbable:first'))
\r
8726 .add(uiDialog.find('.ui-dialog-buttonpane :tabbable:first'))
\r
8731 self._trigger('open');
\r
8732 self._isOpen = true;
\r
8737 _createButtons: function(buttons) {
\r
8739 hasButtons = false,
\r
8740 uiDialogButtonPane = $('<div></div>')
\r
8742 'ui-dialog-buttonpane ' +
\r
8743 'ui-widget-content ' +
\r
8744 'ui-helper-clearfix'
\r
8747 // if we already have a button pane, remove it
\r
8748 self.uiDialog.find('.ui-dialog-buttonpane').remove();
\r
8750 if (typeof buttons === 'object' && buttons !== null) {
\r
8751 $.each(buttons, function() {
\r
8752 return !(hasButtons = true);
\r
8756 $.each(buttons, function(name, fn) {
\r
8757 var button = $('<button type="button"></button>')
\r
8759 .click(function() { fn.apply(self.element[0], arguments); })
\r
8760 .appendTo(uiDialogButtonPane);
\r
8761 if ($.fn.button) {
\r
8765 uiDialogButtonPane.appendTo(self.uiDialog);
\r
8769 _makeDraggable: function() {
\r
8771 options = self.options,
\r
8772 doc = $(document),
\r
8775 function filteredUi(ui) {
\r
8777 position: ui.position,
\r
8782 self.uiDialog.draggable({
\r
8783 cancel: '.ui-dialog-content, .ui-dialog-titlebar-close',
\r
8784 handle: '.ui-dialog-titlebar',
\r
8785 containment: 'document',
\r
8786 start: function(event, ui) {
\r
8787 heightBeforeDrag = options.height === "auto" ? "auto" : $(this).height();
\r
8788 $(this).height($(this).height()).addClass("ui-dialog-dragging");
\r
8789 self._trigger('dragStart', event, filteredUi(ui));
\r
8791 drag: function(event, ui) {
\r
8792 self._trigger('drag', event, filteredUi(ui));
\r
8794 stop: function(event, ui) {
\r
8795 options.position = [ui.position.left - doc.scrollLeft(),
\r
8796 ui.position.top - doc.scrollTop()];
\r
8797 $(this).removeClass("ui-dialog-dragging").height(heightBeforeDrag);
\r
8798 self._trigger('dragStop', event, filteredUi(ui));
\r
8799 $.ui.dialog.overlay.resize();
\r
8804 _makeResizable: function(handles) {
\r
8805 handles = (handles === undefined ? this.options.resizable : handles);
\r
8807 options = self.options,
\r
8808 // .ui-resizable has position: relative defined in the stylesheet
\r
8809 // but dialogs have to use absolute or fixed positioning
\r
8810 position = self.uiDialog.css('position'),
\r
8811 resizeHandles = (typeof handles === 'string' ?
\r
8813 'n,e,s,w,se,sw,ne,nw'
\r
8816 function filteredUi(ui) {
\r
8818 originalPosition: ui.originalPosition,
\r
8819 originalSize: ui.originalSize,
\r
8820 position: ui.position,
\r
8825 self.uiDialog.resizable({
\r
8826 cancel: '.ui-dialog-content',
\r
8827 containment: 'document',
\r
8828 alsoResize: self.element,
\r
8829 maxWidth: options.maxWidth,
\r
8830 maxHeight: options.maxHeight,
\r
8831 minWidth: options.minWidth,
\r
8832 minHeight: self._minHeight(),
\r
8833 handles: resizeHandles,
\r
8834 start: function(event, ui) {
\r
8835 $(this).addClass("ui-dialog-resizing");
\r
8836 self._trigger('resizeStart', event, filteredUi(ui));
\r
8838 resize: function(event, ui) {
\r
8839 self._trigger('resize', event, filteredUi(ui));
\r
8841 stop: function(event, ui) {
\r
8842 $(this).removeClass("ui-dialog-resizing");
\r
8843 options.height = $(this).height();
\r
8844 options.width = $(this).width();
\r
8845 self._trigger('resizeStop', event, filteredUi(ui));
\r
8846 $.ui.dialog.overlay.resize();
\r
8849 .css('position', position)
\r
8850 .find('.ui-resizable-se').addClass('ui-icon ui-icon-grip-diagonal-se');
\r
8853 _minHeight: function() {
\r
8854 var options = this.options;
\r
8856 if (options.height === 'auto') {
\r
8857 return options.minHeight;
\r
8859 return Math.min(options.minHeight, options.height);
\r
8863 _position: function(position) {
\r
8868 position = position || $.ui.dialog.prototype.options.position;
\r
8870 // deep extending converts arrays to objects in jQuery <= 1.3.2 :-(
\r
8871 // if (typeof position == 'string' || $.isArray(position)) {
\r
8872 // myAt = $.isArray(position) ? position : position.split(' ');
\r
8874 if (typeof position === 'string' || (typeof position === 'object' && '0' in position)) {
\r
8875 myAt = position.split ? position.split(' ') : [position[0], position[1]];
\r
8876 if (myAt.length === 1) {
\r
8877 myAt[1] = myAt[0];
\r
8880 $.each(['left', 'top'], function(i, offsetPosition) {
\r
8881 if (+myAt[i] === myAt[i]) {
\r
8882 offset[i] = myAt[i];
\r
8883 myAt[i] = offsetPosition;
\r
8886 } else if (typeof position === 'object') {
\r
8887 if ('left' in position) {
\r
8889 offset[0] = position.left;
\r
8890 } else if ('right' in position) {
\r
8891 myAt[0] = 'right';
\r
8892 offset[0] = -position.right;
\r
8895 if ('top' in position) {
\r
8897 offset[1] = position.top;
\r
8898 } else if ('bottom' in position) {
\r
8899 myAt[1] = 'bottom';
\r
8900 offset[1] = -position.bottom;
\r
8904 // need to show the dialog to get the actual offset in the position plugin
\r
8905 isVisible = this.uiDialog.is(':visible');
\r
8907 this.uiDialog.show();
\r
8910 // workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781
\r
8911 .css({ top: 0, left: 0 })
\r
8913 my: myAt.join(' '),
\r
8914 at: myAt.join(' '),
\r
8915 offset: offset.join(' '),
\r
8918 // ensure that the titlebar is never outside the document
\r
8919 using: function(pos) {
\r
8920 var topOffset = $(this).css(pos).offset().top;
\r
8921 if (topOffset < 0) {
\r
8922 $(this).css('top', pos.top - topOffset);
\r
8927 this.uiDialog.hide();
\r
8931 _setOption: function(key, value){
\r
8933 uiDialog = self.uiDialog,
\r
8934 isResizable = uiDialog.is(':data(resizable)'),
\r
8938 //handling of deprecated beforeclose (vs beforeClose) option
\r
8939 //Ticket #4669 http://dev.jqueryui.com/ticket/4669
\r
8940 //TODO: remove in 1.9pre
\r
8941 case "beforeclose":
\r
8942 key = "beforeClose";
\r
8945 self._createButtons(value);
\r
8948 // convert whatever was passed in to a string, for text() to not throw up
\r
8949 self.uiDialogTitlebarCloseText.text("" + value);
\r
8951 case "dialogClass":
\r
8953 .removeClass(self.options.dialogClass)
\r
8954 .addClass(uiDialogClasses + value);
\r
8958 uiDialog.addClass('ui-dialog-disabled');
\r
8960 uiDialog.removeClass('ui-dialog-disabled');
\r
8965 self._makeDraggable();
\r
8967 uiDialog.draggable('destroy');
\r
8974 if (isResizable) {
\r
8975 uiDialog.resizable('option', 'maxHeight', value);
\r
8980 if (isResizable) {
\r
8981 uiDialog.resizable('option', 'maxWidth', value);
\r
8986 if (isResizable) {
\r
8987 uiDialog.resizable('option', 'minHeight', value);
\r
8992 if (isResizable) {
\r
8993 uiDialog.resizable('option', 'minWidth', value);
\r
8998 self._position(value);
\r
9001 // currently resizable, becoming non-resizable
\r
9002 if (isResizable && !value) {
\r
9003 uiDialog.resizable('destroy');
\r
9006 // currently resizable, changing handles
\r
9007 if (isResizable && typeof value === 'string') {
\r
9008 uiDialog.resizable('option', 'handles', value);
\r
9011 // currently non-resizable, becoming resizable
\r
9012 if (!isResizable && value !== false) {
\r
9013 self._makeResizable(value);
\r
9017 // convert whatever was passed in o a string, for html() to not throw up
\r
9018 $(".ui-dialog-title", self.uiDialogTitlebar).html("" + (value || ' '));
\r
9025 $.Widget.prototype._setOption.apply(self, arguments);
\r
9031 _size: function() {
\r
9032 /* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
\r
9033 * divs will both have width and height set, so we need to reset them
\r
9035 var options = this.options,
\r
9038 // reset content sizing
\r
9039 // hide for non content measurement because height: 0 doesn't work in IE quirks mode (see #4350)
\r
9040 this.element.css('width', 'auto')
\r
9043 // reset wrapper sizing
\r
9044 // determine the height of all the non-content elements
\r
9045 nonContentHeight = this.uiDialog.css({
\r
9047 width: options.width
\r
9052 .css(options.height === 'auto' ? {
\r
9053 minHeight: Math.max(options.minHeight - nonContentHeight, 0),
\r
9057 height: Math.max(options.height - nonContentHeight, 0)
\r
9061 if (this.uiDialog.is(':data(resizable)')) {
\r
9062 this.uiDialog.resizable('option', 'minHeight', this._minHeight());
\r
9067 $.extend($.ui.dialog, {
\r
9073 getTitleId: function($el) {
\r
9074 var id = $el.attr('id');
\r
9079 return 'ui-dialog-title-' + id;
\r
9082 overlay: function(dialog) {
\r
9083 this.$el = $.ui.dialog.overlay.create(dialog);
\r
9087 $.extend($.ui.dialog.overlay, {
\r
9089 // reuse old instances due to IE memory leak with alpha transparency (see #5185)
\r
9092 events: $.map('focus,mousedown,mouseup,keydown,keypress,click'.split(','),
\r
9093 function(event) { return event + '.dialog-overlay'; }).join(' '),
\r
9094 create: function(dialog) {
\r
9095 if (this.instances.length === 0) {
\r
9096 // prevent use of anchors and inputs
\r
9097 // we use a setTimeout in case the overlay is created from an
\r
9098 // event that we're going to be cancelling (see #2804)
\r
9099 setTimeout(function() {
\r
9100 // handle $(el).dialog().dialog('close') (see #4065)
\r
9101 if ($.ui.dialog.overlay.instances.length) {
\r
9102 $(document).bind($.ui.dialog.overlay.events, function(event) {
\r
9103 // stop events if the z-index of the target is < the z-index of the overlay
\r
9104 return ($(event.target).zIndex() >= $.ui.dialog.overlay.maxZ);
\r
9109 // allow closing by pressing the escape key
\r
9110 $(document).bind('keydown.dialog-overlay', function(event) {
\r
9111 if (dialog.options.closeOnEscape && event.keyCode &&
\r
9112 event.keyCode === $.ui.keyCode.ESCAPE) {
\r
9114 dialog.close(event);
\r
9115 event.preventDefault();
\r
9119 // handle window resize
\r
9120 $(window).bind('resize.dialog-overlay', $.ui.dialog.overlay.resize);
\r
9123 var $el = (this.oldInstances.pop() || $('<div></div>').addClass('ui-widget-overlay'))
\r
9124 .appendTo(document.body)
\r
9126 width: this.width(),
\r
9127 height: this.height()
\r
9130 if ($.fn.bgiframe) {
\r
9134 this.instances.push($el);
\r
9138 destroy: function($el) {
\r
9139 this.oldInstances.push(this.instances.splice($.inArray($el, this.instances), 1)[0]);
\r
9141 if (this.instances.length === 0) {
\r
9142 $([document, window]).unbind('.dialog-overlay');
\r
9147 // adjust the maxZ to allow other modal dialogs to continue to work (see #4309)
\r
9149 $.each(this.instances, function() {
\r
9150 maxZ = Math.max(maxZ, this.css('z-index'));
\r
9155 height: function() {
\r
9159 if ($.browser.msie && $.browser.version < 7) {
\r
9160 scrollHeight = Math.max(
\r
9161 document.documentElement.scrollHeight,
\r
9162 document.body.scrollHeight
\r
9164 offsetHeight = Math.max(
\r
9165 document.documentElement.offsetHeight,
\r
9166 document.body.offsetHeight
\r
9169 if (scrollHeight < offsetHeight) {
\r
9170 return $(window).height() + 'px';
\r
9172 return scrollHeight + 'px';
\r
9174 // handle "good" browsers
\r
9176 return $(document).height() + 'px';
\r
9180 width: function() {
\r
9184 if ($.browser.msie && $.browser.version < 7) {
\r
9185 scrollWidth = Math.max(
\r
9186 document.documentElement.scrollWidth,
\r
9187 document.body.scrollWidth
\r
9189 offsetWidth = Math.max(
\r
9190 document.documentElement.offsetWidth,
\r
9191 document.body.offsetWidth
\r
9194 if (scrollWidth < offsetWidth) {
\r
9195 return $(window).width() + 'px';
\r
9197 return scrollWidth + 'px';
\r
9199 // handle "good" browsers
\r
9201 return $(document).width() + 'px';
\r
9205 resize: function() {
\r
9206 /* If the dialog is draggable and the user drags it past the
\r
9207 * right edge of the window, the document becomes wider so we
\r
9208 * need to stretch the overlay. If the user then drags the
\r
9209 * dialog back to the left, the document will become narrower,
\r
9210 * so we need to shrink the overlay to the appropriate size.
\r
9211 * This is handled by shrinking the overlay before setting it
\r
9212 * to the full document size.
\r
9214 var $overlays = $([]);
\r
9215 $.each($.ui.dialog.overlay.instances, function() {
\r
9216 $overlays = $overlays.add(this);
\r
9223 width: $.ui.dialog.overlay.width(),
\r
9224 height: $.ui.dialog.overlay.height()
\r
9229 $.extend($.ui.dialog.overlay.prototype, {
\r
9230 destroy: function() {
\r
9231 $.ui.dialog.overlay.destroy(this.$el);
\r
9237 * jQuery UI Position 1.8
\r
9239 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
9240 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
9241 * and GPL (GPL-LICENSE.txt) licenses.
\r
9243 * http://docs.jquery.com/UI/Position
\r
9247 $.ui = $.ui || {};
\r
9249 var horizontalPositions = /left|center|right/,
\r
9250 horizontalDefault = "center",
\r
9251 verticalPositions = /top|center|bottom/,
\r
9252 verticalDefault = "center",
\r
9253 _position = $.fn.position,
\r
9254 _offset = $.fn.offset;
\r
9256 $.fn.position = function( options ) {
\r
9257 if ( !options || !options.of ) {
\r
9258 return _position.apply( this, arguments );
\r
9261 // make a copy, we don't want to modify arguments
\r
9262 options = $.extend( {}, options );
\r
9264 var target = $( options.of ),
\r
9265 collision = ( options.collision || "flip" ).split( " " ),
\r
9266 offset = options.offset ? options.offset.split( " " ) : [ 0, 0 ],
\r
9271 if ( options.of.nodeType === 9 ) {
\r
9272 targetWidth = target.width();
\r
9273 targetHeight = target.height();
\r
9274 basePosition = { top: 0, left: 0 };
\r
9275 } else if ( options.of.scrollTo && options.of.document ) {
\r
9276 targetWidth = target.width();
\r
9277 targetHeight = target.height();
\r
9278 basePosition = { top: target.scrollTop(), left: target.scrollLeft() };
\r
9279 } else if ( options.of.preventDefault ) {
\r
9280 // force left top to allow flipping
\r
9281 options.at = "left top";
\r
9282 targetWidth = targetHeight = 0;
\r
9283 basePosition = { top: options.of.pageY, left: options.of.pageX };
\r
9285 targetWidth = target.outerWidth();
\r
9286 targetHeight = target.outerHeight();
\r
9287 basePosition = target.offset();
\r
9290 // force my and at to have valid horizontal and veritcal positions
\r
9291 // if a value is missing or invalid, it will be converted to center
\r
9292 $.each( [ "my", "at" ], function() {
\r
9293 var pos = ( options[this] || "" ).split( " " );
\r
9294 if ( pos.length === 1) {
\r
9295 pos = horizontalPositions.test( pos[0] ) ?
\r
9296 pos.concat( [verticalDefault] ) :
\r
9297 verticalPositions.test( pos[0] ) ?
\r
9298 [ horizontalDefault ].concat( pos ) :
\r
9299 [ horizontalDefault, verticalDefault ];
\r
9301 pos[ 0 ] = horizontalPositions.test( pos[0] ) ? pos[ 0 ] : horizontalDefault;
\r
9302 pos[ 1 ] = verticalPositions.test( pos[1] ) ? pos[ 1 ] : verticalDefault;
\r
9303 options[ this ] = pos;
\r
9306 // normalize collision option
\r
9307 if ( collision.length === 1 ) {
\r
9308 collision[ 1 ] = collision[ 0 ];
\r
9311 // normalize offset option
\r
9312 offset[ 0 ] = parseInt( offset[0], 10 ) || 0;
\r
9313 if ( offset.length === 1 ) {
\r
9314 offset[ 1 ] = offset[ 0 ];
\r
9316 offset[ 1 ] = parseInt( offset[1], 10 ) || 0;
\r
9318 if ( options.at[0] === "right" ) {
\r
9319 basePosition.left += targetWidth;
\r
9320 } else if (options.at[0] === horizontalDefault ) {
\r
9321 basePosition.left += targetWidth / 2;
\r
9324 if ( options.at[1] === "bottom" ) {
\r
9325 basePosition.top += targetHeight;
\r
9326 } else if ( options.at[1] === verticalDefault ) {
\r
9327 basePosition.top += targetHeight / 2;
\r
9330 basePosition.left += offset[ 0 ];
\r
9331 basePosition.top += offset[ 1 ];
\r
9333 return this.each(function() {
\r
9334 var elem = $( this ),
\r
9335 elemWidth = elem.outerWidth(),
\r
9336 elemHeight = elem.outerHeight(),
\r
9337 position = $.extend( {}, basePosition );
\r
9339 if ( options.my[0] === "right" ) {
\r
9340 position.left -= elemWidth;
\r
9341 } else if ( options.my[0] === horizontalDefault ) {
\r
9342 position.left -= elemWidth / 2;
\r
9345 if ( options.my[1] === "bottom" ) {
\r
9346 position.top -= elemHeight;
\r
9347 } else if ( options.my[1] === verticalDefault ) {
\r
9348 position.top -= elemHeight / 2;
\r
9351 $.each( [ "left", "top" ], function( i, dir ) {
\r
9352 if ( $.ui.position[ collision[i] ] ) {
\r
9353 $.ui.position[ collision[i] ][ dir ]( position, {
\r
9354 targetWidth: targetWidth,
\r
9355 targetHeight: targetHeight,
\r
9356 elemWidth: elemWidth,
\r
9357 elemHeight: elemHeight,
\r
9365 if ( $.fn.bgiframe ) {
\r
9368 elem.offset( $.extend( position, { using: options.using } ) );
\r
9374 left: function( position, data ) {
\r
9375 var win = $( window ),
\r
9376 over = position.left + data.elemWidth - win.width() - win.scrollLeft();
\r
9377 position.left = over > 0 ? position.left - over : Math.max( 0, position.left );
\r
9379 top: function( position, data ) {
\r
9380 var win = $( window ),
\r
9381 over = position.top + data.elemHeight - win.height() - win.scrollTop();
\r
9382 position.top = over > 0 ? position.top - over : Math.max( 0, position.top );
\r
9387 left: function( position, data ) {
\r
9388 if ( data.at[0] === "center" ) {
\r
9391 var win = $( window ),
\r
9392 over = position.left + data.elemWidth - win.width() - win.scrollLeft(),
\r
9393 myOffset = data.my[ 0 ] === "left" ?
\r
9395 data.my[ 0 ] === "right" ?
\r
9398 offset = -2 * data.offset[ 0 ];
\r
9399 position.left += position.left < 0 ?
\r
9400 myOffset + data.targetWidth + offset :
\r
9402 myOffset - data.targetWidth + offset :
\r
9405 top: function( position, data ) {
\r
9406 if ( data.at[1] === "center" ) {
\r
9409 var win = $( window ),
\r
9410 over = position.top + data.elemHeight - win.height() - win.scrollTop(),
\r
9411 myOffset = data.my[ 1 ] === "top" ?
\r
9412 -data.elemHeight :
\r
9413 data.my[ 1 ] === "bottom" ?
\r
9416 atOffset = data.at[ 1 ] === "top" ?
\r
9417 data.targetHeight :
\r
9418 -data.targetHeight,
\r
9419 offset = -2 * data.offset[ 1 ];
\r
9420 position.top += position.top < 0 ?
\r
9421 myOffset + data.targetHeight + offset :
\r
9423 myOffset + atOffset + offset :
\r
9429 // offset setter from jQuery 1.4
\r
9430 if ( !$.offset.setOffset ) {
\r
9431 $.offset.setOffset = function( elem, options ) {
\r
9432 // set position first, in-case top/left are set even on static elem
\r
9433 if ( /static/.test( $.curCSS( elem, "position" ) ) ) {
\r
9434 elem.style.position = "relative";
\r
9436 var curElem = $( elem ),
\r
9437 curOffset = curElem.offset(),
\r
9438 curTop = parseInt( $.curCSS( elem, "top", true ), 10 ) || 0,
\r
9439 curLeft = parseInt( $.curCSS( elem, "left", true ), 10) || 0,
\r
9441 top: (options.top - curOffset.top) + curTop,
\r
9442 left: (options.left - curOffset.left) + curLeft
\r
9445 if ( 'using' in options ) {
\r
9446 options.using.call( elem, props );
\r
9448 curElem.css( props );
\r
9452 $.fn.offset = function( options ) {
\r
9453 var elem = this[ 0 ];
\r
9454 if ( !elem || !elem.ownerDocument ) { return null; }
\r
9456 return this.each(function() {
\r
9457 $.offset.setOffset( this, options );
\r
9460 return _offset.call( this );
\r
9466 * jQuery UI Progressbar 1.8
\r
9468 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
9469 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
9470 * and GPL (GPL-LICENSE.txt) licenses.
\r
9472 * http://docs.jquery.com/UI/Progressbar
\r
9475 * jquery.ui.core.js
\r
9476 * jquery.ui.widget.js
\r
9480 $.widget( "ui.progressbar", {
\r
9484 _create: function() {
\r
9486 .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
\r
9488 role: "progressbar",
\r
9489 "aria-valuemin": this._valueMin(),
\r
9490 "aria-valuemax": this._valueMax(),
\r
9491 "aria-valuenow": this._value()
\r
9494 this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
\r
9495 .appendTo( this.element );
\r
9497 this._refreshValue();
\r
9500 destroy: function() {
\r
9502 .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
\r
9503 .removeAttr( "role" )
\r
9504 .removeAttr( "aria-valuemin" )
\r
9505 .removeAttr( "aria-valuemax" )
\r
9506 .removeAttr( "aria-valuenow" );
\r
9508 this.valueDiv.remove();
\r
9510 $.Widget.prototype.destroy.apply( this, arguments );
\r
9513 value: function( newValue ) {
\r
9514 if ( newValue === undefined ) {
\r
9515 return this._value();
\r
9518 this._setOption( "value", newValue );
\r
9522 _setOption: function( key, value ) {
\r
9525 this.options.value = value;
\r
9526 this._refreshValue();
\r
9527 this._trigger( "change" );
\r
9531 $.Widget.prototype._setOption.apply( this, arguments );
\r
9534 _value: function() {
\r
9535 var val = this.options.value;
\r
9536 // normalize invalid value
\r
9537 if ( typeof val !== "number" ) {
\r
9540 if ( val < this._valueMin() ) {
\r
9541 val = this._valueMin();
\r
9543 if ( val > this._valueMax() ) {
\r
9544 val = this._valueMax();
\r
9550 _valueMin: function() {
\r
9554 _valueMax: function() {
\r
9558 _refreshValue: function() {
\r
9559 var value = this.value();
\r
9561 [ value === this._valueMax() ? "addClass" : "removeClass"]( "ui-corner-right" )
\r
9562 .width( value + "%" );
\r
9563 this.element.attr( "aria-valuenow", value );
\r
9567 $.extend( $.ui.progressbar, {
\r
9573 * jQuery UI Slider 1.8
\r
9575 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
9576 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
9577 * and GPL (GPL-LICENSE.txt) licenses.
\r
9579 * http://docs.jquery.com/UI/Slider
\r
9582 * jquery.ui.core.js
\r
9583 * jquery.ui.mouse.js
\r
9584 * jquery.ui.widget.js
\r
9589 // number of pages in a slider
\r
9590 // (how many times can you page up/down to go through the whole range)
\r
9593 $.widget("ui.slider", $.ui.mouse, {
\r
9594 widgetEventPrefix: "slide",
\r
9600 orientation: 'horizontal',
\r
9606 _create: function() {
\r
9608 var self = this, o = this.options;
\r
9609 this._keySliding = false;
\r
9610 this._mouseSliding = false;
\r
9611 this._animateOff = true;
\r
9612 this._handleIndex = null;
\r
9613 this._detectOrientation();
\r
9614 this._mouseInit();
\r
9617 .addClass("ui-slider"
\r
9618 + " ui-slider-" + this.orientation
\r
9620 + " ui-widget-content"
\r
9621 + " ui-corner-all");
\r
9624 this.element.addClass('ui-slider-disabled ui-disabled');
\r
9627 this.range = $([]);
\r
9631 if (o.range === true) {
\r
9632 this.range = $('<div></div>');
\r
9633 if (!o.values) o.values = [this._valueMin(), this._valueMin()];
\r
9634 if (o.values.length && o.values.length != 2) {
\r
9635 o.values = [o.values[0], o.values[0]];
\r
9638 this.range = $('<div></div>');
\r
9642 .appendTo(this.element)
\r
9643 .addClass("ui-slider-range");
\r
9645 if (o.range == "min" || o.range == "max") {
\r
9646 this.range.addClass("ui-slider-range-" + o.range);
\r
9649 // note: this isn't the most fittingly semantic framework class for this element,
\r
9650 // but worked best visually with a variety of themes
\r
9651 this.range.addClass("ui-widget-header");
\r
9655 if ($(".ui-slider-handle", this.element).length == 0)
\r
9656 $('<a href="#"></a>')
\r
9657 .appendTo(this.element)
\r
9658 .addClass("ui-slider-handle");
\r
9660 if (o.values && o.values.length) {
\r
9661 while ($(".ui-slider-handle", this.element).length < o.values.length)
\r
9662 $('<a href="#"></a>')
\r
9663 .appendTo(this.element)
\r
9664 .addClass("ui-slider-handle");
\r
9667 this.handles = $(".ui-slider-handle", this.element)
\r
9668 .addClass("ui-state-default"
\r
9669 + " ui-corner-all");
\r
9671 this.handle = this.handles.eq(0);
\r
9673 this.handles.add(this.range).filter("a")
\r
9674 .click(function(event) {
\r
9675 event.preventDefault();
\r
9677 .hover(function() {
\r
9678 if (!o.disabled) {
\r
9679 $(this).addClass('ui-state-hover');
\r
9682 $(this).removeClass('ui-state-hover');
\r
9684 .focus(function() {
\r
9685 if (!o.disabled) {
\r
9686 $(".ui-slider .ui-state-focus").removeClass('ui-state-focus'); $(this).addClass('ui-state-focus');
\r
9691 .blur(function() {
\r
9692 $(this).removeClass('ui-state-focus');
\r
9695 this.handles.each(function(i) {
\r
9696 $(this).data("index.ui-slider-handle", i);
\r
9699 this.handles.keydown(function(event) {
\r
9703 var index = $(this).data("index.ui-slider-handle");
\r
9705 if (self.options.disabled)
\r
9708 switch (event.keyCode) {
\r
9709 case $.ui.keyCode.HOME:
\r
9710 case $.ui.keyCode.END:
\r
9711 case $.ui.keyCode.PAGE_UP:
\r
9712 case $.ui.keyCode.PAGE_DOWN:
\r
9713 case $.ui.keyCode.UP:
\r
9714 case $.ui.keyCode.RIGHT:
\r
9715 case $.ui.keyCode.DOWN:
\r
9716 case $.ui.keyCode.LEFT:
\r
9718 if (!self._keySliding) {
\r
9719 self._keySliding = true;
\r
9720 $(this).addClass("ui-state-active");
\r
9721 self._start(event, index);
\r
9726 var curVal, newVal, step = self._step();
\r
9727 if (self.options.values && self.options.values.length) {
\r
9728 curVal = newVal = self.values(index);
\r
9730 curVal = newVal = self.value();
\r
9733 switch (event.keyCode) {
\r
9734 case $.ui.keyCode.HOME:
\r
9735 newVal = self._valueMin();
\r
9737 case $.ui.keyCode.END:
\r
9738 newVal = self._valueMax();
\r
9740 case $.ui.keyCode.PAGE_UP:
\r
9741 newVal = curVal + ((self._valueMax() - self._valueMin()) / numPages);
\r
9743 case $.ui.keyCode.PAGE_DOWN:
\r
9744 newVal = curVal - ((self._valueMax() - self._valueMin()) / numPages);
\r
9746 case $.ui.keyCode.UP:
\r
9747 case $.ui.keyCode.RIGHT:
\r
9748 if(curVal == self._valueMax()) return;
\r
9749 newVal = curVal + step;
\r
9751 case $.ui.keyCode.DOWN:
\r
9752 case $.ui.keyCode.LEFT:
\r
9753 if(curVal == self._valueMin()) return;
\r
9754 newVal = curVal - step;
\r
9758 self._slide(event, index, newVal);
\r
9762 }).keyup(function(event) {
\r
9764 var index = $(this).data("index.ui-slider-handle");
\r
9766 if (self._keySliding) {
\r
9767 self._keySliding = false;
\r
9768 self._stop(event, index);
\r
9769 self._change(event, index);
\r
9770 $(this).removeClass("ui-state-active");
\r
9775 this._refreshValue();
\r
9777 this._animateOff = false;
\r
9781 destroy: function() {
\r
9783 this.handles.remove();
\r
9784 this.range.remove();
\r
9787 .removeClass("ui-slider"
\r
9788 + " ui-slider-horizontal"
\r
9789 + " ui-slider-vertical"
\r
9790 + " ui-slider-disabled"
\r
9792 + " ui-widget-content"
\r
9793 + " ui-corner-all")
\r
9794 .removeData("slider")
\r
9795 .unbind(".slider");
\r
9797 this._mouseDestroy();
\r
9802 _mouseCapture: function(event) {
\r
9804 var o = this.options;
\r
9809 this.elementSize = {
\r
9810 width: this.element.outerWidth(),
\r
9811 height: this.element.outerHeight()
\r
9813 this.elementOffset = this.element.offset();
\r
9815 var position = { x: event.pageX, y: event.pageY };
\r
9816 var normValue = this._normValueFromMouse(position);
\r
9818 var distance = this._valueMax() - this._valueMin() + 1, closestHandle;
\r
9819 var self = this, index;
\r
9820 this.handles.each(function(i) {
\r
9821 var thisDistance = Math.abs(normValue - self.values(i));
\r
9822 if (distance > thisDistance) {
\r
9823 distance = thisDistance;
\r
9824 closestHandle = $(this);
\r
9829 // workaround for bug #3736 (if both handles of a range are at 0,
\r
9830 // the first is always used as the one with least distance,
\r
9831 // and moving it is obviously prevented by preventing negative ranges)
\r
9832 if(o.range == true && this.values(1) == o.min) {
\r
9833 closestHandle = $(this.handles[++index]);
\r
9836 this._start(event, index);
\r
9837 this._mouseSliding = true;
\r
9839 self._handleIndex = index;
\r
9842 .addClass("ui-state-active")
\r
9845 var offset = closestHandle.offset();
\r
9846 var mouseOverHandle = !$(event.target).parents().andSelf().is('.ui-slider-handle');
\r
9847 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
\r
9848 left: event.pageX - offset.left - (closestHandle.width() / 2),
\r
9849 top: event.pageY - offset.top
\r
9850 - (closestHandle.height() / 2)
\r
9851 - (parseInt(closestHandle.css('borderTopWidth'),10) || 0)
\r
9852 - (parseInt(closestHandle.css('borderBottomWidth'),10) || 0)
\r
9853 + (parseInt(closestHandle.css('marginTop'),10) || 0)
\r
9856 normValue = this._normValueFromMouse(position);
\r
9857 this._slide(event, index, normValue);
\r
9858 this._animateOff = true;
\r
9863 _mouseStart: function(event) {
\r
9867 _mouseDrag: function(event) {
\r
9869 var position = { x: event.pageX, y: event.pageY };
\r
9870 var normValue = this._normValueFromMouse(position);
\r
9872 this._slide(event, this._handleIndex, normValue);
\r
9878 _mouseStop: function(event) {
\r
9880 this.handles.removeClass("ui-state-active");
\r
9881 this._mouseSliding = false;
\r
9882 this._stop(event, this._handleIndex);
\r
9883 this._change(event, this._handleIndex);
\r
9884 this._handleIndex = null;
\r
9885 this._clickOffset = null;
\r
9887 this._animateOff = false;
\r
9892 _detectOrientation: function() {
\r
9893 this.orientation = this.options.orientation == 'vertical' ? 'vertical' : 'horizontal';
\r
9896 _normValueFromMouse: function(position) {
\r
9898 var pixelTotal, pixelMouse;
\r
9899 if ('horizontal' == this.orientation) {
\r
9900 pixelTotal = this.elementSize.width;
\r
9901 pixelMouse = position.x - this.elementOffset.left - (this._clickOffset ? this._clickOffset.left : 0);
\r
9903 pixelTotal = this.elementSize.height;
\r
9904 pixelMouse = position.y - this.elementOffset.top - (this._clickOffset ? this._clickOffset.top : 0);
\r
9907 var percentMouse = (pixelMouse / pixelTotal);
\r
9908 if (percentMouse > 1) percentMouse = 1;
\r
9909 if (percentMouse < 0) percentMouse = 0;
\r
9910 if ('vertical' == this.orientation)
\r
9911 percentMouse = 1 - percentMouse;
\r
9913 var valueTotal = this._valueMax() - this._valueMin(),
\r
9914 valueMouse = percentMouse * valueTotal,
\r
9915 valueMouseModStep = valueMouse % this.options.step,
\r
9916 normValue = this._valueMin() + valueMouse - valueMouseModStep;
\r
9918 if (valueMouseModStep > (this.options.step / 2))
\r
9919 normValue += this.options.step;
\r
9921 // Since JavaScript has problems with large floats, round
\r
9922 // the final value to 5 digits after the decimal point (see #4124)
\r
9923 return parseFloat(normValue.toFixed(5));
\r
9927 _start: function(event, index) {
\r
9929 handle: this.handles[index],
\r
9930 value: this.value()
\r
9932 if (this.options.values && this.options.values.length) {
\r
9933 uiHash.value = this.values(index);
\r
9934 uiHash.values = this.values();
\r
9936 this._trigger("start", event, uiHash);
\r
9939 _slide: function(event, index, newVal) {
\r
9941 var handle = this.handles[index];
\r
9943 if (this.options.values && this.options.values.length) {
\r
9945 var otherVal = this.values(index ? 0 : 1);
\r
9947 if ((this.options.values.length == 2 && this.options.range === true) &&
\r
9948 ((index == 0 && newVal > otherVal) || (index == 1 && newVal < otherVal))){
\r
9949 newVal = otherVal;
\r
9952 if (newVal != this.values(index)) {
\r
9953 var newValues = this.values();
\r
9954 newValues[index] = newVal;
\r
9955 // A slide can be canceled by returning false from the slide callback
\r
9956 var allowed = this._trigger("slide", event, {
\r
9957 handle: this.handles[index],
\r
9961 var otherVal = this.values(index ? 0 : 1);
\r
9962 if (allowed !== false) {
\r
9963 this.values(index, newVal, true);
\r
9969 if (newVal != this.value()) {
\r
9970 // A slide can be canceled by returning false from the slide callback
\r
9971 var allowed = this._trigger("slide", event, {
\r
9972 handle: this.handles[index],
\r
9975 if (allowed !== false) {
\r
9976 this.value(newVal);
\r
9985 _stop: function(event, index) {
\r
9987 handle: this.handles[index],
\r
9988 value: this.value()
\r
9990 if (this.options.values && this.options.values.length) {
\r
9991 uiHash.value = this.values(index);
\r
9992 uiHash.values = this.values();
\r
9994 this._trigger("stop", event, uiHash);
\r
9997 _change: function(event, index) {
\r
9998 if (!this._keySliding && !this._mouseSliding) {
\r
10000 handle: this.handles[index],
\r
10001 value: this.value()
\r
10003 if (this.options.values && this.options.values.length) {
\r
10004 uiHash.value = this.values(index);
\r
10005 uiHash.values = this.values();
\r
10007 this._trigger("change", event, uiHash);
\r
10011 value: function(newValue) {
\r
10013 if (arguments.length) {
\r
10014 this.options.value = this._trimValue(newValue);
\r
10015 this._refreshValue();
\r
10016 this._change(null, 0);
\r
10019 return this._value();
\r
10023 values: function(index, newValue) {
\r
10025 if (arguments.length > 1) {
\r
10026 this.options.values[index] = this._trimValue(newValue);
\r
10027 this._refreshValue();
\r
10028 this._change(null, index);
\r
10031 if (arguments.length) {
\r
10032 if ($.isArray(arguments[0])) {
\r
10033 var vals = this.options.values, newValues = arguments[0];
\r
10034 for (var i = 0, l = vals.length; i < l; i++) {
\r
10035 vals[i] = this._trimValue(newValues[i]);
\r
10036 this._change(null, i);
\r
10038 this._refreshValue();
\r
10040 if (this.options.values && this.options.values.length) {
\r
10041 return this._values(index);
\r
10043 return this.value();
\r
10047 return this._values();
\r
10052 _setOption: function(key, value) {
\r
10056 if ( jQuery.isArray(this.options.values) ) {
\r
10057 valsLength = this.options.values.length;
\r
10060 $.Widget.prototype._setOption.apply(this, arguments);
\r
10065 this.handles.filter(".ui-state-focus").blur();
\r
10066 this.handles.removeClass("ui-state-hover");
\r
10067 this.handles.attr("disabled", "disabled");
\r
10068 this.element.addClass("ui-disabled");
\r
10070 this.handles.removeAttr("disabled");
\r
10071 this.element.removeClass("ui-disabled");
\r
10073 case 'orientation':
\r
10075 this._detectOrientation();
\r
10078 .removeClass("ui-slider-horizontal ui-slider-vertical")
\r
10079 .addClass("ui-slider-" + this.orientation);
\r
10080 this._refreshValue();
\r
10083 this._animateOff = true;
\r
10084 this._refreshValue();
\r
10085 this._change(null, 0);
\r
10086 this._animateOff = false;
\r
10089 this._animateOff = true;
\r
10090 this._refreshValue();
\r
10091 for (i = 0; i < valsLength; i++) {
\r
10092 this._change(null, i);
\r
10094 this._animateOff = false;
\r
10100 _step: function() {
\r
10101 var step = this.options.step;
\r
10105 _value: function() {
\r
10106 //internal value getter
\r
10107 // _value() returns value trimmed by min and max
\r
10108 var val = this.options.value;
\r
10109 val = this._trimValue(val);
\r
10114 _values: function(index) {
\r
10115 //internal values getter
\r
10116 // _values() returns array of values trimmed by min and max
\r
10117 // _values(index) returns single value trimmed by min and max
\r
10119 if (arguments.length) {
\r
10120 var val = this.options.values[index];
\r
10121 val = this._trimValue(val);
\r
10125 // .slice() creates a copy of the array
\r
10126 // this copy gets trimmed by min and max and then returned
\r
10127 var vals = this.options.values.slice();
\r
10128 for (var i = 0, l = vals.length; i < l; i++) {
\r
10129 vals[i] = this._trimValue(vals[i]);
\r
10137 _trimValue: function(val) {
\r
10138 if (val < this._valueMin()) val = this._valueMin();
\r
10139 if (val > this._valueMax()) val = this._valueMax();
\r
10144 _valueMin: function() {
\r
10145 var valueMin = this.options.min;
\r
10149 _valueMax: function() {
\r
10150 var valueMax = this.options.max;
\r
10154 _refreshValue: function() {
\r
10156 var oRange = this.options.range, o = this.options, self = this;
\r
10157 var animate = (!this._animateOff) ? o.animate : false;
\r
10159 if (this.options.values && this.options.values.length) {
\r
10161 this.handles.each(function(i, j) {
\r
10162 var valPercent = (self.values(i) - self._valueMin()) / (self._valueMax() - self._valueMin()) * 100;
\r
10163 var _set = {}; _set[self.orientation == 'horizontal' ? 'left' : 'bottom'] = valPercent + '%';
\r
10164 $(this).stop(1,1)[animate ? 'animate' : 'css'](_set, o.animate);
\r
10165 if (self.options.range === true) {
\r
10166 if (self.orientation == 'horizontal') {
\r
10167 (i == 0) && self.range.stop(1,1)[animate ? 'animate' : 'css']({ left: valPercent + '%' }, o.animate);
\r
10168 (i == 1) && self.range[animate ? 'animate' : 'css']({ width: (valPercent - lastValPercent) + '%' }, { queue: false, duration: o.animate });
\r
10170 (i == 0) && self.range.stop(1,1)[animate ? 'animate' : 'css']({ bottom: (valPercent) + '%' }, o.animate);
\r
10171 (i == 1) && self.range[animate ? 'animate' : 'css']({ height: (valPercent - lastValPercent) + '%' }, { queue: false, duration: o.animate });
\r
10174 lastValPercent = valPercent;
\r
10177 var value = this.value(),
\r
10178 valueMin = this._valueMin(),
\r
10179 valueMax = this._valueMax(),
\r
10180 valPercent = valueMax != valueMin
\r
10181 ? (value - valueMin) / (valueMax - valueMin) * 100
\r
10183 var _set = {}; _set[self.orientation == 'horizontal' ? 'left' : 'bottom'] = valPercent + '%';
\r
10184 this.handle.stop(1,1)[animate ? 'animate' : 'css'](_set, o.animate);
\r
10186 (oRange == "min") && (this.orientation == "horizontal") && this.range.stop(1,1)[animate ? 'animate' : 'css']({ width: valPercent + '%' }, o.animate);
\r
10187 (oRange == "max") && (this.orientation == "horizontal") && this.range[animate ? 'animate' : 'css']({ width: (100 - valPercent) + '%' }, { queue: false, duration: o.animate });
\r
10188 (oRange == "min") && (this.orientation == "vertical") && this.range.stop(1,1)[animate ? 'animate' : 'css']({ height: valPercent + '%' }, o.animate);
\r
10189 (oRange == "max") && (this.orientation == "vertical") && this.range[animate ? 'animate' : 'css']({ height: (100 - valPercent) + '%' }, { queue: false, duration: o.animate });
\r
10196 $.extend($.ui.slider, {
\r
10202 * jQuery UI Tabs 1.8
\r
10204 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
\r
10205 * Dual licensed under the MIT (MIT-LICENSE.txt)
\r
10206 * and GPL (GPL-LICENSE.txt) licenses.
\r
10208 * http://docs.jquery.com/UI/Tabs
\r
10211 * jquery.ui.core.js
\r
10212 * jquery.ui.widget.js
\r
10219 $.widget("ui.tabs", {
\r
10222 ajaxOptions: null,
\r
10224 cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
\r
10225 collapsible: false,
\r
10230 fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 }
\r
10231 idPrefix: 'ui-tabs-',
\r
10233 panelTemplate: '<div></div>',
\r
10237 spinner: '<em>Loading…</em>',
\r
10238 tabTemplate: '<li><a href="#{href}"><span>#{label}</span></a></li>'
\r
10240 _create: function() {
\r
10241 this._tabify(true);
\r
10244 _setOption: function(key, value) {
\r
10245 if (key == 'selected') {
\r
10246 if (this.options.collapsible && value == this.options.selected) {
\r
10249 this.select(value);
\r
10252 this.options[key] = value;
\r
10257 _tabId: function(a) {
\r
10258 return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '') ||
\r
10259 this.options.idPrefix + (++tabId);
\r
10262 _sanitizeSelector: function(hash) {
\r
10263 return hash.replace(/:/g, '\\:'); // we need this because an id may contain a ":"
\r
10266 _cookie: function() {
\r
10267 var cookie = this.cookie || (this.cookie = this.options.cookie.name || 'ui-tabs-' + (++listId));
\r
10268 return $.cookie.apply(null, [cookie].concat($.makeArray(arguments)));
\r
10271 _ui: function(tab, panel) {
\r
10275 index: this.anchors.index(tab)
\r
10279 _cleanup: function() {
\r
10280 // restore all former loading tabs labels
\r
10281 this.lis.filter('.ui-state-processing').removeClass('ui-state-processing')
\r
10282 .find('span:data(label.tabs)')
\r
10283 .each(function() {
\r
10284 var el = $(this);
\r
10285 el.html(el.data('label.tabs')).removeData('label.tabs');
\r
10289 _tabify: function(init) {
\r
10291 this.list = this.element.find('ol,ul').eq(0);
\r
10292 this.lis = $('li:has(a[href])', this.list);
\r
10293 this.anchors = this.lis.map(function() { return $('a', this)[0]; });
\r
10294 this.panels = $([]);
\r
10296 var self = this, o = this.options;
\r
10298 var fragmentId = /^#.+/; // Safari 2 reports '#' for an empty hash
\r
10299 this.anchors.each(function(i, a) {
\r
10300 var href = $(a).attr('href');
\r
10302 // For dynamically created HTML that contains a hash as href IE < 8 expands
\r
10303 // such href to the full page url with hash and then misinterprets tab as ajax.
\r
10304 // Same consideration applies for an added tab with a fragment identifier
\r
10305 // since a[href=#fragment-identifier] does unexpectedly not match.
\r
10306 // Thus normalize href attribute...
\r
10307 var hrefBase = href.split('#')[0], baseEl;
\r
10308 if (hrefBase && (hrefBase === location.toString().split('#')[0] ||
\r
10309 (baseEl = $('base')[0]) && hrefBase === baseEl.href)) {
\r
10315 if (fragmentId.test(href)) {
\r
10316 self.panels = self.panels.add(self._sanitizeSelector(href));
\r
10320 else if (href != '#') { // prevent loading the page itself if href is just "#"
\r
10321 $.data(a, 'href.tabs', href); // required for restore on destroy
\r
10323 // TODO until #3808 is fixed strip fragment identifier from url
\r
10324 // (IE fails to load from such url)
\r
10325 $.data(a, 'load.tabs', href.replace(/#.*$/, '')); // mutable data
\r
10327 var id = self._tabId(a);
\r
10328 a.href = '#' + id;
\r
10329 var $panel = $('#' + id);
\r
10330 if (!$panel.length) {
\r
10331 $panel = $(o.panelTemplate).attr('id', id).addClass('ui-tabs-panel ui-widget-content ui-corner-bottom')
\r
10332 .insertAfter(self.panels[i - 1] || self.list);
\r
10333 $panel.data('destroy.tabs', true);
\r
10335 self.panels = self.panels.add($panel);
\r
10338 // invalid tab href
\r
10340 o.disabled.push(i);
\r
10344 // initialization from scratch
\r
10347 // attach necessary classes for styling
\r
10348 this.element.addClass('ui-tabs ui-widget ui-widget-content ui-corner-all');
\r
10349 this.list.addClass('ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all');
\r
10350 this.lis.addClass('ui-state-default ui-corner-top');
\r
10351 this.panels.addClass('ui-tabs-panel ui-widget-content ui-corner-bottom');
\r
10354 // use "selected" option or try to retrieve:
\r
10355 // 1. from fragment identifier in url
\r
10356 // 2. from cookie
\r
10357 // 3. from selected class attribute on <li>
\r
10358 if (o.selected === undefined) {
\r
10359 if (location.hash) {
\r
10360 this.anchors.each(function(i, a) {
\r
10361 if (a.hash == location.hash) {
\r
10363 return false; // break
\r
10367 if (typeof o.selected != 'number' && o.cookie) {
\r
10368 o.selected = parseInt(self._cookie(), 10);
\r
10370 if (typeof o.selected != 'number' && this.lis.filter('.ui-tabs-selected').length) {
\r
10371 o.selected = this.lis.index(this.lis.filter('.ui-tabs-selected'));
\r
10373 o.selected = o.selected || (this.lis.length ? 0 : -1);
\r
10375 else if (o.selected === null) { // usage of null is deprecated, TODO remove in next release
\r
10379 // sanity check - default to first tab...
\r
10380 o.selected = ((o.selected >= 0 && this.anchors[o.selected]) || o.selected < 0) ? o.selected : 0;
\r
10382 // Take disabling tabs via class attribute from HTML
\r
10383 // into account and update option properly.
\r
10384 // A selected tab cannot become disabled.
\r
10385 o.disabled = $.unique(o.disabled.concat(
\r
10386 $.map(this.lis.filter('.ui-state-disabled'),
\r
10387 function(n, i) { return self.lis.index(n); } )
\r
10390 if ($.inArray(o.selected, o.disabled) != -1) {
\r
10391 o.disabled.splice($.inArray(o.selected, o.disabled), 1);
\r
10394 // highlight selected tab
\r
10395 this.panels.addClass('ui-tabs-hide');
\r
10396 this.lis.removeClass('ui-tabs-selected ui-state-active');
\r
10397 if (o.selected >= 0 && this.anchors.length) { // check for length avoids error when initializing empty list
\r
10398 this.panels.eq(o.selected).removeClass('ui-tabs-hide');
\r
10399 this.lis.eq(o.selected).addClass('ui-tabs-selected ui-state-active');
\r
10401 // seems to be expected behavior that the show callback is fired
\r
10402 self.element.queue("tabs", function() {
\r
10403 self._trigger('show', null, self._ui(self.anchors[o.selected], self.panels[o.selected]));
\r
10406 this.load(o.selected);
\r
10409 // clean up to avoid memory leaks in certain versions of IE 6
\r
10410 $(window).bind('unload', function() {
\r
10411 self.lis.add(self.anchors).unbind('.tabs');
\r
10412 self.lis = self.anchors = self.panels = null;
\r
10416 // update selected after add/remove
\r
10418 o.selected = this.lis.index(this.lis.filter('.ui-tabs-selected'));
\r
10421 // update collapsible
\r
10422 this.element[o.collapsible ? 'addClass' : 'removeClass']('ui-tabs-collapsible');
\r
10424 // set or update cookie after init and add/remove respectively
\r
10426 this._cookie(o.selected, o.cookie);
\r
10430 for (var i = 0, li; (li = this.lis[i]); i++) {
\r
10431 $(li)[$.inArray(i, o.disabled) != -1 &&
\r
10432 !$(li).hasClass('ui-tabs-selected') ? 'addClass' : 'removeClass']('ui-state-disabled');
\r
10435 // reset cache if switching from cached to not cached
\r
10436 if (o.cache === false) {
\r
10437 this.anchors.removeData('cache.tabs');
\r
10440 // remove all handlers before, tabify may run on existing tabs after add or option change
\r
10441 this.lis.add(this.anchors).unbind('.tabs');
\r
10443 if (o.event != 'mouseover') {
\r
10444 var addState = function(state, el) {
\r
10445 if (el.is(':not(.ui-state-disabled)')) {
\r
10446 el.addClass('ui-state-' + state);
\r
10449 var removeState = function(state, el) {
\r
10450 el.removeClass('ui-state-' + state);
\r
10452 this.lis.bind('mouseover.tabs', function() {
\r
10453 addState('hover', $(this));
\r
10455 this.lis.bind('mouseout.tabs', function() {
\r
10456 removeState('hover', $(this));
\r
10458 this.anchors.bind('focus.tabs', function() {
\r
10459 addState('focus', $(this).closest('li'));
\r
10461 this.anchors.bind('blur.tabs', function() {
\r
10462 removeState('focus', $(this).closest('li'));
\r
10466 // set up animations
\r
10467 var hideFx, showFx;
\r
10469 if ($.isArray(o.fx)) {
\r
10470 hideFx = o.fx[0];
\r
10471 showFx = o.fx[1];
\r
10474 hideFx = showFx = o.fx;
\r
10478 // Reset certain styles left over from animation
\r
10479 // and prevent IE's ClearType bug...
\r
10480 function resetStyle($el, fx) {
\r
10481 $el.css({ display: '' });
\r
10482 if (!$.support.opacity && fx.opacity) {
\r
10483 $el[0].style.removeAttribute('filter');
\r
10488 var showTab = showFx ?
\r
10489 function(clicked, $show) {
\r
10490 $(clicked).closest('li').addClass('ui-tabs-selected ui-state-active');
\r
10491 $show.hide().removeClass('ui-tabs-hide') // avoid flicker that way
\r
10492 .animate(showFx, showFx.duration || 'normal', function() {
\r
10493 resetStyle($show, showFx);
\r
10494 self._trigger('show', null, self._ui(clicked, $show[0]));
\r
10497 function(clicked, $show) {
\r
10498 $(clicked).closest('li').addClass('ui-tabs-selected ui-state-active');
\r
10499 $show.removeClass('ui-tabs-hide');
\r
10500 self._trigger('show', null, self._ui(clicked, $show[0]));
\r
10503 // Hide a tab, $show is optional...
\r
10504 var hideTab = hideFx ?
\r
10505 function(clicked, $hide) {
\r
10506 $hide.animate(hideFx, hideFx.duration || 'normal', function() {
\r
10507 self.lis.removeClass('ui-tabs-selected ui-state-active');
\r
10508 $hide.addClass('ui-tabs-hide');
\r
10509 resetStyle($hide, hideFx);
\r
10510 self.element.dequeue("tabs");
\r
10513 function(clicked, $hide, $show) {
\r
10514 self.lis.removeClass('ui-tabs-selected ui-state-active');
\r
10515 $hide.addClass('ui-tabs-hide');
\r
10516 self.element.dequeue("tabs");
\r
10519 // attach tab event handler, unbind to avoid duplicates from former tabifying...
\r
10520 this.anchors.bind(o.event + '.tabs', function() {
\r
10521 var el = this, $li = $(this).closest('li'), $hide = self.panels.filter(':not(.ui-tabs-hide)'),
\r
10522 $show = $(self._sanitizeSelector(this.hash));
\r
10524 // If tab is already selected and not collapsible or tab disabled or
\r
10525 // or is already loading or click callback returns false stop here.
\r
10526 // Check if click handler returns false last so that it is not executed
\r
10527 // for a disabled or loading tab!
\r
10528 if (($li.hasClass('ui-tabs-selected') && !o.collapsible) ||
\r
10529 $li.hasClass('ui-state-disabled') ||
\r
10530 $li.hasClass('ui-state-processing') ||
\r
10531 self._trigger('select', null, self._ui(this, $show[0])) === false) {
\r
10536 o.selected = self.anchors.index(this);
\r
10540 // if tab may be closed
\r
10541 if (o.collapsible) {
\r
10542 if ($li.hasClass('ui-tabs-selected')) {
\r
10546 self._cookie(o.selected, o.cookie);
\r
10549 self.element.queue("tabs", function() {
\r
10550 hideTab(el, $hide);
\r
10551 }).dequeue("tabs");
\r
10556 else if (!$hide.length) {
\r
10558 self._cookie(o.selected, o.cookie);
\r
10561 self.element.queue("tabs", function() {
\r
10562 showTab(el, $show);
\r
10565 self.load(self.anchors.index(this)); // TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171
\r
10573 self._cookie(o.selected, o.cookie);
\r
10577 if ($show.length) {
\r
10578 if ($hide.length) {
\r
10579 self.element.queue("tabs", function() {
\r
10580 hideTab(el, $hide);
\r
10583 self.element.queue("tabs", function() {
\r
10584 showTab(el, $show);
\r
10587 self.load(self.anchors.index(this));
\r
10590 throw 'jQuery UI Tabs: Mismatching fragment identifier.';
\r
10593 // Prevent IE from keeping other link focussed when using the back button
\r
10594 // and remove dotted border from clicked link. This is controlled via CSS
\r
10595 // in modern browsers; blur() removes focus from address bar in Firefox
\r
10596 // which can become a usability and annoying problem with tabs('rotate').
\r
10597 if ($.browser.msie) {
\r
10603 // disable click in any case
\r
10604 this.anchors.bind('click.tabs', function(){return false;});
\r
10608 destroy: function() {
\r
10609 var o = this.options;
\r
10613 this.element.unbind('.tabs')
\r
10614 .removeClass('ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible')
\r
10615 .removeData('tabs');
\r
10617 this.list.removeClass('ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all');
\r
10619 this.anchors.each(function() {
\r
10620 var href = $.data(this, 'href.tabs');
\r
10622 this.href = href;
\r
10624 var $this = $(this).unbind('.tabs');
\r
10625 $.each(['href', 'load', 'cache'], function(i, prefix) {
\r
10626 $this.removeData(prefix + '.tabs');
\r
10630 this.lis.unbind('.tabs').add(this.panels).each(function() {
\r
10631 if ($.data(this, 'destroy.tabs')) {
\r
10632 $(this).remove();
\r
10635 $(this).removeClass([
\r
10636 'ui-state-default',
\r
10638 'ui-tabs-selected',
\r
10639 'ui-state-active',
\r
10640 'ui-state-hover',
\r
10641 'ui-state-focus',
\r
10642 'ui-state-disabled',
\r
10644 'ui-widget-content',
\r
10645 'ui-corner-bottom',
\r
10652 this._cookie(null, o.cookie);
\r
10658 add: function(url, label, index) {
\r
10659 if (index === undefined) {
\r
10660 index = this.anchors.length; // append by default
\r
10663 var self = this, o = this.options,
\r
10664 $li = $(o.tabTemplate.replace(/#\{href\}/g, url).replace(/#\{label\}/g, label)),
\r
10665 id = !url.indexOf('#') ? url.replace('#', '') : this._tabId($('a', $li)[0]);
\r
10667 $li.addClass('ui-state-default ui-corner-top').data('destroy.tabs', true);
\r
10669 // try to find an existing element before creating a new one
\r
10670 var $panel = $('#' + id);
\r
10671 if (!$panel.length) {
\r
10672 $panel = $(o.panelTemplate).attr('id', id).data('destroy.tabs', true);
\r
10674 $panel.addClass('ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide');
\r
10676 if (index >= this.lis.length) {
\r
10677 $li.appendTo(this.list);
\r
10678 $panel.appendTo(this.list[0].parentNode);
\r
10681 $li.insertBefore(this.lis[index]);
\r
10682 $panel.insertBefore(this.panels[index]);
\r
10685 o.disabled = $.map(o.disabled,
\r
10686 function(n, i) { return n >= index ? ++n : n; });
\r
10690 if (this.anchors.length == 1) { // after tabify
\r
10692 $li.addClass('ui-tabs-selected ui-state-active');
\r
10693 $panel.removeClass('ui-tabs-hide');
\r
10694 this.element.queue("tabs", function() {
\r
10695 self._trigger('show', null, self._ui(self.anchors[0], self.panels[0]));
\r
10702 this._trigger('add', null, this._ui(this.anchors[index], this.panels[index]));
\r
10706 remove: function(index) {
\r
10707 var o = this.options, $li = this.lis.eq(index).remove(),
\r
10708 $panel = this.panels.eq(index).remove();
\r
10710 // If selected tab was removed focus tab to the right or
\r
10711 // in case the last tab was removed the tab to the left.
\r
10712 if ($li.hasClass('ui-tabs-selected') && this.anchors.length > 1) {
\r
10713 this.select(index + (index + 1 < this.anchors.length ? 1 : -1));
\r
10716 o.disabled = $.map($.grep(o.disabled, function(n, i) { return n != index; }),
\r
10717 function(n, i) { return n >= index ? --n : n; });
\r
10722 this._trigger('remove', null, this._ui($li.find('a')[0], $panel[0]));
\r
10726 enable: function(index) {
\r
10727 var o = this.options;
\r
10728 if ($.inArray(index, o.disabled) == -1) {
\r
10732 this.lis.eq(index).removeClass('ui-state-disabled');
\r
10733 o.disabled = $.grep(o.disabled, function(n, i) { return n != index; });
\r
10736 this._trigger('enable', null, this._ui(this.anchors[index], this.panels[index]));
\r
10740 disable: function(index) {
\r
10741 var self = this, o = this.options;
\r
10742 if (index != o.selected) { // cannot disable already selected tab
\r
10743 this.lis.eq(index).addClass('ui-state-disabled');
\r
10745 o.disabled.push(index);
\r
10746 o.disabled.sort();
\r
10749 this._trigger('disable', null, this._ui(this.anchors[index], this.panels[index]));
\r
10755 select: function(index) {
\r
10756 if (typeof index == 'string') {
\r
10757 index = this.anchors.index(this.anchors.filter('[href$=' + index + ']'));
\r
10759 else if (index === null) { // usage of null is deprecated, TODO remove in next release
\r
10762 if (index == -1 && this.options.collapsible) {
\r
10763 index = this.options.selected;
\r
10766 this.anchors.eq(index).trigger(this.options.event + '.tabs');
\r
10770 load: function(index) {
\r
10771 var self = this, o = this.options, a = this.anchors.eq(index)[0], url = $.data(a, 'load.tabs');
\r
10775 // not remote or from cache
\r
10776 if (!url || this.element.queue("tabs").length !== 0 && $.data(a, 'cache.tabs')) {
\r
10777 this.element.dequeue("tabs");
\r
10781 // load remote from here on
\r
10782 this.lis.eq(index).addClass('ui-state-processing');
\r
10785 var span = $('span', a);
\r
10786 span.data('label.tabs', span.html()).html(o.spinner);
\r
10789 this.xhr = $.ajax($.extend({}, o.ajaxOptions, {
\r
10791 success: function(r, s) {
\r
10792 $(self._sanitizeSelector(a.hash)).html(r);
\r
10794 // take care of tab labels
\r
10798 $.data(a, 'cache.tabs', true); // if loaded once do not load them again
\r
10802 self._trigger('load', null, self._ui(self.anchors[index], self.panels[index]));
\r
10804 o.ajaxOptions.success(r, s);
\r
10808 error: function(xhr, s, e) {
\r
10809 // take care of tab labels
\r
10813 self._trigger('load', null, self._ui(self.anchors[index], self.panels[index]));
\r
10815 // Passing index avoid a race condition when this method is
\r
10816 // called after the user has selected another tab.
\r
10817 // Pass the anchor that initiated this request allows
\r
10818 // loadError to manipulate the tab content panel via $(a.hash)
\r
10819 o.ajaxOptions.error(xhr, s, index, a);
\r
10825 // last, so that load event is fired before show...
\r
10826 self.element.dequeue("tabs");
\r
10831 abort: function() {
\r
10832 // stop possibly running animations
\r
10833 this.element.queue([]);
\r
10834 this.panels.stop(false, true);
\r
10836 // "tabs" queue must not contain more than two elements,
\r
10837 // which are the callbacks for the latest clicked tab...
\r
10838 this.element.queue("tabs", this.element.queue("tabs").splice(-2, 2));
\r
10840 // terminate pending requests from other tabs
\r
10842 this.xhr.abort();
\r
10846 // take care of tab labels
\r
10851 url: function(index, url) {
\r
10852 this.anchors.eq(index).removeData('cache.tabs').data('load.tabs', url);
\r
10856 length: function() {
\r
10857 return this.anchors.length;
\r
10862 $.extend($.ui.tabs, {
\r
10867 * Tabs Extensions
\r
10873 $.extend($.ui.tabs.prototype, {
\r
10875 rotate: function(ms, continuing) {
\r
10877 var self = this, o = this.options;
\r
10879 var rotate = self._rotate || (self._rotate = function(e) {
\r
10880 clearTimeout(self.rotation);
\r
10881 self.rotation = setTimeout(function() {
\r
10882 var t = o.selected;
\r
10883 self.select( ++t < self.anchors.length ? t : 0 );
\r
10887 e.stopPropagation();
\r
10891 var stop = self._unrotate || (self._unrotate = !continuing ?
\r
10893 if (e.clientX) { // in case of a true click
\r
10894 self.rotate(null);
\r
10902 // start rotation
\r
10904 this.element.bind('tabsshow', rotate);
\r
10905 this.anchors.bind(o.event + '.tabs', stop);
\r
10910 clearTimeout(self.rotation);
\r
10911 this.element.unbind('tabsshow', rotate);
\r
10912 this.anchors.unbind(o.event + '.tabs', stop);
\r
10913 delete this._rotate;
\r
10914 delete this._unrotate;
\r