-
14 Mar 2012 8:18 AM #1
Ext JS 4 Custom Drag and Drop does not work as expected
Ext JS 4 Custom Drag and Drop does not work as expected
There is a strange behaviour with this code using ExtJS 4. After dragging the drag element inside the drop zone it is nearly impossible to drag the element back to its original position. It seems that there is a problem with the positioning. Maybe you have to test the code with 3.2 and 4.07 to see the behaviour. Same with the custom drag and drop example at http://www.sencha.com/blog/5-steps-t...p-with-ext-js/ It will work with ExtJS 3 but strange behaviour with 4.07
I think it could be a bug inside Ext.dd.DD. Maybe alignElWithMouse() has a bug.
Themes to be the same like: http://www.sencha.com/forum/showthre...tem-up-or-left
Code:<html> <head> <title>ExtJS Custom Drag'n Drop Demo</title> <link rel="stylesheet" type="text/css" href="/extjs/resources/css/ext-all.css" /> <style type="text/css"> #dropper { width: 290px; padding-left: 5px; height: 150px; background-color: silver; } #burgerzone { width: 290px; padding-left: 5px; height: 150px; } #dragme, #dropme { border: 1px solid black; margin-bottom: 5px; margin-left: 5px; padding-left: 5px; padding-bottom: 5px; width: 300px; } </style> <script type="text/javascript" src="/extjs/ext-all-debug.js"> </script> <script type="text/javascript"> // overrides enthaelt die individuelle Drag and Drop Logik einer Anwendung var overrides = { onInvalidDrop: function(){ // onIvalidDrop wird ausgefuehrt, wenn der Burger an eine unzulaessigen Stelle außerhalb // der grauen Flaeche gezogen wurde // hier kann noch zusaetzlicher Code ausgefuehrt werden, z.B. eine extra Logik implementiert werden // im Normalfall setzt man hier nur invalidDrop auf true und wertet dies spaeter in endDrag aus this.invalidDrop = true; }, b4StartDrag: function(){ if (!this.el) { this.el = Ext.get(this.getEl()); } // falls der ganze Drag and Drop Vorgang unguelltig ist, merkt man sich in origPos die // Ausgangsposition des bewegten Elements und kann das Element spaeter wieder dort positionieren this.origPos = this.el.getXY(); }, endDrag: function(){ // Auswertung von invalidDrop // Ist der Drag and Drop des Burgers unguelltig? if (this.invalidDrop === true) { // Konfiguration fuer Repair-Animation var anim = { easing: 'elasticOut', duration: 1, scope: this, callback: function(){ // sobald die Animation beendet ist, wird der Burger wieder // an seiner Ausgangsposition angezeigt this.el.dom.style.position = ''; } }; // Repair-Animation // der Burger wird wieder an die Ausgangsposition verschoben this.el.moveTo(this.origPos[0], this.origPos[1], anim); delete this.invalidDrop; } }, onDragDrop: function(evtObject, targetElId){ // der Burger wird zu einem Ext.Element var dropEl = Ext.get(targetElId); // der Burger wird nur verschoben, wenn Ursprungs- // und Ziel-Element nicht identisch sind if (this.el.dom.parentNode.id != targetElId) { // der Burger wird zum Kind des Ziel-Elements dropEl.appendChild(this.el); // der Burger ist jetzt ein Kind von dropper // falsche styles sind zu loeschen this.el.dom.style.position = ''; debugger; } else { // this was an invalid drop, initiate a repair this.onInvalidDrop(); } } }; </script> <script type="text/javascript"> Ext.onReady(function(){ // aus dem HTML-Code des Burgers wird das Ext.Element burgerElement var burgerElement = Ext.get('burger'); // dd ist eine Instanz der Klasse Ext.dd.DD // beim instanziieren wird das burgerElement übergeben und // die DDGroup speisekartenDDGroup angegeben // dd ist kein target var dd = new Ext.dd.DD(burgerElement, 'speisekartenDDGroup', { isTarget: false }); // overrides wird in dd kopiert Ext.apply(dd, overrides); // der div Tag mit der id dropper wird als drop target definiert // und ebenfalls der DDGroup speisekartenDDGroup zugewiesen var dragzone = new Ext.dd.DDTarget('burgerzone', 'speisekartenDDGroup'); var dropper = new Ext.dd.DDTarget('dropper', 'speisekartenDDGroup'); }); </script> <body> <fieldset id="dragme"> <legend> Drag from here </legend> <div id="burgerzone"> <img id="burger" alt="burger" src="/assets/images/food/hamburger.jpg" width="100" height="100"> </div> </fieldset> <fieldset id="dropme"> <legend> Drop here </legend> <div id="dropper"> </div> </fieldset> </body> </html>
-
14 Mar 2012 10:25 AM #2
Do you want this thread to be moved to Bugs Forum?
Jozef Sakalos, aka Saki
A lot of valuable info at:
Saki's Extensions and Plugins
Saki's Extensions and Plugins Docs
Saki's Examples, Latest: Grid in Card Layout
Saki's Blog, Featured: Writing a Big Application in Ext, Latest: Grid MultiSearch Plugin Video
-
14 Mar 2012 1:23 PM #3
maybe solved: bug or feature
maybe solved: bug or feature
The method alignElWithMouse() uses absolute and relative positioning.
The problem is the relative positioning with fly.setLeftTop() and Math.max() with a value of 0. Math.max() with 0 never can be negative so it is not possible to move a drag item to the top(up) or to the left side. Simply removing Math.max() with 0 would do the trick.Code:alignElWithMouse: function(el, iPageX, iPageY) { var oCoord = this.getTargetCoord(iPageX, iPageY), fly = el.dom ? el : Ext.fly(el, '_dd'), elSize = fly.getSize(), EL = Ext.Element, vpSize; if (!this.deltaSetXY) { vpSize = this.cachedViewportSize = { width: EL.getDocumentWidth(), height: EL.getDocumentHeight() }; var aCoord = [ Math.max(0, Math.min(oCoord.x, vpSize.width - elSize.width)), Math.max(0, Math.min(oCoord.y, vpSize.height - elSize.height)) ]; // absolute positioning with fly.setXY() fly.setXY(aCoord); var newLeft = fly.getLeft(true); var newTop = fly.getTop(true); this.deltaSetXY = [newLeft - oCoord.x, newTop - oCoord.y]; } else { vpSize = this.cachedViewportSize; // relative positioning with fly.setLeftTop() fly.setLeftTop( // problem code Math.max(0, Math.min(oCoord.x + this.deltaSetXY[0], vpSize.width - elSize.width)), Math.max(0, Math.min(oCoord.y + this.deltaSetXY[1], vpSize.height - elSize.height)) ); } this.cachePosition(oCoord.x, oCoord.y); this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth); return oCoord; }
Code:<html> <head> <title>ExtJS Custom Drag'n Drop Demo</title> <link rel="stylesheet" type="text/css" href="/extjs/resources/css/ext-all.css" /> <style type="text/css"> #dropper { width: 290px; padding-left: 5px; height: 150px; background-color: silver; } #burgerzone { width: 290px; padding-left: 5px; height: 150px; } #burger { width: 100px; padding: 5px; height: 100px; background-color: red; } #dragme, #dropme { border: 1px solid black; margin-bottom: 5px; margin-left: 5px; padding-left: 5px; padding-bottom: 5px; width: 300px; } </style> <script type="text/javascript" src="/extjs/ext-all-debug-w-comments.js"> </script> <script type="text/javascript"> // overrides enthaelt die individuelle Drag and Drop Logik einer Anwendung var overrides = { onInvalidDrop: function(){ // onIvalidDrop wird ausgefuehrt, wenn der Burger an eine unzulaessigen Stelle außerhalb // der grauen Flaeche gezogen wurde // hier kann noch zusaetzlicher Code ausgefuehrt werden, z.B. eine extra Logik implementiert werden // im Normalfall setzt man hier nur invalidDrop auf true und wertet dies spaeter in endDrag aus this.invalidDrop = true; }, b4StartDrag: function(){ if (!this.el) { this.el = Ext.get(this.getEl()); } // falls der ganze Drag and Drop Vorgang unguelltig ist, merkt man sich in origPos die // Ausgangsposition des bewegten Elements und kann das Element spaeter wieder dort positionieren this.origPos = this.el.getXY(); }, endDrag: function(){ // Auswertung von invalidDrop // Ist der Drag and Drop des Burgers unguelltig? if (this.invalidDrop === true) { // Konfiguration fuer Repair-Animation var anim = { easing: 'elasticOut', duration: 1, scope: this, callback: function(){ // sobald die Animation beendet ist, wird der Burger wieder // an seiner Ausgangsposition angezeigt this.el.dom.style.position = ''; } }; // Repair-Animation // der Burger wird wieder an die Ausgangsposition verschoben this.el.moveTo(this.origPos[0], this.origPos[1], anim); delete this.invalidDrop; } }, onDragDrop: function(evtObject, targetElId){ // der Burger wird zu einem Ext.Element var dropEl = Ext.get(targetElId); // der Burger wird nur verschoben, wenn Ursprungs- // und Ziel-Element nicht identisch sind if (this.el.dom.parentNode.id != targetElId) { // der Burger wird zum Kind des Ziel-Elements dropEl.appendChild(this.el); // der Burger ist jetzt ein Kind von dropper // falsche styles sind zu loeschen this.el.dom.style.position = ''; } else { // this was an invalid drop, initiate a repair this.onInvalidDrop(); } }, alignElWithMouse: function(el, iPageX, iPageY) { var oCoord = this.getTargetCoord(iPageX, iPageY), fly = el.dom ? el : Ext.fly(el, '_dd'), elSize = fly.getSize(), EL = Ext.Element, vpSize; if (!this.deltaSetXY) { vpSize = this.cachedViewportSize = { width: EL.getDocumentWidth(), height: EL.getDocumentHeight() }; var aCoord = [ Math.max(0, Math.min(oCoord.x, vpSize.width - elSize.width)), Math.max(0, Math.min(oCoord.y, vpSize.height - elSize.height)) ]; fly.setXY(aCoord); var newLeft = fly.getLeft(true); var newTop = fly.getTop(true); this.deltaSetXY = [newLeft - oCoord.x, newTop - oCoord.y]; } else { vpSize = this.cachedViewportSize; fly.setLeftTop( Math.min(oCoord.x + this.deltaSetXY[0], vpSize.width - elSize.width), Math.min(oCoord.y + this.deltaSetXY[1], vpSize.height - elSize.height) ); } this.cachePosition(oCoord.x, oCoord.y); this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth); return oCoord; } }; </script> <script type="text/javascript"> Ext.onReady(function(){ // aus dem HTML-Code des Burgers wird das Ext.Element burgerElement var burgerElement = Ext.get('burger'); // dd ist eine Instanz der Klasse Ext.dd.DD // beim instanziieren wird das burgerElement übergeben und // die DDGroup speisekartenDDGroup angegeben // dd ist kein target var dd = new Ext.dd.DD(burgerElement, 'speisekartenDDGroup', { isTarget: false }); // overrides wird in dd kopiert Ext.apply(dd, overrides); // der div Tag mit der id dropper wird als drop target definiert // und ebenfalls der DDGroup speisekartenDDGroup zugewiesen var dragzone = new Ext.dd.DDTarget('burgerzone', 'speisekartenDDGroup'); var dropper = new Ext.dd.DDTarget('dropper', 'speisekartenDDGroup'); }); </script> <body> <div align="center"> <fieldset id="dragme"> <legend> Drag from here </legend> <div id="burgerzone"> <div id="burger">Burger</div> </div> </fieldset> <fieldset id="dropme"> <legend> Drop here </legend> <div id="dropper"> </div> </fieldset> </div> </body> </html>
-
14 Mar 2012 1:24 PM #4
Is that solved then? Or should I move it to Bugs?
Jozef Sakalos, aka Saki
A lot of valuable info at:
Saki's Extensions and Plugins
Saki's Extensions and Plugins Docs
Saki's Examples, Latest: Grid in Card Layout
Saki's Blog, Featured: Writing a Big Application in Ext, Latest: Grid MultiSearch Plugin Video
-
14 Mar 2012 1:38 PM #5
Move it to bugs because it only works with an override.
Thank you for reporting this bug. We will make it our priority to review this report.


Reply With Quote