﻿/*
* jQuery UI Draggable
*
* Copyright (c) 2008 Paul Bakaus
* Dual licensed under the MIT (MIT-LICENSE.txt)
* and GPL (GPL-LICENSE.txt) licenses.
* 
* http://docs.jquery.com/UI/Draggables
*
* Depends:
*	ui.core.js
*/
(function($) {

    $.widget("ui.draggable", $.extend({}, $.ui.mouse, {
        init: function() {

            //Initialize needed constants
            var o = this.options;

            //Position the node
            if (o.helper == 'original' && !(/(relative|absolute|fixed)/).test(this.element.css('position')))
                this.element.css('position', 'relative');

            this.element.addClass('ui-draggable');
            (o.disabled && this.element.addClass('ui-draggable-disabled'));

            this.mouseInit();

        },
        mouseStart: function(e) {
            var o = this.options;

            if (this.helper || o.disabled || $(e.target).is('.ui-resizable-handle')) return false;

            var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false;


            $(this.options.handle, this.element).find("*").andSelf().each(function() {
                if (this == e.target) handle = true;
            });
            if (!handle) return false;

            if ($.ui.ddmanager) $.ui.ddmanager.current = this;

            //Create and append the visible helper
            this.helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [e])) : (o.helper == 'clone' ? this.element.clone() : this.element);
            if (!this.helper.parents('body').length) this.helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo));
            if (this.helper[0] != this.element[0] && !(/(fixed|absolute)/).test(this.helper.css("position"))) this.helper.css("position", "absolute");

            /*
            * - Position generation -
            * This block generates everything position related - it's the core of draggables.
            */

            this.margins = {																				//Cache the margins
                left: (parseInt(this.element.css("marginLeft"), 10) || 0),
                top: (parseInt(this.element.css("marginTop"), 10) || 0)
            };

            this.cssPosition = this.helper.css("position"); 												//Store the helper's css position
            this.offset = this.element.offset(); 														//The element's absolute position on the page
            this.offset = {																					//Substract the margins from the element's absolute offset
                top: this.offset.top - this.margins.top,
                left: this.offset.left - this.margins.left
            };

            this.offset.click = {																			//Where the click happened, relative to the element
                left: e.pageX - this.offset.left,
                top: e.pageY - this.offset.top
            };

            this.offsetParent = this.helper.offsetParent(); var po = this.offsetParent.offset(); 		//Get the offsetParent and cache its position
            if (this.offsetParent[0] == document.body && $.browser.mozilla) po = { top: 0, left: 0 }; 	//Ugly FF3 fix
            this.offset.parent = {																			//Store its position plus border
                top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"), 10) || 0),
                left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"), 10) || 0)
            };

            var p = this.element.position(); 															//This is a relative to absolute position minus the actual position calculation - only used for relative positioned helpers
            this.offset.relative = this.cssPosition == "relative" ? {
                top: p.top - (parseInt(this.helper.css("top"), 10) || 0) + this.offsetParent[0].scrollTop,
                left: p.left - (parseInt(this.helper.css("left"), 10) || 0) + this.offsetParent[0].scrollLeft
} : { top: 0, left: 0 };

                this.originalPosition = this.generatePosition(e); 											//Generate the original position
                this.helperProportions = { width: this.helper.outerWidth(), height: this.helper.outerHeight() }; //Cache the helper size

                if (o.cursorAt) {
                    if (o.cursorAt.left != undefined) this.offset.click.left = o.cursorAt.left + this.margins.left;
                    if (o.cursorAt.right != undefined) this.offset.click.left = this.helperProportions.width - o.cursorAt.right + this.margins.left;
                    if (o.cursorAt.top != undefined) this.offset.click.top = o.cursorAt.top + this.margins.top;
                    if (o.cursorAt.bottom != undefined) this.offset.click.top = this.helperProportions.height - o.cursorAt.bottom + this.margins.top;
                }


                /*
                * - Position constraining -
                * Here we prepare position constraining like grid and containment.
                */

                if (o.containment) {
                    if (o.containment == 'parent') o.containment = this.helper[0].parentNode;
                    if (o.containment == 'document' || o.containment == 'window') this.containment = [
				0 - this.offset.relative.left - this.offset.parent.left,
				0 - this.offset.relative.top - this.offset.parent.top,
				$(o.containment == 'document' ? document : window).width() - this.offset.relative.left - this.offset.parent.left - this.helperProportions.width - this.margins.left - (parseInt(this.element.css("marginRight"), 10) || 0),
				($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.offset.relative.top - this.offset.parent.top - this.helperProportions.height - this.margins.top - (parseInt(this.element.css("marginBottom"), 10) || 0)
			];

                    if (!(/^(document|window|parent)$/).test(o.containment)) {
                        var ce = $(o.containment)[0];
                        var co = $(o.containment).offset();

                        this.containment = [
					co.left + (parseInt($(ce).css("borderLeftWidth"), 10) || 0) - this.offset.relative.left - this.offset.parent.left,
					co.top + (parseInt($(ce).css("borderTopWidth"), 10) || 0) - this.offset.relative.top - this.offset.parent.top,
					co.left + Math.max(ce.scrollWidth, ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"), 10) || 0) - this.offset.relative.left - this.offset.parent.left - this.helperProportions.width - this.margins.left - (parseInt(this.element.css("marginRight"), 10) || 0),
					co.top + Math.max(ce.scrollHeight, ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"), 10) || 0) - this.offset.relative.top - this.offset.parent.top - this.helperProportions.height - this.margins.top - (parseInt(this.element.css("marginBottom"), 10) || 0)
				];
                    }
                }

                //Call plugins and callbacks
                this.propagate("start", e);

                this.helperProportions = { width: this.helper.outerWidth(), height: this.helper.outerHeight() }; //Recache the helper size
                if ($.ui.ddmanager && !o.dropBehaviour) $.ui.ddmanager.prepareOffsets(this, e);

                this.helper.addClass("ui-draggable-dragging");
                this.mouseDrag(e); //Execute the drag once - this causes the helper not to be visible before getting its correct position
                return true;
            },
            convertPositionTo: function(d, pos) {
                if (!pos) pos = this.position;
                var mod = d == "absolute" ? 1 : -1;
                return {
                    top: (
				pos.top																	// the calculated relative position
				+ this.offset.relative.top * mod										// Only for relative positioned nodes: Relative offset from element to offset parent
				+ this.offset.parent.top * mod											// The offsetParent's offset without borders (offset + border)
				- (this.cssPosition == "fixed" || (this.cssPosition == "absolute" && this.offsetParent[0] == document.body) ? 0 : this.offsetParent[0].scrollTop) * mod	// The offsetParent's scroll position, not if the element is fixed
				+ (this.cssPosition == "fixed" ? $(document).scrollTop() : 0) * mod
				+ this.margins.top * mod												//Add the margin (you don't want the margin counting in intersection methods)
			),
                    left: (
				pos.left																// the calculated relative position
				+ this.offset.relative.left * mod										// Only for relative positioned nodes: Relative offset from element to offset parent
				+ this.offset.parent.left * mod											// The offsetParent's offset without borders (offset + border)
				- (this.cssPosition == "fixed" || (this.cssPosition == "absolute" && this.offsetParent[0] == document.body) ? 0 : this.offsetParent[0].scrollLeft) * mod	// The offsetParent's scroll position, not if the element is fixed
				+ (this.cssPosition == "fixed" ? $(document).scrollLeft() : 0) * mod
				+ this.margins.left * mod												//Add the margin (you don't want the margin counting in intersection methods)
			)
                };
            },
            generatePosition: function(e) {

                var o = this.options;
                var position = {
                    top: (
				e.pageY																	// The absolute mouse position
				- this.offset.click.top													// Click offset (relative to the element)
				- this.offset.relative.top												// Only for relative positioned nodes: Relative offset from element to offset parent
				- this.offset.parent.top												// The offsetParent's offset without borders (offset + border)
				+ (this.cssPosition == "fixed" || (this.cssPosition == "absolute" && this.offsetParent[0] == document.body) ? 0 : this.offsetParent[0].scrollTop)	// The offsetParent's scroll position, not if the element is fixed
				- (this.cssPosition == "fixed" ? $(document).scrollTop() : 0)
			),
                    left: (
				e.pageX																	// The absolute mouse position
				- this.offset.click.left												// Click offset (relative to the element)
				- this.offset.relative.left												// Only for relative positioned nodes: Relative offset from element to offset parent
				- this.offset.parent.left												// The offsetParent's offset without borders (offset + border)
				+ (this.cssPosition == "fixed" || (this.cssPosition == "absolute" && this.offsetParent[0] == document.body) ? 0 : this.offsetParent[0].scrollLeft)	// The offsetParent's scroll position, not if the element is fixed
				- (this.cssPosition == "fixed" ? $(document).scrollLeft() : 0)
			)
                };

                if (!this.originalPosition) return position; 									//If we are not dragging yet, we won't check for options

                /*
                * - Position constraining -
                * Constrain the position to a mix of grid, containment.
                */
                if (this.containment) {
                    if (position.left < this.containment[0]) position.left = this.containment[0];
                    if (position.top < this.containment[1]) position.top = this.containment[1];
                    if (position.left > this.containment[2]) position.left = this.containment[2];
                    if (position.top > this.containment[3]) position.top = this.containment[3];
                }

                if (o.grid) {
                    var top = this.originalPosition.top + Math.round((position.top - this.originalPosition.top) / o.grid[1]) * o.grid[1];
                    position.top = this.containment ? (!(top < this.containment[1] || top > this.containment[3]) ? top : (!(top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;

                    var left = this.originalPosition.left + Math.round((position.left - this.originalPosition.left) / o.grid[0]) * o.grid[0];
                    position.left = this.containment ? (!(left < this.containment[0] || left > this.containment[2]) ? left : (!(left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
                }

                return position;
            },
            mouseDrag: function(e) {

                //Compute the helpers position
                this.position = this.generatePosition(e);
                this.positionAbs = this.convertPositionTo("absolute");

                //Call plugins and callbacks and use the resulting position if something is returned		
                this.position = this.propagate("drag", e) || this.position;

                if (!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left + 'px';
                if (!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top + 'px';
                if ($.ui.ddmanager) $.ui.ddmanager.drag(this, e);

                return false;
            },
            mouseStop: function(e) {

                //If we are using droppables, inform the manager about the drop
                var dropped = false;
                if ($.ui.ddmanager && !this.options.dropBehaviour)
                    var dropped = $.ui.ddmanager.drop(this, e);

                if ((this.options.revert == "invalid" && !dropped) || (this.options.revert == "valid" && dropped) || this.options.revert === true) {
                    var self = this;
                    $(this.helper).animate(this.originalPosition, parseInt(this.options.revert, 10) || 500, function() {
                        self.propagate("stop", e);
                        self.clear();
                    });
                } else {
                    this.propagate("stop", e);
                    this.clear();
                }

                return false;
            },
            clear: function() {
                this.helper.removeClass("ui-draggable-dragging");
                if (this.options.helper != 'original' && !this.cancelHelperRemoval) this.helper.remove();
                //if($.ui.ddmanager) $.ui.ddmanager.current = null;
                this.helper = null;
                this.cancelHelperRemoval = false;
            },

            // From now on bulk stuff - mainly helpers
            plugins: {},
            uiHash: function(e) {
                return {
                    helper: this.helper,
                    position: this.position,
                    absolutePosition: this.positionAbs,
                    options: this.options
                };
            },
            propagate: function(n, e) {
                $.ui.plugin.call(this, n, [e, this.uiHash()]);
                if (n == "drag") this.positionAbs = this.convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins
                return this.element.triggerHandler(n == "drag" ? n : "drag" + n, [e, this.uiHash()], this.options[n]);
            },
            destroy: function() {
                if (!this.element.data('draggable')) return;
                this.element.removeData("draggable").unbind(".draggable").removeClass('ui-draggable');
                this.mouseDestroy();
            }
        }));

        $.extend($.ui.draggable, {
            defaults: {
                appendTo: "parent",
                axis: false,
                cancel: ":input",
                delay: 0,
                distance: 1,
                helper: "original"
            }
        });

        $.ui.plugin.add("draggable", "cursor", {
            start: function(e, ui) {
                var t = $('body');
                if (t.css("cursor")) ui.options._cursor = t.css("cursor");
                t.css("cursor", ui.options.cursor);
            },
            stop: function(e, ui) {
                if (ui.options._cursor) $('body').css("cursor", ui.options._cursor);
            }
        });

        $.ui.plugin.add("draggable", "zIndex", {
            start: function(e, ui) {
                var t = $(ui.helper);
                if (t.css("zIndex")) ui.options._zIndex = t.css("zIndex");
                t.css('zIndex', ui.options.zIndex);
            },
            stop: function(e, ui) {
                if (ui.options._zIndex) $(ui.helper).css('zIndex', ui.options._zIndex);
            }
        });

        $.ui.plugin.add("draggable", "opacity", {
            start: function(e, ui) {
                var t = $(ui.helper);
                if (t.css("opacity")) ui.options._opacity = t.css("opacity");
                t.css('opacity', ui.options.opacity);
            },
            stop: function(e, ui) {
                if (ui.options._opacity) $(ui.helper).css('opacity', ui.options._opacity);
            }
        });

        $.ui.plugin.add("draggable", "iframeFix", {
            start: function(e, ui) {
                $(ui.options.iframeFix === true ? "iframe" : ui.options.iframeFix).each(function() {
                    $('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>')
			.css({
			    width: this.offsetWidth + "px", height: this.offsetHeight + "px",
			    position: "absolute", opacity: "0.001", zIndex: 1000
			})
			.css($(this).offset())
			.appendTo("body");
                });
            },
            stop: function(e, ui) {
                $("div.DragDropIframeFix").each(function() { this.parentNode.removeChild(this); }); //Remove frame helpers	
            }
        });

        $.ui.plugin.add("draggable", "scroll", {
            start: function(e, ui) {
                var o = ui.options;
                var i = $(this).data("draggable");
                o.scrollSensitivity = o.scrollSensitivity || 20;
                o.scrollSpeed = o.scrollSpeed || 20;

                i.overflowY = function(el) {
                    do { if (/auto|scroll/.test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-y'))) return el; el = el.parent(); } while (el[0].parentNode);
                    return $(document);
                } (this);
                i.overflowX = function(el) {
                    do { if (/auto|scroll/.test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-x'))) return el; el = el.parent(); } while (el[0].parentNode);
                    return $(document);
                } (this);

                if (i.overflowY[0] != document && i.overflowY[0].tagName != 'HTML') i.overflowYOffset = i.overflowY.offset();
                if (i.overflowX[0] != document && i.overflowX[0].tagName != 'HTML') i.overflowXOffset = i.overflowX.offset();

            },
            drag: function(e, ui) {

                var o = ui.options;
                var i = $(this).data("draggable");

                if (i.overflowY[0] != document && i.overflowY[0].tagName != 'HTML') {
                    if ((i.overflowYOffset.top + i.overflowY[0].offsetHeight) - e.pageY < o.scrollSensitivity)
                        i.overflowY[0].scrollTop = i.overflowY[0].scrollTop + o.scrollSpeed;
                    if (e.pageY - i.overflowYOffset.top < o.scrollSensitivity)
                        i.overflowY[0].scrollTop = i.overflowY[0].scrollTop - o.scrollSpeed;

                } else {
                    if (e.pageY - $(document).scrollTop() < o.scrollSensitivity)
                        $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
                    if ($(window).height() - (e.pageY - $(document).scrollTop()) < o.scrollSensitivity)
                        $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
                }

                if (i.overflowX[0] != document && i.overflowX[0].tagName != 'HTML') {
                    if ((i.overflowXOffset.left + i.overflowX[0].offsetWidth) - e.pageX < o.scrollSensitivity)
                        i.overflowX[0].scrollLeft = i.overflowX[0].scrollLeft + o.scrollSpeed;
                    if (e.pageX - i.overflowXOffset.left < o.scrollSensitivity)
                        i.overflowX[0].scrollLeft = i.overflowX[0].scrollLeft - o.scrollSpeed;
                } else {
                    if (e.pageX - $(document).scrollLeft() < o.scrollSensitivity)
                        $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
                    if ($(window).width() - (e.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
                        $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
                }

            }
        });

        $.ui.plugin.add("draggable", "snap", {
            start: function(e, ui) {

                var inst = $(this).data("draggable");
                inst.snapElements = [];
                $(ui.options.snap === true ? '.ui-draggable' : ui.options.snap).each(function() {
                    var $t = $(this); var $o = $t.offset();
                    if (this != inst.element[0]) inst.snapElements.push({
                        item: this,
                        width: $t.outerWidth(), height: $t.outerHeight(),
                        top: $o.top, left: $o.left
                    });
                });

            },
            drag: function(e, ui) {

                var inst = $(this).data("draggable");
                var d = ui.options.snapTolerance || 20;
                var x1 = ui.absolutePosition.left, x2 = x1 + inst.helperProportions.width,
			y1 = ui.absolutePosition.top, y2 = y1 + inst.helperProportions.height;

                for (var i = inst.snapElements.length - 1; i >= 0; i--) {

                    var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width,
				t = inst.snapElements[i].top, b = t + inst.snapElements[i].height;

                    //Yes, I know, this is insane ;)
                    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))) continue;

                    if (ui.options.snapMode != 'inner') {
                        var ts = Math.abs(t - y2) <= 20;
                        var bs = Math.abs(b - y1) <= 20;
                        var ls = Math.abs(l - x2) <= 20;
                        var rs = Math.abs(r - x1) <= 20;
                        if (ts) ui.position.top = inst.convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top;
                        if (bs) ui.position.top = inst.convertPositionTo("relative", { top: b, left: 0 }).top;
                        if (ls) ui.position.left = inst.convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left;
                        if (rs) ui.position.left = inst.convertPositionTo("relative", { top: 0, left: r }).left;
                    }

                    if (ui.options.snapMode != 'outer') {
                        var ts = Math.abs(t - y1) <= 20;
                        var bs = Math.abs(b - y2) <= 20;
                        var ls = Math.abs(l - x1) <= 20;
                        var rs = Math.abs(r - x2) <= 20;
                        if (ts) ui.position.top = inst.convertPositionTo("relative", { top: t, left: 0 }).top;
                        if (bs) ui.position.top = inst.convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top;
                        if (ls) ui.position.left = inst.convertPositionTo("relative", { top: 0, left: l }).left;
                        if (rs) ui.position.left = inst.convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left;
                    }

                };
            }
        });

        $.ui.plugin.add("draggable", "connectToSortable", {
            start: function(e, ui) {

                var inst = $(this).data("draggable");
                inst.sortables = [];
                $(ui.options.connectToSortable).each(function() {
                    if ($.data(this, 'sortable')) {
                        var sortable = $.data(this, 'sortable');
                        inst.sortables.push({
                            instance: sortable,
                            shouldRevert: sortable.options.revert
                        });
                        sortable.refreshItems(); //Do a one-time refresh at start to refresh the containerCache	
                        sortable.propagate("activate", e, inst);
                    }
                });

            },
            stop: function(e, ui) {

                //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
                var inst = $(this).data("draggable");

                $.each(inst.sortables, function() {
                    if (this.instance.isOver) {
                        this.instance.isOver = 0;
                        inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
                        this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
                        if (this.shouldRevert) this.instance.options.revert = true; //revert here
                        this.instance.mouseStop(e);

                        //Also propagate receive event, since the sortable is actually receiving a element
                        this.instance.element.triggerHandler("sortreceive", [e, $.extend(this.instance.ui(), { sender: inst.element })], this.instance.options["receive"]);

                        this.instance.options.helper = this.instance.options._helper;
                    } else {
                        this.instance.propagate("deactivate", e, inst);
                    }

                });

            },
            drag: function(e, ui) {

                var inst = $(this).data("draggable"), self = this;

                var checkPos = function(o) {

                    var l = o.left, r = l + o.width,
				t = o.top, b = t + o.height;

                    return (l < (this.positionAbs.left + this.offset.click.left) && (this.positionAbs.left + this.offset.click.left) < r
					&& t < (this.positionAbs.top + this.offset.click.top) && (this.positionAbs.top + this.offset.click.top) < b);
                };

                $.each(inst.sortables, function(i) {

                    if (checkPos.call(inst, this.instance.containerCache)) {

                        //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
                        if (!this.instance.isOver) {
                            this.instance.isOver = 1;

                            //Now we fake the start of dragging for the sortable instance,
                            //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
                            //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)
                            this.instance.currentItem = $(self).clone().appendTo(this.instance.element).data("sortable-item", true);
                            this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
                            this.instance.options.helper = function() { return ui.helper[0]; };

                            e.target = this.instance.currentItem[0];
                            this.instance.mouseCapture(e, true);
                            this.instance.mouseStart(e, true, true);

                            //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
                            this.instance.offset.click.top = inst.offset.click.top;
                            this.instance.offset.click.left = inst.offset.click.left;
                            this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
                            this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;

                            inst.propagate("toSortable", e);

                        }

                        //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
                        if (this.instance.currentItem) this.instance.mouseDrag(e);

                    } else {

                        //If it doesn't intersect with the sortable, and it intersected before,
                        //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
                        if (this.instance.isOver) {
                            this.instance.isOver = 0;
                            this.instance.cancelHelperRemoval = true;
                            this.instance.options.revert = false; //No revert here
                            this.instance.mouseStop(e, true);
                            this.instance.options.helper = this.instance.options._helper;

                            //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
                            this.instance.currentItem.remove();
                            if (this.instance.placeholder) this.instance.placeholder.remove();

                            inst.propagate("fromSortable", e);
                        }

                    };

                });

            }
        });

        $.ui.plugin.add("draggable", "stack", {
            start: function(e, ui) {
                var group = $.makeArray($(ui.options.stack.group)).sort(function(a, b) {
                    return (parseInt($(a).css("zIndex"), 10) || ui.options.stack.min) - (parseInt($(b).css("zIndex"), 10) || ui.options.stack.min);
                });

                $(group).each(function(i) {
                    this.style.zIndex = ui.options.stack.min + i;
                });

                this[0].style.zIndex = ui.options.stack.min + group.length;
            }
        });

    })(jQuery);