1. #1
    Ext JS Premium Member
    Join Date
    Mar 2007
    Location
    France
    Posts
    223
    Vote Rating
    0
    tof is on a distinguished road

      0  

    Smile Sortable Plugin for DataView (Updated for 4.2)

    Sortable Plugin for DataView (Updated for 4.2)


    Hi people,

    I just made a quick & dirty plugin for DataView, which make it sortable by drag/drop.

    Example and code are at : http://tof2k.com/ext/sortable/

    If you find any bug or need any help, you can post questions here !

    Update: Thank you Sighter for an updated, 4.2 compatible version. Code available here, or below :

    Code:
    /**
    /**
     * Plugin (ptype = 'viewsortable') that makes a view "Sortable"
     * via drag/drop.
     */
    Ext.define('Utils.plugins.Sortable', {
    
        extend: 'Ext.AbstractPlugin',
    
        alias: 'plugin.viewsortable',
    
        mixins: {
            observable: 'Ext.util.Observable'
        },
    
        config: {
    
            /** 
             * the event which the plugin should listen on the view,
             *
             * at this moment the plugin initiializes it's drag and drop zones
             */
            eventName: 'render',
    
            /**
             * the class which will be added to the dragged node, then it enters a
             * valid target
             *
             */
            highlightClass: 'my-row-highlight-class'
        },
    
        //logger: log4javascript.getLogger('Utils.plugin.Sortable'),
        logger: {
            debug: function() {return null;}
        },
    
        /**
         * initialize the plugin
         *
         * @private
         */
        init : function(view) {
            this.mixins.observable.constructor.call(this);
    
            this.logger.debug('sortable plugin init:', view);
            this.logger.debug('using event:', this.getEventName());
    
            this.addEvents(
    
                /**
                 * @event
                 * event gets fired after a drag and drop action
                 * was successful
                 *
                 * @param {Utils.plugins.Sortable} this the plugin
                 * @param {Ext.data.Record} draggedRecord the dragged record
                 * @param {Ext.data.Record} targetRecord the record on which the other has droped
                 */
                'aftersort'
            );
    
            this.view = view;
            view.on(this.getEventName(), this.initDragDrop, this);
        },
    
        /**
         * initialize the drag and drop behavior on the view
         *
         * @private
         */
        initDragDrop : function() {
    
            this.logger.debug('init drag and drop');
    
            var me = this;
            var v = this.view;
    
            var dragZone = Ext.create('Ext.dd.DragZone', this.view.getEl(), {
    
                //      On receipt of a mousedown event, see if it is within a DataView node.
                //      Return a drag data object if so.
                getDragData: function(e) {
    
                    // Use the DataView's own itemSelector (a mandatory property) to
                    // test if the mousedown is within one of the DataView's nodes.
                    var sourceEl = e.getTarget(v.itemSelector, 10);
    
                    // If the mousedown is within a DataView node, clone the node to produce
                    // a ddel element for use by the drag proxy. Also add application data
                    // to the returned data object.
                    if (sourceEl) {
                        d = sourceEl.cloneNode(true);
                        d.id = Ext.id();
                        return {
                            ddel: d,
                            sourceEl: sourceEl,
                            repairXY: Ext.fly(sourceEl).getXY(),
                            sourceStore: v.store,
                            draggedRecord: v.getRecord(sourceEl)
                        };
                    }
                },
    
                // Provide coordinates for the proxy to slide back to on failed drag.
                // This is the original XY coordinates of the draggable element captured
                // in the getDragData method.
                getRepairXY: function() {
                    return this.dragData.repairXY;
                }
            });
    
            var dropZone = Ext.create('Ext.dd.DropZone', this.view.getEl(), {
    
                // If the mouse is over a grid row, return that node. This is
                // provided as the "target" parameter in all "onNodeXXXX" node event handling functions
                getTargetFromEvent: function(e) {
                    return e.getTarget(v.itemSelector);
                },
    
                // On entry into a target node, highlight that node.
                onNodeEnter : function(target, dd, e, data){
                    Ext.fly(target).addCls(me.getHighlightClass());
                },
    
                // On exit from a target node, unhighlight that node.
                onNodeOut : function(target, dd, e, data){
                    Ext.fly(target).removeCls(me.getHighlightClass());
                },
    
                // While over a target node, return the default drop allowed class which
                // places a "tick" icon into the drag proxy.
                onNodeOver : function(target, dd, e, data){
                    return Ext.dd.DropZone.prototype.dropAllowed;
                },
    
                // On node drop we can interrogate the target to find the underlying
                // application object that is the real target of the dragged data.
                // In this case, it is a Record in the GridPanel's Store.
                // We can use the data set up by the DragZone's getDragData method to read
                // any data we decided to attach in the DragZone's getDragData method.
                onNodeDrop : function(target, dd, e, data){
                    me.logger.debug('onNodeDrop target', target);
                    me.logger.debug('onNodeDrop data', data);
    
                    var store = v.getStore();
    
                    var index = v.indexOf(target);
                    me.logger.debug('onNodeDrop dropped on', index);
                    
                    var r = store.getAt(index);
    
                    store.remove(data.draggedRecord);
                    store.insert(index, [data.draggedRecord]);
    
                    me.fireEvent('aftersort', me, data.draggedRecord, r);
    
                    // Ext.Msg.alert('Drop gesture', 'Dropped Record id ' + data.draggedRecord.id +
                    //     ' on Record id ' + r.id);
                    return true;
                }
            });
        }
    });
    Last edited by tof; 19 Sep 2014 at 5:50 AM. Reason: Update for ExtJS 4.2
    Christophe Badoit
    aka Tof

    My work : Lesiteimmo.com - Unobstrusive ExtJs Powered !

  2. #2
    Sencha - Community Support Team mystix's Avatar
    Join Date
    Mar 2007
    Location
    Singapore
    Posts
    6,236
    Vote Rating
    5
    mystix will become famous soon enough

      0  

    Default


    yay! more neat stuff!

  3. #3
    Ext JS Premium Member
    Join Date
    Aug 2007
    Location
    Germany
    Posts
    139
    Vote Rating
    1
    Spirit is on a distinguished road

      0  

    Default


    Nice plugin!

    But i have a problem whith catchin the drop event.
    While i m draggin it fires a lot of times and i dunno why. (even if i m not movin the dataview item and drop it back again (release mouse button))

    Any suggestions ?

  4. #4
    Ext JS Premium Member
    Join Date
    Aug 2007
    Location
    Germany
    Posts
    139
    Vote Rating
    1
    Spirit is on a distinguished road

      0  

    Default


    I dunno how i could add a listener to the implicit created plugin, and if i attach it to an explicit plugin "drop" fires too often, as mentioned in my above post.

    I made a minimal change on your code and it works like i would expect it:
    Code:
    		// endDrag : remove dragCls and fire "drop" event
    		dd.endDrag = function(e) {
    			if (!this.dragData) { return true; }
    			Ext.fly(v.getNode(this.dragData.lastIdx)).removeClass(dragCls);
    			v.el.removeClass(viewDragCls);
    			v.fireEvent('drop', this.dragData.origIdx,     // <- changed from self to   v
    				this.dragData.lastIdx, this.dragData.record);
    			return true;
    		};
    Now the event can be catched on dataview as i would have expected it.

  5. #5
    Ext JS Premium Member
    Join Date
    Mar 2007
    Location
    France
    Posts
    223
    Vote Rating
    0
    tof is on a distinguished road

      0  

    Default


    Hi,

    To attach an event to the plugin, you have to, well,... attach the event to the plugin.

    For exemple :

    PHP Code:
    var sortablePlugin = new .....SortableView(...);
    var 
    view = new Ext.DataView({
      
    plugins sortablePlugin,
      ....
    });

    sortablePlugin.on('drop'console.log); 


    Your change is interesting, but I actually didn't want to add an event to the view itself (the view could be a "drop" recipient for something else, who knows ?).
    Christophe Badoit
    aka Tof

    My work : Lesiteimmo.com - Unobstrusive ExtJs Powered !

  6. #6
    Ext JS Premium Member
    Join Date
    Aug 2007
    Location
    Germany
    Posts
    139
    Vote Rating
    1
    Spirit is on a distinguished road

      0  

    Default


    The way you describe is how i would do it and how i have done it before (i called it explicit in my upper post, may be the wrong term for that), but in that case my event fires a bunch of times and not only once.

  7. #7
    Ext JS Premium Member
    Join Date
    Mar 2007
    Location
    France
    Posts
    223
    Vote Rating
    0
    tof is on a distinguished road

      0  

    Default


    if you have firebug, on the test page : http://tof2k.com/ext/sortable/
    You can try this quick & dirty line :

    PHP Code:
    Ext.getCmp('ext-comp-1001').plugins.on('drop'console.log
    It does work for me (on FF2).
    On which browser are you testing ?
    Christophe Badoit
    aka Tof

    My work : Lesiteimmo.com - Unobstrusive ExtJs Powered !

  8. #8
    Ext JS Premium Member
    Join Date
    Aug 2007
    Location
    Germany
    Posts
    139
    Vote Rating
    1
    Spirit is on a distinguished road

      0  

    Default


    I m testing on FF too.

    The last post from you is the way it works.

    So if i attach the event handler
    on "dataview.plugins" as you mentioned in your last post it works also fro me

    But if i attach the it to the explicit created plugin like this:
    var sortablePlugin = new .....SortableView(...);

    var view = new Ext.DataView({

    plugins : sortablePlugin,

    ....

    });
    sortablePlugin.on('drop', console.log);
    It doesnt and fires more than once.

    Ok, i dunno why, but 4 me its ok, now i have both approaches and can get your drop event even on dataview or the plugin, so i m fine with it. Nice plugin

  9. #9
    Sencha User
    Join Date
    Aug 2008
    Posts
    31
    Vote Rating
    0
    Bodom78 is on a distinguished road

      0  

    Default


    Just want to say thanks tof,


    I was about to try something like this out and your plug in really helped me out. Works with dragging items to the DavaView as well which is really nice.

    Cheers

  10. #10
    Ext JS Premium Member
    Join Date
    Mar 2007
    Location
    France
    Posts
    223
    Vote Rating
    0
    tof is on a distinguished road

      0  

    Default


    I'm happy to know it's useful to others
    Christophe Badoit
    aka Tof

    My work : Lesiteimmo.com - Unobstrusive ExtJs Powered !