From d0d8ee752df025ed109fdab002e19bc1c406d727 Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Sun, 25 May 2008 18:24:02 +0000 Subject: [PATCH] sortable,draggable: made connectToSortable work again, now works with multiple sortables (closes #2785) --- ui/source/ui.draggable.js | 164 ++++++++++++++++++++++---------------- ui/source/ui.sortable.js | 35 ++++---- 2 files changed, 112 insertions(+), 87 deletions(-) diff --git a/ui/source/ui.draggable.js b/ui/source/ui.draggable.js index ac74ae00a..746326d04 100644 --- a/ui/source/ui.draggable.js +++ b/ui/source/ui.draggable.js @@ -423,89 +423,115 @@ $.ui.plugin.add("draggable", "connectToSortable", { start: function(e,ui) { + var inst = $(this).data("draggable"); - inst.sortable = $.data($(ui.options.connectToSortable)[0], 'sortable'); - inst.sortableOffset = inst.sortable.element.offset(); - inst.sortableOuterWidth = inst.sortable.element.outerWidth(); - inst.sortableOuterHeight = inst.sortable.element.outerHeight(); - if(inst.sortable.options.revert) inst.sortable.shouldRevert = true; + inst.sortables = []; + $(ui.options.connectToSortable).each(function() { + if($.data(this, 'sortable')) inst.sortables.push({ + instance: $.data(this, 'sortable'), + offset: $.data(this, 'sortable').element.offset(), + width: $.data(this, 'sortable').element.width(), + height: $.data(this, 'sortable').element.height(), + shouldRevert: $.data(this, 'sortable').options.revert + }); + }); + }, stop: function(e,ui) { + //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper - var instDraggable = $(this).data("draggable"); - var inst = instDraggable.sortable; - - if(inst.isOver) { - inst.isOver = 0; - instDraggable.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance - inst.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work) - if(inst.shouldRevert) inst.options.revert = true; //revert here - inst.stop(e); - inst.options.helper = "original"; - } + 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); + this.instance.options.helper = "original"; + } + }); + }, drag: function(e,ui) { + //This is handy: We reuse the intersectsWith method for checking if the current draggable helper //intersects with the sortable container - var instDraggable = $(this).data("draggable"); - var inst = instDraggable.sortable; - instDraggable.position.absolute = ui.absolutePosition; //Sorry, this is an ugly API fix - - if(inst.intersectsWith.call(instDraggable, { - left: instDraggable.sortableOffset.left, top: instDraggable.sortableOffset.top, - width: instDraggable.sortableOuterWidth, height: instDraggable.sortableOuterHeight - })) { - //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once - if(!inst.isOver) { - inst.isOver = 1; + var inst = $(this).data("draggable"), self = this; + inst.position.absolute = ui.absolutePosition; //Sorry, this is an ugly API fix + + var checkPos = function(o) { - //Cache the width/height of the new helper - var height = inst.options.placeholderElement ? $(inst.options.placeholderElement, $(inst.options.items, inst.element)).innerHeight() : $(inst.options.items, inst.element).innerHeight(); - var width = inst.options.placeholderElement ? $(inst.options.placeholderElement, $(inst.options.items, inst.element)).innerWidth() : $(inst.options.items, inst.element).innerWidth(); + var l = o.left, r = l + o.width, + t = o.top, b = t + o.height; - //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) - inst.currentItem = $(this).clone().appendTo(inst.element); - inst.options.helper = function() { return ui.helper[0]; }; - inst.start(e); + return (l < (this.position.absolute.left + this.offset.click.left) && (this.position.absolute.left + this.offset.click.left) < r + && t < (this.position.absolute.top + this.offset.click.top) && (this.position.absolute.top + this.offset.click.top) < b); + }; + + $.each(inst.sortables, function() { + + if(checkPos.call(inst, { + left: this.offset.left, top: this.offset.top, + width: this.width, height: this.height + })) { + //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; + + //Cache the width/height of the new helper + var height = this.instance.options.placeholderElement ? $(this.instance.options.placeholderElement, $(this.instance.options.items, this.instance.element)).innerHeight() : $(this.instance.options.items, this.instance.element).innerHeight(); + var width = this.instance.options.placeholderElement ? $(this.instance.options.placeholderElement, $(this.instance.options.items, this.instance.element)).innerWidth() : $(this.instance.options.items, this.instance.element).innerWidth(); - //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes - inst.clickOffset.top = instDraggable.offset.click.top; - inst.clickOffset.left = instDraggable.offset.click.left; - inst.offset.left -= ui.absolutePosition.left - inst.position.absolute.left; - inst.offset.top -= ui.absolutePosition.top - inst.position.absolute.top; + //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 = function() { return ui.helper[0]; }; - //Do a nifty little helper animation: Animate it to the portlet's size (just takes the first 'li' element in the sortable now) - inst.helperProportions = {width: width, height: height}; //We have to reset the helper proportions, because we are doing our animation there - ui.helper.animate({height: height, width: width}, 500); - instDraggable.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(inst.currentItem) inst.drag(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(inst.isOver) { - inst.isOver = 0; - inst.cancelHelperRemoval = true; - inst.options.revert = false; //No revert here - inst.stop(e); - inst.options.helper = "original"; + e.target = this.instance.currentItem[0]; + this.instance.mouseStart(e, true); + + //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes + this.instance.clickOffset.top = inst.offset.click.top; + this.instance.clickOffset.left = inst.offset.click.left; + this.instance.offset.left -= ui.absolutePosition.left - this.instance.position.absolute.left; + this.instance.offset.top -= ui.absolutePosition.top - this.instance.position.absolute.top; + + //Do a nifty little helper animation: Animate it to the portlet's size (just takes the first 'li' element in the sortable now) + this.instance.helperProportions = {width: width, height: height}; //We have to reset the helper proportions, because we are doing our animation there + ui.helper.animate({height: height, width: width}, 500); + inst.propagate("toSortable", e); - //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size - inst.currentItem.remove(); - inst.placeholder.remove(); + } - ui.helper.animate({ height: this.innerHeight(), width: this.innerWidth() }, 500); - instDraggable.propagate("fromSortable", 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); + this.instance.options.helper = "original"; + + //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(); + this.instance.placeholder.remove(); + + ui.helper.animate({ height: self.innerHeight(), width: self.innerWidth() }, 500); + inst.propagate("fromSortable", e); + } + + }; + + }); + } }); diff --git a/ui/source/ui.sortable.js b/ui/source/ui.sortable.js index 8d9c7822d..4c5e00d35 100644 --- a/ui/source/ui.sortable.js +++ b/ui/source/ui.sortable.js @@ -280,8 +280,8 @@ }; }, - mouseStart: function(e) { - + mouseStart: function(e, overrideHandle) { + var o = this.options; this.currentContainer = this; @@ -295,9 +295,9 @@ } }); if($.data(e.target, 'sortable-item')) currentItem = $(e.target); - - if(!currentItem) return false; - if(this.options.handle) { + + if(!currentItem) return false; + if(this.options.handle && !overrideHandle) { var validHandle = false; $(this.options.handle, currentItem).each(function() { if(this == e.target) validHandle = true; }); if(!validHandle) return false; @@ -330,7 +330,7 @@ //The relative click offset this.offsets.parent = this.offsetParent.offset(); this.clickOffset = { left: e.pageX - this.offsets.absolute.left, top: e.pageY - this.offsets.absolute.top }; - + this.originalPosition = { left: this.offsets.absolute.left - this.offsets.parent.left - this.margins.left, top: this.offsets.absolute.top - this.offsets.parent.top - this.margins.top @@ -512,14 +512,14 @@ $.ui.plugin.add("sortable", "revert", { stop: function(e, ui) { - var self = ui.instance; + var self = this.data("sortable"); self.cancelHelperRemoval = true; var cur = self.currentItem.offset(); var op = self.helper.offsetParent().offset(); - if(ui.instance.options.zIndex) ui.helper.css('zIndex', ui.instance.options.zIndex); //Do the zIndex again because it already was resetted by the plugin above on stop + if(self.options.zIndex) ui.helper.css('zIndex', self.options.zIndex); //Do the zIndex again because it already was resetted by the plugin above on stop //Also animate the placeholder if we have one - if(ui.instance.placeholder) ui.instance.placeholder.animate({ opacity: 'hide' }, parseInt(ui.options.revert, 10) || 500); + if(self.placeholder) self.placeholder.animate({ opacity: 'hide' }, parseInt(ui.options.revert, 10) || 500); ui.helper.animate({ @@ -595,35 +595,35 @@ $.ui.plugin.add("sortable", "axis", { sort: function(e, ui) { - var o = ui.options; + var o = ui.options, inst = this.data("sortable"); if(o.constraint) o.axis = o.constraint; //Legacy check - o.axis == 'x' ? ui.instance.position.current.top = ui.instance.originalPosition.top : ui.instance.position.current.left = ui.instance.originalPosition.left; + o.axis == 'x' ? inst.position.current.top = inst.originalPosition.top : inst.position.current.left = inst.originalPosition.left; } }); $.ui.plugin.add("sortable", "scroll", { start: function(e, ui) { - var o = ui.options; + var o = ui.options, inst = this.data("sortable"); o.scrollSensitivity = o.scrollSensitivity || 20; o.scrollSpeed = o.scrollSpeed || 20; - ui.instance.overflowY = function(el) { + inst.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); - ui.instance.overflowX = function(el) { + inst.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(ui.instance.overflowY[0] != document && ui.instance.overflowY[0].tagName != 'HTML') ui.instance.overflowYstart = ui.instance.overflowY[0].scrollTop; - if(ui.instance.overflowX[0] != document && ui.instance.overflowX[0].tagName != 'HTML') ui.instance.overflowXstart = ui.instance.overflowX[0].scrollLeft; + if(inst.overflowY[0] != document && inst.overflowY[0].tagName != 'HTML') inst.overflowYstart = inst.overflowY[0].scrollTop; + if(inst.overflowX[0] != document && inst.overflowX[0].tagName != 'HTML') inst.overflowXstart = inst.overflowX[0].scrollLeft; }, sort: function(e, ui) { var o = ui.options; - var i = ui.instance; + var i = this.data("sortable"); if(i.overflowY[0] != document && i.overflowY[0].tagName != 'HTML') { if(i.overflowY[0].offsetHeight - (ui.position.top - i.overflowY[0].scrollTop + i.clickOffset.top) < o.scrollSensitivity) @@ -650,7 +650,6 @@ $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); } - //ui.instance.recallOffset(e); i.offset = { left: i.mouse.start.left - i.originalPosition.left + (i.overflowXstart !== undefined ? i.overflowXstart - i.overflowX[0].scrollLeft : 0), top: i.mouse.start.top - i.originalPosition.top + (i.overflowYstart !== undefined ? i.overflowYstart - i.overflowX[0].scrollTop : 0) -- 2.39.5