1. #1
    Sencha - Community Support Team jsakalos's Avatar
    Join Date
    Apr 2007
    Location
    Slovakia
    Posts
    27,527
    Vote Rating
    378
    jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future

      0  

    Lightbulb Custom Drag and Drop Example

    Custom Drag and Drop Example


    Hi folks,

    reading this forums for a couple of weeks it seems to me that Drag and Drop is still a mystery for many users and a few days ago it was also for me. Now, that I implemented my own drag & drop I've got a little bit more knowledge and experiences on the subject so I think it would be good to share it.

    First of all: see it in action.

    And now comes explanation:

    I'm using proxy dragging in that example what means that I do not drag elements themselves but I create a proxy (a ghost) and I drag that. For this I've extended Ext.dd.DDProxy class as it is nearest to my needs.

    Each panel has its own instance of this extended class (the name of the class is Ext.Accordion.DDDock). There is also one Ext.dd.DropZone for the Accordion dock. Instance of the DropZone is created in the Accordion constructor:

    PHP Code:
    Ext.Accordion = function(elconfig) {
        
        
    // call parent constructor
        
    Ext.Accordion.superclass.constructor.call(thiselconfig);

        
    // code here deleted for clarity

        
    this.dd = new Ext.dd.DropZone(this.body.dom, {ddGroup:'dock-' this.id });

    }; 
    // end of constructor 
    When a panel is added to the Accordion it's own instance of Ext.Accordion.DDDock is created for it:

    PHP Code:
    Ext.extend(Ext.AccordionExt.ContentPanel, {

        
    /**
            * Adds the panel to Accordion
            * @param {Ext.InfoPanel} panel Panel to add
            * @return {Ext.InfoPanel} added panel
            */
        
    add: function(panel) {

            
    // code here deleted for clarity

            // panel dragging
            
    panel.dd = new Ext.Accordion.DDDock(panel'dock-' this.idthis);

            
    // code here deleted for clarity
            
    return panel;
        } 
    And the jewel on the crown is the DDProxy extension itself. Code is well commented so it should be understandable:

    PHP Code:
    /**
        * @class Ext.Accordion.DDDock
        * @constructor
        * @extends Ext.dd.DDProxy
        * @param {Ext.InfoPanel} panel Panel the dragging object is created for
        * @param {String} group Only elements of same group interact
        * @param {Ext.Accordion} dock Place where panels are docked/undocked
        */
    Ext.Accordion.DDDock = function(panelgroupdock) {

        
    // call parent constructor
        
    Ext.Accordion.DDDock.superclass.constructor.call(thispanel.el.domgroup);

        
    // save panel and dock references for use in methods
        
    this.panel panel;
        
    this.dock dock;

        
    // drag by grabbing the title only
        
    this.setHandleElId(panel.titleEl.id);

        
    // move only in the dock if undockable
        
    if(false === dock.undockable) {
            
    this.setXConstraint(00);
        }

        
    // init internal variables
        
    this.lastY 0;
        
    this.dY 0;
        
    this.lastDY 0;

        
    // debugging flag. When true some console logs are produced while dragging
        // Warning! Debugging works only with FF/FB
        
    this.debug false;

    }; 
    // end of constructor
    // }}}

    // extend
    Ext.extend(Ext.Accordion.DDDockExt.dd.DDProxy, {

        
    // {{{
        /**
            * Default DDProxy startDrag override
            * Saves some variable for use by other methods 
            * and creates nice dragging proxy (ghost)
            *
            * Received x, y arguments are not used
            */
        
    startDrag: function(xy) {

            
    // get srcEl (the original) and dragEl (the ghost)
            
    var srcEl Ext.get(this.getEl());
            var 
    dragEl Ext.get(this.getDragEl());

            
    // make the ghost look same as original
            
    dragEl.dom.className srcEl.dom.className;

            
    // semitransparent ghost
            
    dragEl.setOpacity(0.7);

            
    // raise panel's "window" above others
            
    if(!this.panel.docked) {
                
    this.dock.raise(this.panel);
            }

            
    // hide panel's shadow if any
            
    if(this.panel.shadow) {
                
    this.panel.shadow.hide();
            }

            
    // cancel ugly default ghost border and raise it above all panels (windows)
            
    dragEl.applyStyles({'border':'0''z-index'this.dock.zindex this.dock.zindexInc});

            
    // copy the panel's content to ghost
            
    dragEl.update(srcEl.dom.innerHTML);

            
    // position the ghost to the source position
            
    dragEl.setBox(srcEl.getBox());

            
    // clear visibility of panel's body (was setup by animations)
            
    this.panel.body.dom.style.visibility ''

            
    // hide source panel if undocked
            
    if(!this.panel.docked) {
                
    srcEl.hide();
            }

            
    // debugging output
            
    if(this.debug) {
                
    console.info(
                    
    'Start dragging: ' 
                    
    this.panel.id
                    
    ', groups='
                    
    this.groups.toSource()
                )
            } 
    // end of debug output
        
    // end of function startDrag
        // }}}
        // {{{
        /**
            * Default DDProxy onDragOver override
            * It is called when dragging over a panel
            * or over the dock.body DropZone
            *
            * @param {Event} e not used
            * @param {String} targetId id of the target we're over
            *
            * Beware: While dragging over docked panels it's called
            * twice. Once for panel and once for DropZone
            */
        
    onDragOver: function(etargetId) {

            
    // save targetId for use by endDrag
            
    this.lastTarget targetId;

            
    // {{{
            // debugging output
            
    if(this.debug) {
                
    console.log(
                    
    'Dragging panel: '
                    
    this.panel.id
                    
    ' over '
                    
    targetId
                
    );
            } 
    // end of debug output
            // }}}

            // get panel element
            
    var srcEl Ext.get(this.getEl());

            
    // get target panel
            
    var targetPanel this.dock.items.get(targetId);

            
    // do nothing if we're not over another docked panel
            
    if(!targetPanel || !targetPanel.docked) {
                return;
            }

            
    // reorder panels in dock if we're docked too
            
    if(this.panel.docked && targetPanel) {
                var 
    targetEl targetPanel.el;

                
    // we have dY (delta Y) from onDrag method
                
    if(this.dY < -2) {
                    
    srcEl.insertBefore(targetEl);
                }
                else if(
    this.dY 2) {
                    
    srcEl.insertAfter(targetEl);
                }
            }
            return;
        } 
    // end of fucntion onDragOver
        // }}}
        // {{{
        /**
            * Default DDProxy onDrag override
            *
            * It's called whilde dragging
            * @param {Event} e used to get coordinates
            */
        
    onDrag: function(e) {

            
    // get source (original) and proxy (ghost) elements
            
    var srcEl Ext.get(this.getEl());
            var 
    dragEl Ext.get(this.getDragEl());

            
    // calculate dY for onDragOver method
            // todo: the whole hysteresis logic might be simplified
            
    var e.getPageY();
            
    this.dY this.lastY;
            if((
    this.dY && this.lastDY 0) || (this.dY && this.lastDY 0)) {
                
    this.dY 0;
            }
            if(
    this.dY < -|| this.dY 2) {
                
    this.lastY y;
            }
        } 
    // end of function onDrag
        // }}}
        // {{{
        /**
            * Default DDProxy endDrag override
            *
            * Called when dragging is finished
            */
        
    endDrag: function() {

            
    // debugging output
            
    if(this.debug) {
                
    console.info(
                    
    'End dragging:   '
                    
    this.panel.id
                    
    ', groups='
                    
    this.groups.toSource()
                );
            }

            
    // get the source (original) and proxy (ghost) elements
            
    var srcEl Ext.get(this.getEl())
            var 
    dragEl Ext.get(this.getDragEl())

            
    // setup withinDock flag
            
    var box dragEl.getBox();
            var 
    dockBox this.dock.body.getBox();
            var 
    withinDock 
                
    box.<= dockBox.right && box.right >= dockBox.
                
    && box.<= dockBox.bottom && box.bottom >= dockBox.y
            
    ;

            
    // undock the panel if it was dragged outside of dock
            
    if(!withinDock && this.panel.docked) {
                
    this.dock.undock(this.panelbox);
            }

            
    // dock the panel if it was dragged from outside to dock
            
    else if(withinDock && !this.panel.docked) {
                
    this.dock.dock(this.panelthis.lastTarget)
            }

            
    // hide the ghost
            
    dragEl.hide();

            
    // repair/adjust visuals of dropped panel
            
    if(this.panel.docked) {
                
    srcEl.applyStyles({
                    
    'top':''
                    
    'left':''
                    
    'width':''
                    
    'height':''
                    
    'z-index':''
                    
    'position':''
                    
    'visibility':''
                
    });
            }
            else {
                
    srcEl.setBox(dragEl.getBox());
                
    srcEl.applyStyles({
                    
    position:'absolute'
                    
    'z-index'this.panel.zindex
                    
    visibility:''
                    
    height:''
                
    });
            }

            
    /// clear the ghost content and move it off screen
            
    dragEl.update('');
            
    dragEl.applyStyles({
                
    'top':'-9999px'
                
    'left':'-9999px'
                
    'height':'0px'
                
    'width':'0px'
            
    });

            
    // update order of docked panels
            
    this.dock.updateOrder();

            
    // repair the expanded/collapsed states of panels in the dock
            
    if(!this.panel.collapsed && !this.dock.independent && this.panel.docked) {
                
    this.dock.collapseAll(falsethis.panel);
                
    this.dock.expanded this.panel;
            }

            
    // show panel shadow
            
    if(this.panel.shadow && !this.panel.docked) {
                
    this.panel.shadow.show(srcEl);
            }

            
    // let the state manager know the new panel position
            
    this.dock.fireEvent('panelbox'this.panelbox);

            
    // reset internal flags
            
    this.lastY 0;
            
    this.dY 0;
            
    this.lastDY 0;

        } 
    // end of function endDrag
        // }}}

    }); 
    Jozef Sakalos, aka Saki

    Education, extensions and services for developers at new http://extjs.eu
    News: Grid Search Plugin, ExtJS 5 Complex Data Binding using MVVM


  2. #2
    Sencha User
    Join Date
    Mar 2007
    Posts
    761
    Vote Rating
    1
    franklt69 is on a distinguished road

      0  

    Default


    Very good jsakalos, I think is good to community to share this experience, maybe will be a good tutorial to explain how to extend extension to make owner customer widget, and accordion could be a start, or maybe other widget more simple.

    In may case for instance I am learning to use the library, I don't have experience to make some widget and I would like for instance to do a calculator with extension but I don't have idea how to begin, for that a good tutorial explain how to make widget will be good to all community.


    kind regards
    Frank

  3. #3
    Sencha - Community Support Team jsakalos's Avatar
    Join Date
    Apr 2007
    Location
    Slovakia
    Posts
    27,527
    Vote Rating
    378
    jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future

      0  

    Default


    Quote Originally Posted by franklt69 View Post
    Very good jsakalos, I think is good to community to share this experience, maybe will be a good tutorial to explain how to extend extension to make owner customer widget, and accordion could be a start, or maybe other widget more simple.

    In may case for instance I am learning to use the library, I don't have experience to make some widget and I would like for instance to do a calculator with extension but I don't have idea how to begin, for that a good tutorial explain how to make widget will be good to all community.


    kind regards
    Frank
    Hi Frank,

    I don't know if you've noticed but I wrote a pattern on how to extend class: How to extend an Ext class for (not so) Beginners.

    Your first decision would be what class to extend. When I'm thinking of calculator some sort of Dialog seems suitable to me.

    Hi,
    Jozef Sakalos, aka Saki

    Education, extensions and services for developers at new http://extjs.eu
    News: Grid Search Plugin, ExtJS 5 Complex Data Binding using MVVM


  4. #4
    Sencha User
    Join Date
    Mar 2007
    Posts
    761
    Vote Rating
    1
    franklt69 is on a distinguished road

      0  

    Default


    Ok thanks that is a good start, now imagine that I want this requirement:

    1 - the calculator could be appear in a page, ready to use
    2- the calculator could be appear like a Ext.form.DateField, I mean a button and then appear the calculator.
    3- the calculator could be inside a column in a grid, for instance amount column.

    which class in ext will be correct to extend?

    kind regards
    Frank

  5. #5
    Sencha - Community Support Team jsakalos's Avatar
    Join Date
    Apr 2007
    Location
    Slovakia
    Posts
    27,527
    Vote Rating
    378
    jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future

      0  

    Default


    Hmmm,

    in this case the dialog wouldn't be best. I'm not going to name one class but generally:

    You should use class that has most functionalities you need. I was thinking of dialog because it has "window" functionalities so it can be dragged anywhere on the screen and the Calc thus be handy.

    However your points make difference; maybe you could go down to the Element. You'd then be able o put this calculator anywhere: to dialog as content, to layout, grid, etc.

    So you need to think like this: What class has most of functionalities of my new Calc to save as much of my work as possible?

    Hi
    Jozef Sakalos, aka Saki

    Education, extensions and services for developers at new http://extjs.eu
    News: Grid Search Plugin, ExtJS 5 Complex Data Binding using MVVM


  6. #6
    Sencha Premium Member
    Join Date
    Jul 2007
    Posts
    96
    Vote Rating
    1
    Nam is on a distinguished road

      0  

    Question


    I am trying to set up multiple accordions which can have the InfoPanels dragged from one accordion to another. I can't seem to figure out how to get any of the drag event set up. Is there currently this ability already built into Accordion/InfoPanels, or is there some way I can access the events so that I can accomplish this functionality myself?...

    You can see the test of what I am trying to do at http://www.foirc.net/ and if you just want to see the Code which I am trying to use, you can go to http://www.foirc.net/pages/Home/ which is loaded via an Ajax call.

    My goal is to have a dynamic homepage similar to iGoogle which allows for the user to move elements around the page as they wish to make it organized the way they want. Accordion seems to be the best way to do this, but I cannot figure out how to get events set up to move the panels back and forth between multiple accordions.

    And help or advice on this?

  7. #7
    Sencha Premium Member
    Join Date
    Jul 2007
    Posts
    96
    Vote Rating
    1
    Nam is on a distinguished road

      0  

    Question


    Jozef, can you help me out on this please?

  8. #8
    Sencha - Community Support Team jsakalos's Avatar
    Join Date
    Apr 2007
    Location
    Slovakia
    Posts
    27,527
    Vote Rating
    378
    jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future jsakalos has a brilliant future

      0  

    Default


    This is now built-in and should work out of the box. See http://aariadne.com/accordion-preview tab Linked.
    Jozef Sakalos, aka Saki

    Education, extensions and services for developers at new http://extjs.eu
    News: Grid Search Plugin, ExtJS 5 Complex Data Binding using MVVM


  9. #9
    Sencha Premium Member
    Join Date
    Jul 2007
    Posts
    96
    Vote Rating
    1
    Nam is on a distinguished road

      0  

    Default


    Quote Originally Posted by jsakalos View Post
    This is now built-in and should work out of the box. See http://aariadne.com/accordion-preview tab Linked.
    OHHH YEAA!! That absolutely rocks man!! Who's the man... you are. Thanks a lot, This is going to come in very handy.

  10. #10
    Sencha User
    Join Date
    Apr 2012
    Posts
    74
    Vote Rating
    2
    url is on a distinguished road

      0  

    Default


    Hi jsakalos,

    I'm unable to get the total code from the link. I'm also searching for an example on the custom drag and drop in Extjs 4.1. Can you please provide me the total code for the running example so that i can have a better clarity of the concept.






    Regards
    url

Thread Participants: 3