Skip to main content

Search and Top Navigation

#9337 closed bug (invalid)

Opened May 28, 2013 09:51PM UTC

Closed June 12, 2013 08:35AM UTC

Greedy droppables do not clear highlighting when deeply nested child becomes active if the immediate parent droppable was not active

Reported by: mwadams Owned by: mwadams
Priority: minor Milestone: none
Component: ui.droppable Version: 1.10.3
Keywords: Cc:
Blocked by: Blocking:
Description

Consider a hierarchy:

elem1:droppable, greedy: true, accept: foo

elem2:droppable, greedy: true, accept: bar

elem3:droppable, greedy: true, accept: foo

If you drag a foo over elem1, then elem1 becomes active.

If you continue to drag it over elem2, elem1 stays active, as elem2 did not accept it.

If you continue to drag it over elem3, elem3 becomes active, but elem1 remains active.

This is because the code in ddmanager's drag: function only handles 1 immediate predecessor.

Here's the code in question:

if (this.options.greedy) {
				// find droppable parents with same scope
				scope = this.options.scope;
				parent = this.element.parents(":data(ui-droppable)").filter(function () {
					return $.data(this, "ui-droppable").options.scope === scope;
				});

				if (parent.length) {
				        var parentInstance = $.data(parent[0], "ui-droppable");
				...etc...

The important code is in that $.data(parent[0]...

I've modified the drag function to this:

	drag: function(draggable, event) {

		//If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
		if(draggable.options.refreshPositions) {
			$.ui.ddmanager.prepareOffsets(draggable, event);
		}

		//Run through all droppables and check their positions based on specific tolerance options
		$.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {

			if(this.options.disabled || this.greedyChild || !this.visible) {
				return;
			}

			var scope, parent,
				intersects = $.ui.intersect(draggable, this, this.options.tolerance),
				c = !intersects && this.isover ? "isout" : (intersects && !this.isover ? "isover" : null);
			if(!c) {
				return;
			}

			if (this.options.greedy) {
				// find droppable parents with same scope
				scope = this.options.scope;
				parent = this.element.parents(":data(ui-droppable)").filter(function () {
					return $.data(this, "ui-droppable").options.scope === scope;
				});

				if (parent.length) {
				    for (var parentIndex = 0  ; parentIndex < parent.length ; parentIndex++) {
				        var parentInstance = $.data(parent[parentIndex], "ui-droppable");
				        parentInstance.greedyChild = (c === "isover");
				    }
				}
			}

			// we just moved into a greedy child
			if (parent.length > 0 && c === "isover") {
			    for (var parentIndex = 0  ; parentIndex < parent.length ; parentIndex++) {
			        var parentInstance = $.data(parent[parentIndex], "ui-droppable");
			        parentInstance.isover = false;
			        parentInstance.isout = true;
			        parentInstance._out.call(parentInstance, event);
			    }
			}

			this[c] = true;
			this[c === "isout" ? "isover" : "isout"] = false;
			this[c === "isover" ? "_over" : "_out"].call(this, event);

			// we just moved out of a greedy child
			if (parent.length > 0 && c === "isout") {
			    for (var parentIndex = 0  ; parentIndex < parent.length ; parentIndex++) {
			        var parentInstance = $.data(parent[parentIndex], "ui-droppable");
			        parentInstance.isout = false;
			        parentInstance.isover = true;
			        parentInstance._over.call(parentInstance, event);
			    }
			}
		});

	},

And this seems to fix the problem.

Attachments (0)
Change History (2)

Changed May 29, 2013 01:07AM UTC by tj.vantoll comment:1

component: ui.coreui.droppable
owner: → mwadams
status: newpending

Hi mwadams,

Thanks for taking the time to contribute to the jQuery UI project. Could you please create a test case that shows the behavior you're describing. Seeing this visually should help us understand it. You can use this as a starting point: http://jsfiddle.net/tj_vantoll/8RtqV/.

Changed June 12, 2013 08:35AM UTC by trac-o-bot comment:2

resolution: → invalid
status: pendingclosed

Because we get so many tickets, we often need to return them to the initial reporter for more information. If that person does not reply within 14 days, the ticket will automatically be closed, and that has happened in this case. If you still are interested in pursuing this issue, feel free to add a comment with the requested information and we will be happy to reopen the ticket if it is still valid. Thanks!