0

它是唯一适用于我的代码的 jQuery 多重排序。它昨天就起来了,但现在它似乎消失了,我正在为没有抓住源头而自责。

编辑:布拉德发现它如下所述。太感谢了。对于那些好奇的人,这是我发现的 jQuery multisort 的最佳工作版本,至少可用于表行。

4

1 回答 1

1

jQuery UI Sortable 可以在这里找到:

https://code.google.com/p/myscrumproject/source/browse/trunk/ScrumWebClient/WebContent/js/ui.multisortable.js?r=197

您也可以将它作为 jQuery UI 的一部分来获取。官方在这里下载:http: //jqueryui.com/download/

/*
 * jQuery UI Sortable 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/Sortables
 *
 * Depends:
 *  ui.core.js
 */
(function($) {

$.widget("ui.multisortable", $.extend({}, $.ui.sortable.prototype, {

    _mouseCapture: function(event, overrideHandle) {

        if (this.reverting) {
            return false;
        }

        if(this.options.disabled || this.options.type == 'static') return false;

        //We have to refresh the items data once first
        this._refreshItems(event);

        //Find out if the clicked node (or one of its parents) is a actual item in this.items
        var currentItem = null, self = this, nodes = $(event.target).parents().each(function() {
            if($.data(this, 'sortable-item') == self) {
                currentItem = $(this);
                return false;
            }
        });
        if($.data(event.target, 'sortable-item') == self) currentItem = $(event.target);

        if(!currentItem) return false;
        if(this.options.handle && !overrideHandle) {
            var validHandle = false;

            $(this.options.handle, currentItem).find("*").andSelf().each(function() { if(this == event.target) validHandle = true; });
            if(!validHandle) return false;
        }

        if (event.ctrlKey) {
            // Class for marking a multidraggable as being part of the group
            $(currentItem).toggleClass('ui-multisort-grouped');
        }       

        this.currentItem = currentItem;
        this._removeCurrentsFromItems();
        return true;

    },

    _mouseStart: function(event, overrideHandle, noActivation) {

        var o = this.options, self = this;
        this.currentContainer = this;

        //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
        this.refreshPositions();

        //Create and append the visible helper
        this.helper = this._createHelper(event);

        $("#target").text(this.helper.length);

        //Cache the helper size
        this._cacheHelperProportions();

        /*
         * - Position generation -
         * This block generates everything position related - it's the core of draggables.
         */

        //Cache the margins of the original element
        this._cacheMargins();

        //Get the next scrolling parent
        this.scrollParent = this.helper.scrollParent();

        //The element's absolute position on the page minus margins
        this.offset = this.currentItem.offset();
        this.offset = {
            top: this.offset.top - this.margins.top,
            left: this.offset.left - this.margins.left
        };

        // Only after we got the offset, we can change the helper's position to absolute
        // TODO: Still need to figure out a way to make relative sorting possible
        this.helper.css("position", "absolute");
        this.cssPosition = this.helper.css("position");

        $.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);

        //Cache the former DOM position
        this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };

        //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
        if(this.helper[0] != this.currentItem[0]) {
            this.currentItem.hide();
        }

        //Create the placeholder
        this._createPlaceholder();

        //Set a containment if given in the options
        if(o.containment)
            this._setContainment();

        if(o.cursor) { // cursor option
            if ($('body').css("cursor")) this._storedCursor = $('body').css("cursor");
            $('body').css("cursor", o.cursor);
        }

        if(o.opacity) { // opacity option
            if (this.helper.css("opacity")) this._storedOpacity = this.helper.css("opacity");
            this.helper.css("opacity", o.opacity);
        }

        if(o.zIndex) { // zIndex option
            if (this.helper.css("zIndex")) this._storedZIndex = this.helper.css("zIndex");
            this.helper.css("zIndex", o.zIndex);
        }

        //Prepare scrolling
        if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML')
            this.overflowOffset = this.scrollParent.offset();

        //Call callbacks
        this._trigger("start", event, this._uiHash());

        //Recache the helper size
        if(!this._preserveHelperProportions)
            this._cacheHelperProportions();


        //Post 'activate' events to possible containers
        if(!noActivation) {
             for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i]._trigger("activate", event, self._uiHash(this)); }
        }

        //Prepare possible droppables
        if($.ui.ddmanager)
            $.ui.ddmanager.current = this;

        if ($.ui.ddmanager && !o.dropBehaviour)
            $.ui.ddmanager.prepareOffsets(this, event);

        this.dragging = true;

        this.helper.addClass("ui-sortable-helper");
        this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
        return true;

    },

    _mouseDrag: function(event) {

        //Compute the helpers position
        this.position = this._generatePosition(event);
        this.positionAbs = this._convertPositionTo("absolute");

        if (!this.lastPositionAbs) {
            this.lastPositionAbs = this.positionAbs;
        }

        //Do scrolling
        if(this.options.scroll) {
            var o = this.options, scrolled = false;
            if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') {

                if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
                    this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
                else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity)
                    this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;

                if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
                    this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
                else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity)
                    this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;

            } else {

                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(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(this, event);
        }

        //Regenerate the absolute position used for position checks
        this.positionAbs = this._convertPositionTo("absolute");

        //Set the helper 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';

        var options_axis = this.options.axis;

        var pos_left = this.position.left;
        var pos_top = this.position.top;    

        this.helper.each(function(i) {
            if(!options_axis || options_axis != "y") this.style.left = pos_left + 'px';
            if(!options_axis || options_axis != "x") this.style.top = pos_top+ ($(this).outerHeight() * i) + 'px';
        });

        //Rearrange
        for (var i = this.items.length - 1; i >= 0; i--) {

            //Cache variables and intersection, continue if no intersection
            var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item);
            if (!intersection) continue;

            if(itemElement != this.currentItem[0] //cannot intersect with itself
                &&  this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before
                &&  !$.ui.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked
                && (this.options.type == 'semi-dynamic' ? !$.ui.contains(this.element[0], itemElement) : true)
            ) {

                this.direction = intersection == 1 ? "down" : "up";

                if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) {
                    this._rearrange(event, item);
                } else {
                    break;
                }

                this._trigger("change", event, this._uiHash());
                break;
            }
        }

        //Post events to containers
        this._contactContainers(event);

        //Interconnect with droppables
        if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);

        //Call callbacks
        this._trigger('sort', event, this._uiHash());

        this.lastPositionAbs = this.positionAbs;
        return false;

    },

    _createHelper: function(event) {

        var o = this.options;

        if (this.currentItem.hasClass('ui-multisort-grouped')) {
            var helper = $(this.currentItem).add($(this.currentItem).siblings('.ui-multisort-grouped')).clone();
            $(this.currentItem).siblings('.ui-multisort-grouped').hide();

            if(!helper.parents('body').length) {
                //Add the helper to the DOM if that didn't happen already
                var parentNode = $(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0];

                $(helper).each(function(i) {
                    parentNode.appendChild(helper[i]);
                });
            }
        } else {
            var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper == 'clone' ? this.currentItem.clone() : this.currentItem);

            if(!helper.parents('body').length) //Add the helper to the DOM if that didn't happen already
                $(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);          
        }



        if(helper[0] == this.currentItem[0])
            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") };

        if(helper[0].style.width == '' || o.forceHelperSize) helper.width(this.currentItem.width());
        if(helper[0].style.height == '' || o.forceHelperSize) helper.height(this.currentItem.height());

        return helper;

    },

    _clear: function(event, noPropagation) {

        this.reverting = false;
        // We delay all events that have to be triggered to after the point where the placeholder has been removed and
        // everything else normalized again
        var delayedTriggers = [], self = this;

        // We first have to update the dom position of the actual currentItem
        // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
        if(!this._noFinalSort && this.currentItem[0].parentNode) this.placeholder.before(this.currentItem);
        this._noFinalSort = null;

        if(this.helper[0] == this.currentItem[0]) {
            for(var i in this._storedCSS) {
                if(this._storedCSS[i] == 'auto' || this._storedCSS[i] == 'static') this._storedCSS[i] = '';
            }
            this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
        } else {
            if ($(this.currentItem).parent().children().size() > 0) {
                $(this.currentItem).siblings('.ui-multisort-grouped').show();
            }
            this.currentItem.show();
        }

        if(this.fromOutside && !noPropagation) delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
        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
        if(!$.ui.contains(this.element[0], this.currentItem[0])) { //Node was moved out of the current element
            if(!noPropagation) delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
            for (var i = this.containers.length - 1; i >= 0; i--){
                if($.ui.contains(this.containers[i].element[0], this.currentItem[0]) && !noPropagation) {
                    delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); };  }).call(this, this.containers[i]));
                    delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this));  }; }).call(this, this.containers[i]));
                }
            };
        };

        //Post events to containers
        for (var i = this.containers.length - 1; i >= 0; i--){
            if(!noPropagation) delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); };  }).call(this, this.containers[i]));
            if(this.containers[i].containerCache.over) {
                delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); };  }).call(this, this.containers[i]));
                this.containers[i].containerCache.over = 0;
            }
        }

        //Do what was originally in plugins
        if(this._storedCursor) $('body').css("cursor", this._storedCursor); //Reset cursor
        if(this._storedOpacity) this.helper.css("opacity", this._storedOpacity); //Reset cursor
        if(this._storedZIndex) this.helper.css("zIndex", this._storedZIndex == 'auto' ? '' : this._storedZIndex); //Reset z-index

        this.dragging = false;
        if(this.cancelHelperRemoval) {
            if(!noPropagation) {
                this._trigger("beforeStop", event, this._uiHash());
                for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events
                this._trigger("stop", event, this._uiHash());
            }
            return false;
        }

        if(!noPropagation) this._trigger("beforeStop", event, this._uiHash());

        //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
        if (this.placeholder[0].parentNode) {
            this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
        }

        if(this.helper[0] != this.currentItem[0]) this.helper.remove(); this.helper = null;

        if(!noPropagation) {
            for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events
            this._trigger("stop", event, this._uiHash());
        }

        this.fromOutside = false;
        return true;

    },

}));

$.extend($.ui.multisortable, {
    getter: "serialize toArray",
    version: "1.7.2",
    eventPrefix: "sort",
    defaults: {
        appendTo: "parent",
        axis: false,
        cancel: ":input,option",
        connectWith: false,
        containment: false,
        cursor: 'auto',
        cursorAt: false,
        delay: 0,
        distance: 1,
        dropOnEmpty: true,
        forcePlaceholderSize: false,
        forceHelperSize: false,
        grid: false,
        handle: false,
        helper: "original",
        items: '> *',
        opacity: false,
        placeholder: false,
        revert: false,
        scroll: true,
        scrollSensitivity: 20,
        scrollSpeed: 20,
        scope: "default",
        tolerance: "intersect",
        zIndex: 1000
    }
});

})(jQuery);
于 2013-06-06T21:49:53.807 回答