PDA

View Full Version : Ext2.2: notifyEnter and notifyOut not reliable?



FredrikWendt
18 Jan 2009, 1:22 PM
Hi.

On my left I have list of items (a DataView) where each item has a DragSource setup. To my right I've a list of Ext.Panels, each set up with a DropTarget. Both source and targets belong to the same group. The usability goal is to drag items from the left and insert a reference to them in a list to the right.

The issue I have is that the DropTargets get notifyEnter and notifyOut calls out of sync and sometimes not at all. The only method I'm overriding is DropTarget.notifyDrop. The effect is that the css class I've specified in DropTarget.overClass gets stuck. I've only tested with FF3 so far, but it's really unreliable. All other drag-n-drop operations works perfect otherwise - I have no issues but this one.

I expected notifyOut to be called on the target that's left before receiving notifyEnter on the target that the drag is moving onto. A call trace would be notifyEnter, notifyOut, notifyEnter, notifyOut when moving over two targets. Having notifyEnter being called "out of sync" (notifyEnter, notifyEnter, notifyOut, notifyOut) would be all OK but not receiving notifyOut calls really messes up the UI, leaving several targets with overClass set when it should not be.

Any hints on what I could be doing wrong? Workaround suggestions very welcome too, the application is complete with this only bug left to squash.

Code:

Ext.extend(js.ContentDataView, Ext.DataView, {
/**
* Adds a drag source definition to each node created by the parent's
* refresh method.
*/
refresh: function() {
js.ContentDataView.superclass.refresh.call(this, arguments);
var nodes = this.getNodes();
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
var record = this.getRecord(node);
record.dragSource = new Ext.dd.DragSource(node, {
dragData: record.json,
ddGroup: 'contentDragSource'
});
}
}
});


_addDropTarget: function(slidePanel) {
var controller = this.controller;
slidePanel.dropZone = new Ext.dd.DropTarget(slidePanel.el, {
overClass: 'tt_slide_drag_over',
ddGroup: 'contentDragSource',
notifyDrop: function(dragSource, event, customData){
controller.addContent(customData, slidePanel.slide);
event.stopEvent();
return true;
}
});
},

FredrikWendt
18 Jan 2009, 1:43 PM
The image below shows the bug. On the left is music album covers that has been dragged and dropped on the right area a couple of times (each block in the list to the right is a DropTarget). As you can see, it contains several green lines, added via overClass (and not removed) because notifyOut calls weren't made.

http://wendt.se/software/extjs/drag-n-drop/dnd.png

FredrikWendt
18 Jan 2009, 1:55 PM
And the CSS I've added is:

.tt_slide_drag_over {
border-top: 3px solid #00ff00;
}

FredrikWendt
18 Jan 2009, 2:26 PM
It wasn't that easy - I get notifyOut with wrong scope, which explains the strange behaviour. However, WHY the scope is wrong is unknown. I'll not bother looking into this (unless the client asks for it - more beautiful drag-n-drop).

My workaround is to use a short "blink".

_addDropTarget: function(slidePanel) {
var controller = this.slideshowModel;
slidePanel.dropZone = new Ext.dd.DropTarget(slidePanel.el, {
ddGroup: 'contentDragSource',
notifyDrop: function(dragSource, event, customData){
controller.addContent(customData, slidePanel.slide);
event.stopEvent();
return true;
},
notifyEnter: function() {
var elem = this.el;
console.log('[X] ' + elem.id);
elem.addClass('tt_slide_drag_over');
setTimeout(function() {
elem.removeClass('tt_slide_drag_over');
console.log('[_] ' + elem.id);
}, 300);
}
});
},


PS. I tried adding "border-top: 3px solid #ffffff" to the base class to see if it had anything to do with the size/height changing, but that didn't help (wrong this scope is the problem). DS

Animal
19 Jan 2009, 12:49 AM
What "wrong" scope?

You poke functions INTO the DropTarget object. Obviously the DropTarget calls those using "this.notifyEnter()".

If you need a reference to some other object in the DropTarget, configure it in.



_addDropTarget: function(slidePanel) {
var controller = this.slideshowModel;
slidePanel.dropZone = new Ext.dd.DropTarget(slidePanel.el, {
client: this, // Now we can use "client.blah..."
ddGroup: 'contentDragSource',
notifyDrop: function(dragSource, event, customData){
controller.addContent(customData, slidePanel.slide);
event.stopEvent();
return true;
},
notifyEnter: function() {
var elem = this.el;
console.log('[X] ' + elem.id);
elem.addClass('tt_slide_drag_over');
setTimeout(function() {
elem.removeClass('tt_slide_drag_over');
console.log('[_] ' + elem.id);
}, 300);
}
});
},

FredrikWendt
19 Jan 2009, 1:35 PM
What "wrong" scope?

You poke functions INTO the DropTarget object. Obviously the DropTarget calls those using "this.notifyEnter()".


Dear Animal, I really don't know what you're after (you replied to my workaround, which works as expected). My problem is that the second part of code, in the first post, behaves in a way I didn't expect it to (doesn't mean that it's wrong) - and that's just configuration of the DropTarget according to it's docs.

Expectation:
overClass is added when dragging over a drop target.
overClass is removed when dragging away from a drop target.

However, if I use something like:


_addDropTarget: function(slidePanel) {
var controller = this.controller;
slidePanel.dropZone = new Ext.dd.DropTarget(slidePanel.el, {
overClass: 'tt_slide_drag_over',
ddGroup: 'contentDragSource',
notifyEnter: function(dragSource, event, customData){
console.log('Enter ' + this.id);
},
notifyOut: function(dragSource, event, customData){
console.log('Out ' + this.id);
},
});
},
and drag onto dropTargetA and then to dropTargetB, I *sometimes* get a log looking like

Enter dropTargetA
Enter dropTargetB
Out dropTargetB
which leaves dropTargetA having the overClass class instead of dropTargetB, allthough the mouse pointer now is over dropTargetB. ("Sometimes" is about 50 % of the time.)

Keeping a reference like you point out should work, I just don't get why "this" would be different between notifyEnter and notifyOut calls for the same drop target. I'll read through DropTarget to see how it works when I find the time.

FredrikWendt
19 Jan 2009, 1:45 PM
@Animal: Sorry, but keeping a reference like you proposed doesn't help. In fact, I can't get it to work at all (using client inside notifyDrop for instance - however, this.client is populated, but then again "this" is not properly scoped when notifyOut is called).

Animal
20 Jan 2009, 1:08 AM
It works fine for me. I just added logging to the portal demo.

The portal has id "ext-gen22"

Screencast of me testing:

http://i131.photobucket.com/albums/p286/TimeTrialAnimal/th_dd.jpg (http://s131.photobucket.com/albums/p286/TimeTrialAnimal/?action=view&current=dd.flv)

Animal
20 Jan 2009, 1:10 AM
Well, I notice that they shrunk it a bit, but it does just keep repeating



Enter ext-gen22
Out ext-gen22