/*
 * jQuery UI Draggable 1.7.2
 *
 * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
 * 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(){
            if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position"))) 
                this.element[0].style.position = 'relative';
            
            (this.options.addClasses && this.element.addClass("ui-draggable"));
            (this.options.disabled && this.element.addClass("ui-draggable-disabled"));
            
            this._mouseInit();
            
        },
        
        destroy: function(){
            if (!this.element.data('draggable')) 
                return;
            this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable" +
            " ui-draggable-dragging" +
            " ui-draggable-disabled");
            this._mouseDestroy();
        },
        
        _mouseCapture: function(event){
        
            var o = this.options;
            
            if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle')) 
                return false;
            
            //Quit if we're not on a valid handle
            this.handle = this._getHandle(event);
            if (!this.handle) 
                return false;
            
            return true;
            
        },
        
        _mouseStart: function(event){
        
            var o = this.options;
            
            //Create and append the visible helper
            this.helper = this._createHelper(event);
            
            //Cache the helper size
            this._cacheHelperProportions();
            
            //If ddmanager is used for droppables, set the global draggable
            if ($.ui.ddmanager) 
                $.ui.ddmanager.current = this;
            
            /*
             * - Position generation -
             * This block generates everything position related - it's the core of draggables.
             */
            //Cache the margins of the original element
            this._cacheMargins();
            
            //Store the helper's css position
            this.cssPosition = this.helper.css("position");
            this.scrollParent = this.helper.scrollParent();
            
            //The element's absolute position on the page minus margins
            this.offset = this.element.offset();
            this.offset = {
                top: this.offset.top - this.margins.top,
                left: this.offset.left - this.margins.left
            };
            
            $.extend(this.offset, {
                click: { //Where the click happened, relative to the element
                    left: event.pageX - this.offset.left,
                    top: event.pageY - this.offset.top
                },
                parent: this._getParentOffset(),
                relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
            });
            
            //Generate the original position
            this.originalPosition = this._generatePosition(event);
            this.originalPageX = event.pageX;
            this.originalPageY = event.pageY;
            
            //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
            if (o.cursorAt) 
                this._adjustOffsetFromHelper(o.cursorAt);
            
            //Set a containment if given in the options
            if (o.containment) 
                this._setContainment();
            
            //Call plugins and callbacks
            this._trigger("start", event);
            
            //Recache the helper size
            this._cacheHelperProportions();
            
            //Prepare the droppable offsets
            if ($.ui.ddmanager && !o.dropBehaviour) 
                $.ui.ddmanager.prepareOffsets(this, event);
            
            this.helper.addClass("ui-draggable-dragging");
            this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
            return true;
        },
        
        _mouseDrag: function(event, noPropagation){
        
            //Compute the helpers position
            this.position = this._generatePosition(event);
            this.positionAbs = this._convertPositionTo("absolute");
            
            //Call plugins and callbacks and use the resulting position if something is returned
            if (!noPropagation) {
                var ui = this._uiHash();
                this._trigger('drag', event, ui);
                this.position = ui.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, event);
            
            return false;
        },
        
        _mouseStop: function(event){
        
            //If we are using droppables, inform the manager about the drop
            var dropped = false;
            if ($.ui.ddmanager && !this.options.dropBehaviour) 
                dropped = $.ui.ddmanager.drop(this, event);
            
            //if a drop comes from outside (a sortable)
            if (this.dropped) {
                dropped = this.dropped;
                this.dropped = false;
            }
            
            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))) {
                var self = this;
                $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function(){
                    self._trigger("stop", event);
                    self._clear();
                });
            }
            else {
                this._trigger("stop", event);
                this._clear();
            }
            return false;
        },
        
        _getHandle: function(event){
        
            var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false;
            $(this.options.handle, this.element).find("*").andSelf().each(function(){
                if (this == event.target) 
                    handle = true;
            });
            
            return handle;
            
        },
        
        _createHelper: function(event){
            var o = this.options;
            var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone() : this.element);
            
            if (!helper.parents('body').length) 
                helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo));
            
            if (helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) 
                helper.css("position", "absolute");
            return helper;
            
        },
        
        _adjustOffsetFromHelper: function(obj){
            if (obj.left != undefined) 
                this.offset.click.left = obj.left + this.margins.left;
            if (obj.right != undefined) 
                this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
            if (obj.top != undefined) 
                this.offset.click.top = obj.top + this.margins.top;
            if (obj.bottom != undefined) 
                this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
        },
        
        _getParentOffset: function(){
        
            //Get the offsetParent and cache its position
            this.offsetParent = this.helper.offsetParent();
            var po = this.offsetParent.offset();
            
            // This is a special case where we need to modify a offset calculated on start, since the following happened:
            // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
            // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
            //    the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
            if (this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) {
                po.left += this.scrollParent.scrollLeft();
                po.top += this.scrollParent.scrollTop();
            }
            
            if ((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information
 ||
            (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix
                po = {
                    top: 0,
                    left: 0
                };
            
            return {
                top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"), 10) || 0),
                left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"), 10) || 0)
            };
            
        },
        
        _getRelativeOffset: function(){
        
            if (this.cssPosition == "relative") {
                var p = this.element.position();
                return {
                    top: p.top - (parseInt(this.helper.css("top"), 10) || 0) + this.scrollParent.scrollTop(),
                    left: p.left - (parseInt(this.helper.css("left"), 10) || 0) + this.scrollParent.scrollLeft()
                };
            }
            else {
                return {
                    top: 0,
                    left: 0
                };
            }
            
        },
        
        _cacheMargins: function(){
            this.margins = {
                left: (parseInt(this.element.css("marginLeft"), 10) || 0),
                top: (parseInt(this.element.css("marginTop"), 10) || 0)
            };
        },
        
        _cacheHelperProportions: function(){
            this.helperProportions = {
                width: this.helper.outerWidth(),
                height: this.helper.outerHeight()
            };
        },
        
        _setContainment: function(){
        
            var o = this.options;
            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.helperProportions.width - this.margins.left, ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top];
            
            if (!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) {
                var ce = $(o.containment)[0];
                if (!ce) 
                    return;
                var co = $(o.containment).offset();
                var over = ($(ce).css("overflow") != 'hidden');
                
                this.containment = [co.left + (parseInt($(ce).css("borderLeftWidth"), 10) || 0) + (parseInt($(ce).css("paddingLeft"), 10) || 0) - this.margins.left, co.top + (parseInt($(ce).css("borderTopWidth"), 10) || 0) + (parseInt($(ce).css("paddingTop"), 10) || 0) - this.margins.top, 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, 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];
            }
            else 
                if (o.containment.constructor == Array) {
                    this.containment = o.containment;
                }
            
        },
        
        _convertPositionTo: function(d, pos){
        
            if (!pos) 
                pos = this.position;
            var mod = d == "absolute" ? 1 : -1;
            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);
            
            return {
                top: (pos.top // The absolute mouse 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)
 -
                ($.browser.safari && this.cssPosition == 'fixed' ? 0 : (this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : (scrollIsRootNode ? 0 : scroll.scrollTop())) * mod)),
                left: (pos.left // The absolute mouse 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)
 -
                ($.browser.safari && this.cssPosition == 'fixed' ? 0 : (this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft()) * mod))
            };
            
        },
        
        _generatePosition: function(event){
        
            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);
            
            // This is another very weird special case that only happens for relative elements:
            // 1. If the css position is relative
            // 2. and the scroll parent is the document or similar to the offset parent
            // we have to refresh the relative offset during the scroll so there are no jumps
            if (this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) {
                this.offset.relative = this._getRelativeOffset();
            }
            
            var pageX = event.pageX;
            var pageY = event.pageY;
            
            /*
             * - Position constraining -
             * Constrain the position to a mix of grid, containment.
             */
            if (this.originalPosition) { //If we are not dragging yet, we won't check for options
                if (this.containment) {
                    if (event.pageX - this.offset.click.left < this.containment[0]) 
                        pageX = this.containment[0] + this.offset.click.left;
                    if (event.pageY - this.offset.click.top < this.containment[1]) 
                        pageY = this.containment[1] + this.offset.click.top;
                    if (event.pageX - this.offset.click.left > this.containment[2]) 
                        pageX = this.containment[2] + this.offset.click.left;
                    if (event.pageY - this.offset.click.top > this.containment[3]) 
                        pageY = this.containment[3] + this.offset.click.top;
                }
                
                if (o.grid) {
                    var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
                    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;
                    
                    var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
                    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;
                }
                
            }
            
            return {
                top: (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)
 +
                ($.browser.safari && this.cssPosition == 'fixed' ? 0 : (this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : (scrollIsRootNode ? 0 : scroll.scrollTop())))),
                left: (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)
 +
                ($.browser.safari && this.cssPosition == 'fixed' ? 0 : (this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft())))
            };
            
        },
        
        _clear: function(){
            this.helper.removeClass("ui-draggable-dragging");
            if (this.helper[0] != this.element[0] && !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
        
        _trigger: function(type, event, ui){
            ui = ui || this._uiHash();
            $.ui.plugin.call(this, type, [event, ui]);
            if (type == "drag") 
                this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins
            return $.widget.prototype._trigger.call(this, type, event, ui);
        },
        
        plugins: {},
        
        _uiHash: function(event){
            return {
                helper: this.helper,
                position: this.position,
                absolutePosition: this.positionAbs, //deprecated
                offset: this.positionAbs
            };
        }
        
    }));
    
    $.extend($.ui.draggable, {
        version: "1.7.2",
        eventPrefix: "drag",
        defaults: {
            addClasses: true,
            appendTo: "parent",
            axis: false,
            cancel: ":input,option",
            connectToSortable: false,
            containment: false,
            cursor: "auto",
            cursorAt: false,
            delay: 0,
            distance: 1,
            grid: false,
            handle: false,
            helper: "original",
            iframeFix: false,
            opacity: false,
            refreshPositions: false,
            revert: false,
            revertDuration: 500,
            scope: "default",
            scroll: true,
            scrollSensitivity: 20,
            scrollSpeed: 20,
            snap: false,
            snapMode: "both",
            snapTolerance: 20,
            stack: false,
            zIndex: false,
            dragItem: false
        }
    });
    
    $.ui.plugin.add("draggable", "connectToSortable", {
        start: function(event, ui){
        
            var inst = $(this).data("draggable"), o = inst.options, uiSortable = $.extend({}, ui, {
                item: inst.element
            });
            inst.sortables = [];
            $(o.connectToSortable).each(function(){
                var sortable = $.data(this, 'sortable');
                if (sortable && !sortable.options.disabled) {
                    inst.sortables.push({
                        instance: sortable,
                        shouldRevert: sortable.options.revert
                    });
                    sortable._refreshItems(); //Do a one-time refresh at start to refresh the containerCache
                    sortable._trigger("activate", event, uiSortable);
                }
            });
            
        },
        stop: function(event, 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"), uiSortable = $.extend({}, ui, {
                item: inst.element
            }), self = $(this);
            $.each(inst.sortables, function(){
                if (this.instance.isOver) {
                    var index = 0;
                    var parentId = this.instance.element.parent().attr('id');
                    var namespace = $(self).attr('namespace');
                    //判断父级是否是DIY框架，如果等于 body-bg表示框架
                    //具体判断按照 diy_content 的父级而定
                    if (parentId !== "" && parentId != "body-bg") {
                        var classs = this.instance.element.attr('class'), classes = classs.split(' '), needClass = classes.shift(),gid=$(self).attr('rel');
                        if (typeof(frameArray[parentId][needClass]) == "object") {
                            index = frameArray[parentId][needClass].push("0");
                        }
                        else {
                            frameArray[parentId][needClass] = new Array;
                            index = frameArray[parentId][needClass].push("0");
                        }
                        $.tbox.popup(SITE_URL + "/index.php?app=page&mod=Diy&act=getPopUp&gid="+gid+"&tagName=" + namespace + "&index=" + (index - 1) + "&parentId=" + parentId + "&needClass=" + needClass + "&id=" + parentId + "-" + needClass + "-" + index, "添加模块", false, false, {
                            "closed": function(){
                                $('#placeholder').remove();
                            }
                        });
                        
                        
                        var button = '<p><input class="btn_sea" id="savemodel"  name="" type="button" value="确定" /><input class="btn_sea_n ml5" name="" id="preview_button" type="button" value="预览"/></p>';
                        $('#tbox .tb_button_list').show().html(button);
                        $('#preview_button').click(function(){
                            preview();
                            
                        });
                        $('#savemodel').click(function(){
                            savemodel();
                            $.tbox.close();
                            
                        });
                        
                    }
                    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)
                    //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid'
                    if (this.shouldRevert) 
                        this.instance.options.revert = true;
                    
                    //Trigger the stop of the sortable
                    this.instance._mouseStop(event);
                    
                    this.instance.options.helper = this.instance.options._helper;
                    
                    //If the helper has been the original item, restore properties in the sortable
                    if (inst.options.helper == 'original') 
                        this.instance.currentItem.css({
                            top: 'auto',
                            left: 'auto'
                        });
                    
                }
                else {
                    this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
                    this.instance._trigger("deactivate", event, uiSortable);
                }
                
            });
            
        },
        drag: function(event, ui){
        
            var inst = $(this).data("draggable"), self = this;
            var checkPos = function(o){
                var dyClick = this.offset.click.top, dxClick = this.offset.click.left;
                var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left;
                var itemHeight = o.height, itemWidth = o.width;
                var itemTop = o.top, itemLeft = o.left;
                
                return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth);
            };
            $.each(inst.sortables, function(i){
                var myInstance;
                var newId;
                
                //Copy over some variables to allow calling the sortable's native _intersectsWith
                this.instance.positionAbs = inst.positionAbs;
                this.instance.helperProportions = inst.helperProportions;
                this.instance.offset.click = inst.offset.click;
                
                if (this.instance._intersectsWith(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) {
                        //for (var test in inst.options.dragItem) {
                        var needClass = $(self).attr('class');
                        needClass = needClass.split(' ');
                        switch (needClass.shift()) {
                            case "addFrame":
                                frameCount++;
                                newId = $(self).attr('rel') + "F" + frameCount;
                                
                                var tempFrameTemplate = inst.options.dragItem[$(self).attr('rel')].clone();
                                
                                frameArray[newId] = new Array();
                                frameArray[newId]['html'] = tempFrameTemplate.html().replace(/(\s+)line_D_R/g, '');
                                
                                myInstance = inst.options.dragItem[$(self).attr('rel')];
                                myInstance.children('.bg_diy_tit').find('a').attr('href', 'javascript:void(0)').attr('rel', newId)
                                myInstance.attr('id', newId);
                                break;
                            case "addModel":
                                myInstance = inst.options.dragItem['placeholder'];
                                //alert( this.instance.element.width());
                                myInstance.width(80);
                                myInstance.height(25);
                                myInstance.html('loading...');

                                break;
                        }
                        
                        // }
                        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.options.dragItem[$(self).attr('rel')].clone()
                        this.instance.currentItem = myInstance.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];
                        };
                        
                        event.target = this.instance.currentItem[0];
                        this.instance._mouseCapture(event, true);
                        this.instance._mouseStart(event, 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._trigger("toSortable", event);
                        inst.dropped = this.instance.element; //draggable revert needs that
                        //hack so receive/update callbacks work (mostly)
                        
                        inst.currentItem = inst.element;
                        this.instance.fromOutside = inst;
                        
                    }
                    
                    //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(event);
                    
                }
                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;
                        
                        //Prevent reverting on this forced stop
                        this.instance.options.revert = false;
                        
                        // The out event needs to be triggered independently
                        this.instance._trigger('out', event, this.instance._uiHash(this.instance));
                        
                        this.instance._mouseStop(event, 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._trigger("fromSortable", event);
                        inst.dropped = false; //draggable revert needs that
                    }
                    
                };
                
                            });
            
        }
    });
    
    $.ui.plugin.add("draggable", "cursor", {
        start: function(event, ui){
            var t = $('body'), o = $(this).data('draggable').options;
            if (t.css("cursor")) 
                o._cursor = t.css("cursor");
            t.css("cursor", o.cursor);
        },
        stop: function(event, ui){
            var o = $(this).data('draggable').options;
            if (o._cursor) 
                $('body').css("cursor", o._cursor);
        }
    });
    
    $.ui.plugin.add("draggable", "iframeFix", {
        start: function(event, ui){
            var o = $(this).data('draggable').options;
            $(o.iframeFix === true ? "iframe" : o.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(event, ui){
            $("div.ui-draggable-iframeFix").each(function(){
                this.parentNode.removeChild(this);
            }); //Remove frame helpers
        }
    });
    
    $.ui.plugin.add("draggable", "opacity", {
        start: function(event, ui){
            var t = $(ui.helper), o = $(this).data('draggable').options;
            if (t.css("opacity")) 
                o._opacity = t.css("opacity");
            t.css('opacity', o.opacity);
        },
        stop: function(event, ui){
            var o = $(this).data('draggable').options;
            if (o._opacity) 
                $(ui.helper).css('opacity', o._opacity);
        }
    });
    
    $.ui.plugin.add("draggable", "scroll", {
        start: function(event, ui){
            var i = $(this).data("draggable");
            if (i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') 
                i.overflowOffset = i.scrollParent.offset();
        },
        drag: function(event, ui){
        
            var i = $(this).data("draggable"), o = i.options, scrolled = false;
            
            if (i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') {
            
                if (!o.axis || o.axis != 'x') {
                    if ((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) 
                        i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
                    else 
                        if (event.pageY - i.overflowOffset.top < o.scrollSensitivity) 
                            i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
                }
                
                if (!o.axis || o.axis != 'y') {
                    if ((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) 
                        i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
                    else 
                        if (event.pageX - i.overflowOffset.left < o.scrollSensitivity) 
                            i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
                }
                
            }
            else {
            
                if (!o.axis || o.axis != 'x') {
                    if (event.pageY - $(document).scrollTop() < o.scrollSensitivity) 
                        scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
                    else 
                        if ($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) 
                            scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
                }
                
                if (!o.axis || o.axis != 'y') {
                    if (event.pageX - $(document).scrollLeft() < o.scrollSensitivity) 
                        scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
                    else 
                        if ($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) 
                            scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
                }
                
            }
            
            if (scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) 
                $.ui.ddmanager.prepareOffsets(i, event);
            
        }
    });
    
    $.ui.plugin.add("draggable", "snap", {
        start: function(event, ui){
        
            var i = $(this).data("draggable"), o = i.options;
            i.snapElements = [];
            
            $(o.snap.constructor != String ? (o.snap.items || ':data(draggable)') : o.snap).each(function(){
                var $t = $(this);
                var $o = $t.offset();
                if (this != i.element[0]) 
                    i.snapElements.push({
                        item: this,
                        width: $t.outerWidth(),
                        height: $t.outerHeight(),
                        top: $o.top,
                        left: $o.left
                    });
            });
            
        },
        drag: function(event, ui){
        
            var inst = $(this).data("draggable"), o = inst.options;
            var d = o.snapTolerance;
            
            var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, y1 = ui.offset.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))) {
                    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
                        })));
                    inst.snapElements[i].snapping = false;
                    continue;
                }
                
                if (o.snapMode != 'inner') {
                    var ts = Math.abs(t - y2) <= d;
                    var bs = Math.abs(b - y1) <= d;
                    var ls = Math.abs(l - x2) <= d;
                    var rs = Math.abs(r - x1) <= d;
                    if (ts) 
                        ui.position.top = inst._convertPositionTo("relative", {
                            top: t - inst.helperProportions.height,
                            left: 0
                        }).top -
                        inst.margins.top;
                    if (bs) 
                        ui.position.top = inst._convertPositionTo("relative", {
                            top: b,
                            left: 0
                        }).top -
                        inst.margins.top;
                    if (ls) 
                        ui.position.left = inst._convertPositionTo("relative", {
                            top: 0,
                            left: l - inst.helperProportions.width
                        }).left -
                        inst.margins.left;
                    if (rs) 
                        ui.position.left = inst._convertPositionTo("relative", {
                            top: 0,
                            left: r
                        }).left -
                        inst.margins.left;
                }
                
                var first = (ts || bs || ls || rs);
                
                if (o.snapMode != 'outer') {
                    var ts = Math.abs(t - y1) <= d;
                    var bs = Math.abs(b - y2) <= d;
                    var ls = Math.abs(l - x1) <= d;
                    var rs = Math.abs(r - x2) <= d;
                    if (ts) 
                        ui.position.top = inst._convertPositionTo("relative", {
                            top: t,
                            left: 0
                        }).top -
                        inst.margins.top;
                    if (bs) 
                        ui.position.top = inst._convertPositionTo("relative", {
                            top: b - inst.helperProportions.height,
                            left: 0
                        }).top -
                        inst.margins.top;
                    if (ls) 
                        ui.position.left = inst._convertPositionTo("relative", {
                            top: 0,
                            left: l
                        }).left -
                        inst.margins.left;
                    if (rs) 
                        ui.position.left = inst._convertPositionTo("relative", {
                            top: 0,
                            left: r - inst.helperProportions.width
                        }).left -
                        inst.margins.left;
                }
                
                if (!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) 
                    (inst.options.snap.snap &&
                    inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), {
                        snapItem: inst.snapElements[i].item
                    })));
                inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
                
            };
            
                    }
    });
    
    $.ui.plugin.add("draggable", "stack", {
        start: function(event, ui){
        
            var o = $(this).data("draggable").options;
            
            var group = $.makeArray($(o.stack.group)).sort(function(a, b){
                return (parseInt($(a).css("zIndex"), 10) || o.stack.min) - (parseInt($(b).css("zIndex"), 10) || o.stack.min);
            });
            
            $(group).each(function(i){
                this.style.zIndex = o.stack.min + i;
            });
            
            this[0].style.zIndex = o.stack.min + group.length;
            
        }
    });
    
    $.ui.plugin.add("draggable", "zIndex", {
        start: function(event, ui){
            var t = $(ui.helper), o = $(this).data("draggable").options;
            if (t.css("zIndex")) 
                o._zIndex = t.css("zIndex");
            t.css('zIndex', o.zIndex);
        },
        stop: function(event, ui){
            var o = $(this).data("draggable").options;
            if (o._zIndex) 
                $(ui.helper).css('zIndex', o._zIndex);
        }
    });
    
})(jQuery);
