开发者

Dojo extending dojo.dnd.Source, move not happening. Ideas?

NOTICE: THIS IS SOLVED, I WILL PUBLISH THE SOLUTION HERE ASAP.

Hey all,

Ok... I have a simple dojo page with the bare essentials. Three UL's with some LI's in them. The idea si to allow drag-n-drop among them but if any UL goes empty due to the last item being dragged out, I will put up a message to the user to gie them some instructions.

In order to do that, I wanted to extend the dojo.dnd.Source dijit and add some intelligence. It seemed easy enough. To keep things simple (I am loading Dojo from a CDN) I am simply declating my extension as opposed to doing full on module load. The declaration function is here...

function declare_mockupSmartDndUl(){
dojo.require("dojo.dnd.Source");
dojo.provide("mockup.SmartDndUl");
dojo.declare("mockup.SmartDndUl", dojo.dnd.Source, {
    markupFactory: function(params, node){
        //params._skipStartup = true;
        return new mockup.SmartDndUl(node, params);
    },
    onDndDrop: function(source, nodes, copy){
        console.debug('onDndDrop!');    
        if(this == source){
            // reordering items
            console.debug('moving items from us');
            // DO SOMETHING HERE
        }else{
            // moving items to us
            console.debug('moving items to us');
            // DO SOMETHING HERE
        }

        console.debug('this = ' + this );
        console.debug('source = ' + source );   
        console.debug('nodes = ' + nodes);
        console.debug('copy = ' + copy);
        return dojo.dnd.Source.prototype.onDndDrop.call(this, source, nodes, copy);
    }   
});
}

I have a init function to use this to decorate the lists...

dojo.addOnLoad(function(){
declare_mockupSmartDndUl();
if(dojo.byId('list1')){
    //new mockup.SmartDndUl(dojo.byId('list1'));
    new dojo.dnd.Source(dojo.byId('list1'));
}

if(dojo.byId('list2')){
    new mockup.SmartDndUl(dojo.byId('list2'));
    //new dojo.dnd.Source(dojo.byId('list2'));
}

if(dojo.byId('list3')){
    new mockup.SmartDndUl(dojo.byId('list3'));
    //new dojo.dnd.Source(dojo.byId('list3'));
}
});

It is fine as far as it goes, you will notice I left "list1" as a standard dojo dnd source for testing.

The problem is this - list1 will happily accept items from lists 2 & 3 who will move or copy as apprriate. However lists 2 & 3 refuce to accept items from list1. It is as if the DND operation is being cancelled, but the debugger does show the dojo.dnd.Source.prototype.onDndDrop.call happening, and the paramaters do look ok to me.

Now, the documentation here is really weak, so the example I took some of this from may be way out of date (I am using 1.4).

Ca开发者_如何学Cn anyone fill me in on what might be the issue with my extension dijit?

Thanks!


If you use Dojo XD loader (used with CDNs), all dojo.require() are asynchronous. Yet declare_mockupSmartDndUl() assumes that as soon as it requires dojo.dnd.Source it is available. Generally it is not guaranteed.

Another nitpicking: dojo.dnd.Source is not a widget/dijit, while it is scriptable and can be used with the Dojo Markup, it doesn't implement any Dijit's interfaces.

Now the problem — the method you are overriding has following definition in 1.4:

onDndDrop: function(source, nodes, copy, target){
    // summary:
    //      topic event processor for /dnd/drop, called to finish the DnD operation
    // source: Object
    //      the source which provides items
    // nodes: Array
    //      the list of transferred items
    // copy: Boolean
    //      copy items, if true, move items otherwise
    // target: Object
    //      the target which accepts items
    if(this == target){
        // this one is for us => move nodes!
        this.onDrop(source, nodes, copy);
    }
    this.onDndCancel();
},

Notice that it has 4 arguments, not 3. As you can see if you do not pass the 4th argument, onDrop is never going to be called by the parent method.

Fix these two problems and most probably you'll get what you want.


In the end, I hit the Dojo IRC (great folks!) and we ended up (so far) with this...

    function declare_mockupSmartDndUl(){
    dojo.require("dojo.dnd.Source");
    dojo.provide("mockup.SmartDndUl");
    dojo.declare("mockup.SmartDndUl", dojo.dnd.Source, {
        markupFactory: function(params, node){
            //params._skipStartup = true;
            return new mockup.SmartDndUl(node, params);
        },
        onDropExternal: function(source, nodes, copy){
            console.debug('onDropExternal called...');  

            // dojo.destroy(this.getAllNodes().query(".dndInstructions"));
            this.inherited(arguments);

            var x = source.getAllNodes().length;
            if( x == 0 ){
                newnode = document.createElement('li');
                newnode.innerHTML = "You can drag stuff here!";
                dojo.addClass(newnode,"dndInstructions");
                source.node.appendChild(newnode);
            }

            return true;
            // return dojo.dnd.Source.prototype.onDropExternal.call(this, source, nodes, copy);
        }   
    });
}

And you can see where I am heading, I put in a message when the source is empty (client specs, ug!) and I need to find a way to kill it when something gets dragged in (since it is not, by definition, empty any more ona incomming drag!). That part isnt workign so well.

Anyway, the magic was not to use the onDnd_____ functions, but the higher level one and then call this.inherited(arguments) to fire off the built in functionality.

Thanks!


dojo.require("dojo.dnd.Source");
dojo.provide("mockup.SmartDndUl");
dojo.declare("mockup.SmartDndUl", dojo.dnd.Source, {

Dojo require statement and declare statement are next to next. I think that will cause dependencies problem.

the dojo require statement should go outside onload block and the declare statement should be in onload block.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜