\r
$.ui.plugin.add("draggable", "connectToSortable", {\r
start: function(e,ui) {\r
+ \r
var inst = $(this).data("draggable");\r
- inst.sortable = $.data($(ui.options.connectToSortable)[0], 'sortable');\r
- inst.sortableOffset = inst.sortable.element.offset();\r
- inst.sortableOuterWidth = inst.sortable.element.outerWidth();\r
- inst.sortableOuterHeight = inst.sortable.element.outerHeight();\r
- if(inst.sortable.options.revert) inst.sortable.shouldRevert = true;\r
+ inst.sortables = [];\r
+ $(ui.options.connectToSortable).each(function() {\r
+ if($.data(this, 'sortable')) inst.sortables.push({\r
+ instance: $.data(this, 'sortable'),\r
+ offset: $.data(this, 'sortable').element.offset(),\r
+ width: $.data(this, 'sortable').element.width(),\r
+ height: $.data(this, 'sortable').element.height(),\r
+ shouldRevert: $.data(this, 'sortable').options.revert\r
+ });\r
+ });\r
+\r
},\r
stop: function(e,ui) {\r
+ \r
//If we are still over the sortable, we fake the stop event of the sortable, but also remove helper\r
- var instDraggable = $(this).data("draggable");\r
- var inst = instDraggable.sortable;\r
- \r
- if(inst.isOver) {\r
- inst.isOver = 0;\r
- instDraggable.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance\r
- inst.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)\r
- if(inst.shouldRevert) inst.options.revert = true; //revert here\r
- inst.stop(e);\r
- inst.options.helper = "original";\r
- }\r
+ var inst = $(this).data("draggable");\r
+ \r
+ $.each(inst.sortables, function() {\r
+ if(this.instance.isOver) {\r
+ this.instance.isOver = 0;\r
+ inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance\r
+ this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)\r
+ if(this.shouldRevert) this.instance.options.revert = true; //revert here\r
+ this.instance.mouseStop(e);\r
+ this.instance.options.helper = "original";\r
+ }\r
+ });\r
+ \r
},\r
drag: function(e,ui) {\r
+\r
//This is handy: We reuse the intersectsWith method for checking if the current draggable helper\r
//intersects with the sortable container\r
- var instDraggable = $(this).data("draggable");\r
- var inst = instDraggable.sortable;\r
- instDraggable.position.absolute = ui.absolutePosition; //Sorry, this is an ugly API fix\r
- \r
- if(inst.intersectsWith.call(instDraggable, {\r
- left: instDraggable.sortableOffset.left, top: instDraggable.sortableOffset.top,\r
- width: instDraggable.sortableOuterWidth, height: instDraggable.sortableOuterHeight\r
- })) {\r
- //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once\r
- if(!inst.isOver) {\r
- inst.isOver = 1;\r
+ var inst = $(this).data("draggable"), self = this;\r
+ inst.position.absolute = ui.absolutePosition; //Sorry, this is an ugly API fix\r
+ \r
+ var checkPos = function(o) {\r
\r
- //Cache the width/height of the new helper\r
- var height = inst.options.placeholderElement ? $(inst.options.placeholderElement, $(inst.options.items, inst.element)).innerHeight() : $(inst.options.items, inst.element).innerHeight();\r
- var width = inst.options.placeholderElement ? $(inst.options.placeholderElement, $(inst.options.items, inst.element)).innerWidth() : $(inst.options.items, inst.element).innerWidth();\r
+ var l = o.left, r = l + o.width,\r
+ t = o.top, b = t + o.height;\r
\r
- //Now we fake the start of dragging for the sortable instance,\r
- //by cloning the list group item, appending it to the sortable and using it as inst.currentItem\r
- //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one)\r
- inst.currentItem = $(this).clone().appendTo(inst.element);\r
- inst.options.helper = function() { return ui.helper[0]; };\r
- inst.start(e);\r
+ return (l < (this.position.absolute.left + this.offset.click.left) && (this.position.absolute.left + this.offset.click.left) < r\r
+ && t < (this.position.absolute.top + this.offset.click.top) && (this.position.absolute.top + this.offset.click.top) < b); \r
+ };\r
+ \r
+ $.each(inst.sortables, function() {\r
+\r
+ if(checkPos.call(inst, {\r
+ left: this.offset.left, top: this.offset.top,\r
+ width: this.width, height: this.height\r
+ })) {\r
+ //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once\r
+ if(!this.instance.isOver) {\r
+ this.instance.isOver = 1;\r
+\r
+ //Cache the width/height of the new helper\r
+ 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();\r
+ 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();\r
\r
- //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes\r
- inst.clickOffset.top = instDraggable.offset.click.top;\r
- inst.clickOffset.left = instDraggable.offset.click.left;\r
- inst.offset.left -= ui.absolutePosition.left - inst.position.absolute.left;\r
- inst.offset.top -= ui.absolutePosition.top - inst.position.absolute.top;\r
+ //Now we fake the start of dragging for the sortable instance,\r
+ //by cloning the list group item, appending it to the sortable and using it as inst.currentItem\r
+ //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one)\r
+ this.instance.currentItem = $(self).clone().appendTo(this.instance.element).data("sortable-item", true);\r
+ this.instance.options.helper = function() { return ui.helper[0]; };\r
\r
- //Do a nifty little helper animation: Animate it to the portlet's size (just takes the first 'li' element in the sortable now)\r
- inst.helperProportions = {width: width, height: height}; //We have to reset the helper proportions, because we are doing our animation there\r
- ui.helper.animate({height: height, width: width}, 500);\r
- instDraggable.propagate("toSortable", e);\r
- \r
- }\r
- \r
- //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable\r
- if(inst.currentItem) inst.drag(e);\r
- \r
- } else {\r
- \r
- //If it doesn't intersect with the sortable, and it intersected before,\r
- //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval\r
- if(inst.isOver) {\r
- inst.isOver = 0;\r
- inst.cancelHelperRemoval = true;\r
- inst.options.revert = false; //No revert here\r
- inst.stop(e);\r
- inst.options.helper = "original";\r
+ e.target = this.instance.currentItem[0];\r
+ this.instance.mouseStart(e, true);\r
+\r
+ //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes\r
+ this.instance.clickOffset.top = inst.offset.click.top;\r
+ this.instance.clickOffset.left = inst.offset.click.left;\r
+ this.instance.offset.left -= ui.absolutePosition.left - this.instance.position.absolute.left;\r
+ this.instance.offset.top -= ui.absolutePosition.top - this.instance.position.absolute.top;\r
+ \r
+ //Do a nifty little helper animation: Animate it to the portlet's size (just takes the first 'li' element in the sortable now)\r
+ this.instance.helperProportions = {width: width, height: height}; //We have to reset the helper proportions, because we are doing our animation there\r
+ ui.helper.animate({height: height, width: width}, 500);\r
+ inst.propagate("toSortable", e);\r
\r
- //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size\r
- inst.currentItem.remove();\r
- inst.placeholder.remove();\r
+ }\r
\r
- ui.helper.animate({ height: this.innerHeight(), width: this.innerWidth() }, 500);\r
- instDraggable.propagate("fromSortable", e);\r
- }\r
- \r
- };\r
+ //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable\r
+ if(this.instance.currentItem) this.instance.mouseDrag(e);\r
+ \r
+ } else {\r
+ \r
+ //If it doesn't intersect with the sortable, and it intersected before,\r
+ //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval\r
+ if(this.instance.isOver) {\r
+ this.instance.isOver = 0;\r
+ this.instance.cancelHelperRemoval = true;\r
+ this.instance.options.revert = false; //No revert here\r
+ this.instance.mouseStop(e);\r
+ this.instance.options.helper = "original";\r
+ \r
+ //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size\r
+ this.instance.currentItem.remove();\r
+ this.instance.placeholder.remove();\r
+ \r
+ ui.helper.animate({ height: self.innerHeight(), width: self.innerWidth() }, 500);\r
+ inst.propagate("fromSortable", e);\r
+ }\r
+ \r
+ };\r
+\r
+ });\r
+\r
}\r
});\r
\r
\r
}; \r
},\r
- mouseStart: function(e) {\r
- \r
+ mouseStart: function(e, overrideHandle) {\r
+ \r
var o = this.options;\r
this.currentContainer = this;\r
\r
}\r
});\r
if($.data(e.target, 'sortable-item')) currentItem = $(e.target);\r
- \r
- if(!currentItem) return false; \r
- if(this.options.handle) {\r
+ \r
+ if(!currentItem) return false;\r
+ if(this.options.handle && !overrideHandle) {\r
var validHandle = false;\r
$(this.options.handle, currentItem).each(function() { if(this == e.target) validHandle = true; });\r
if(!validHandle) return false;\r
//The relative click offset\r
this.offsets.parent = this.offsetParent.offset();\r
this.clickOffset = { left: e.pageX - this.offsets.absolute.left, top: e.pageY - this.offsets.absolute.top };\r
- \r
+ \r
this.originalPosition = {\r
left: this.offsets.absolute.left - this.offsets.parent.left - this.margins.left,\r
top: this.offsets.absolute.top - this.offsets.parent.top - this.margins.top\r
\r
$.ui.plugin.add("sortable", "revert", {\r
stop: function(e, ui) {\r
- var self = ui.instance;\r
+ var self = this.data("sortable");\r
self.cancelHelperRemoval = true;\r
var cur = self.currentItem.offset();\r
var op = self.helper.offsetParent().offset();\r
- 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\r
+ 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\r
\r
//Also animate the placeholder if we have one\r
- if(ui.instance.placeholder) ui.instance.placeholder.animate({ opacity: 'hide' }, parseInt(ui.options.revert, 10) || 500);\r
+ if(self.placeholder) self.placeholder.animate({ opacity: 'hide' }, parseInt(ui.options.revert, 10) || 500);\r
\r
\r
ui.helper.animate({\r
\r
$.ui.plugin.add("sortable", "axis", {\r
sort: function(e, ui) {\r
- var o = ui.options;\r
+ var o = ui.options, inst = this.data("sortable");\r
if(o.constraint) o.axis = o.constraint; //Legacy check\r
- o.axis == 'x' ? ui.instance.position.current.top = ui.instance.originalPosition.top : ui.instance.position.current.left = ui.instance.originalPosition.left;\r
+ o.axis == 'x' ? inst.position.current.top = inst.originalPosition.top : inst.position.current.left = inst.originalPosition.left;\r
}\r
});\r
\r
$.ui.plugin.add("sortable", "scroll", {\r
start: function(e, ui) {\r
- var o = ui.options;\r
+ var o = ui.options, inst = this.data("sortable");\r
o.scrollSensitivity = o.scrollSensitivity || 20;\r
o.scrollSpeed = o.scrollSpeed || 20;\r
\r
- ui.instance.overflowY = function(el) {\r
+ inst.overflowY = function(el) {\r
do { if((/auto|scroll/).test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-y'))) return el; el = el.parent(); } while (el[0].parentNode);\r
return $(document);\r
}(this);\r
- ui.instance.overflowX = function(el) {\r
+ inst.overflowX = function(el) {\r
do { if((/auto|scroll/).test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-x'))) return el; el = el.parent(); } while (el[0].parentNode);\r
return $(document);\r
}(this);\r
\r
- if(ui.instance.overflowY[0] != document && ui.instance.overflowY[0].tagName != 'HTML') ui.instance.overflowYstart = ui.instance.overflowY[0].scrollTop;\r
- if(ui.instance.overflowX[0] != document && ui.instance.overflowX[0].tagName != 'HTML') ui.instance.overflowXstart = ui.instance.overflowX[0].scrollLeft;\r
+ if(inst.overflowY[0] != document && inst.overflowY[0].tagName != 'HTML') inst.overflowYstart = inst.overflowY[0].scrollTop;\r
+ if(inst.overflowX[0] != document && inst.overflowX[0].tagName != 'HTML') inst.overflowXstart = inst.overflowX[0].scrollLeft;\r
\r
},\r
sort: function(e, ui) {\r
\r
var o = ui.options;\r
- var i = ui.instance;\r
+ var i = this.data("sortable");\r
\r
if(i.overflowY[0] != document && i.overflowY[0].tagName != 'HTML') {\r
if(i.overflowY[0].offsetHeight - (ui.position.top - i.overflowY[0].scrollTop + i.clickOffset.top) < o.scrollSensitivity)\r
$(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);\r
}\r
\r
- //ui.instance.recallOffset(e);\r
i.offset = {\r
left: i.mouse.start.left - i.originalPosition.left + (i.overflowXstart !== undefined ? i.overflowXstart - i.overflowX[0].scrollLeft : 0),\r
top: i.mouse.start.top - i.originalPosition.top + (i.overflowYstart !== undefined ? i.overflowYstart - i.overflowX[0].scrollTop : 0)\r