Last active
March 9, 2023 14:48
-
-
Save florentbr/60ef7cb8d9b1ae690cafc82aad52da73 to your computer and use it in GitHub Desktop.
Selenium - HTML5 drag and drop
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from selenium import webdriver | |
import time | |
# JavaScript: HTML5 Drag and drop script | |
# param1 (WebElement): Source element to drag | |
# param2 (WebElement): Optional - target element for the drop | |
# param3 (int): Optional - Drop offset x relative to the target if any or source element | |
# param4 (int): Optional - Drop offset y relative to the target if any or source element | |
# param4 (int): Optional - Delay in milliseconds (default = 1ms) for dragging and dropping | |
# param5 (string): Optional - Key pressed (alt or ctrl or shilf) | |
JS_DRAG_AND_DROP = "var t=arguments,e=t[0],n=t[1],i=t[2]||0,o=t[3]||0,r=t[4]||1,a=t[5]||'',s='alt'===a||'\ue00a'===a,l='ctrl'===a||'\ue009'===a,c='shift'===a||'\ue008'===a,u=e.ownerDocument,f=e.getBoundingClientRect(),g=n?n.getBoundingClientRect():f,p=f.left+f.width/2,d=f.top+f.height/2,h=g.left+(i||g.width/2),m=g.top+(o||g.height/2),v=u.elementFromPoint(p,d),y=u.elementFromPoint(h,m);if(!v||!y){var E=new Error('source or target element is not interactable');throw E.code=15,E}var _={constructor:DataTransfer,effectAllowed:null,dropEffect:null,types:[],files:Object.setPrototypeOf([],null),_items:Object.setPrototypeOf([],{add:function(t,e){this[this.length]={_data:''+t,kind:'string',type:e,getAsFile:function(){},getAsString:function(t){t(this._data)}},_.types.push(e)},remove:function(t){Array.prototype.splice.call(this,65535&t,1),_.types.splice(65535&t,1)},clear:function(t,e){this.length=0,_.types.length=0}}),setData:function(t,e){this.clearData(t),this._items.add(e,t)},getData:function(t){for(var e=this._items.length;e--&&this._items[e].type!==t;);return e>=0?this._items[e]._data:null},clearData:function(t){for(var e=this._items.length;e--&&this._items[e].type!==t;);this._items.remove(e)},setDragImage:function(t){}};function w(t,e,n,i){for(var o=0;o<e.length;++o){var r=u.createEvent('MouseEvent');r.initMouseEvent(e[o],!0,!0,u.defaultView,0,0,0,p,d,l,s,c,!1,0,null),t.dispatchEvent(r)}i&&setTimeout(i,n)}function D(t,e,n,i){var o=u.createEvent('DragEvent');o.initMouseEvent(e,!0,!0,u.defaultView,0,0,0,p,d,l,s,c,!1,0,null),Object.setPrototypeOf(o,null),o.dataTransfer=_,Object.setPrototypeOf(o,DragEvent.prototype),t.dispatchEvent(o),i&&setTimeout(i,n)}'items'in DataTransfer.prototype&&(_.items=_._items),w(v,['pointerdown','mousedown'],1,function(){for(var t=v;t&&!t.draggable;)t=t.parentElement;if(t&&t.contains(v)){var e=y.getBoundingClientRect();D(v,'dragstart',r,function(){var t=y.getBoundingClientRect();p=t.left+h-e.left,d=t.top+m-e.top,D(y,'dragenter',1,function(){D(y,'dragover',r,function(){D(u.elementFromPoint(p,d),'drop',1,function(){D(v,'dragend',1,function(){w(u.elementFromPoint(p,d),['mouseup','pointerup'])})})})})})}})" | |
def drag_and_drop(driver, source, target=None, offsetX=0, offsetY=0, delay=25, key=None) : | |
driver.execute_script(JS_DRAG_AND_DROP, source, target, offsetX, offsetY, delay, key) | |
time.sleep(delay * 2 / 1000) | |
driver = webdriver.Chrome() | |
driver.get("http://react-dnd.github.io/react-dnd/examples-dustbin-copy-or-move.html") | |
# drag and drop Glass | |
source = driver.find_element_by_xpath("//*[not(./*)][normalize-space()='Glass']") | |
target = driver.find_element_by_xpath("//*[text()[contains(.,'Works with any drop effect')]]") | |
drag_and_drop(driver, source, target) | |
# drag and drop Banana with alt key pressed | |
source = driver.find_element_by_xpath("//*[not(./*)][normalize-space()='Banana']") | |
target = driver.find_element_by_xpath("//*[text()[contains(.,'Works with copy drop effect')]]") | |
drag_and_drop(driver, source, target, key='alt') | |
# drag and drop Paper by offset | |
source = driver.find_element_by_xpath("//*[not(./*)][normalize-space()='Paper']") | |
drag_and_drop(driver, source, offsetX=250, offsetY=-100) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var args = arguments, | |
elemSrc = args[0], | |
elemDst = args[1], | |
offsetX = args[2] || 0, | |
offsetY = args[3] || 0, | |
delay = args[4] || 1, | |
key = args[5] || '', | |
alt = key === 'alt' || key === '\uE00A', | |
ctrl = key === 'ctrl' || key === '\uE009', | |
shift = key === 'shift' || key === '\uE008', | |
doc = elemSrc.ownerDocument, | |
box1 = elemSrc.getBoundingClientRect(), | |
box2 = elemDst ? elemDst.getBoundingClientRect() : box1, | |
x = box1.left + (box1.width / 2), | |
y = box1.top + (box1.height / 2), | |
x2 = box2.left + (offsetX ? offsetX : box2.width / 2), | |
y2 = box2.top + (offsetY ? offsetY : box2.height / 2), | |
source = doc.elementFromPoint(x, y), | |
target = doc.elementFromPoint(x2, y2); | |
if (!source || !target) { | |
var ex = new Error('source or target element is not interactable'); | |
ex.code = 15; | |
throw ex; | |
} | |
var dataTransfer = { | |
constructor : DataTransfer, | |
effectAllowed : null, | |
dropEffect : null, | |
types : [ ], | |
files : Object.setPrototypeOf([], null), | |
_items : Object.setPrototypeOf([], { | |
add : function add(data, type) { | |
this[this.length] = { | |
_data : '' + data, | |
kind : 'string', | |
type : type, | |
getAsFile : function () { }, | |
getAsString : function (callback) { callback(this._data) } | |
}; | |
dataTransfer.types.push(type); | |
}, | |
remove : function remove(i) { | |
Array.prototype.splice.call(this, i & 65535, 1); | |
dataTransfer.types.splice(i & 65535, 1); | |
}, | |
clear : function clear(data, type) { | |
this.length = 0; | |
dataTransfer.types.length = 0; | |
} | |
}), | |
setData : function setData(format, data) { | |
this.clearData(format); | |
this._items.add(data, format); | |
}, | |
getData : function getData(format) { | |
for (var i = this._items.length; i-- && this._items[i].type !== format;); | |
return i >= 0 ? this._items[i]._data : null; | |
}, | |
clearData : function clearData(format) { | |
for (var i = this._items.length; i-- && this._items[i].type !== format;); | |
this._items.remove(i); | |
}, | |
setDragImage : function setDragImage(format) { } | |
}; | |
if ('items' in DataTransfer.prototype) | |
dataTransfer.items = dataTransfer._items; | |
emit_mouse(source, [ 'pointerdown', 'mousedown' ], 1, function () { | |
var elem = source; | |
while (elem && !elem.draggable) | |
elem = elem.parentElement; | |
if (!elem || !elem.contains(source)) | |
return; | |
var box2 = target.getBoundingClientRect(); | |
emit_drag(source, 'dragstart', delay, function () { | |
var box3 = target.getBoundingClientRect(); | |
x = box3.left + x2 - box2.left; | |
y = box3.top + y2 - box2.top; | |
emit_drag(target, 'dragenter', 1, function () { | |
emit_drag(target, 'dragover', delay, function () { | |
emit_drag(doc.elementFromPoint(x, y), 'drop', 1, function () { | |
emit_drag(source, 'dragend', 1, function () { | |
emit_mouse(doc.elementFromPoint(x, y), [ 'mouseup', 'pointerup' ]); | |
})})})})})}); | |
function emit_mouse(element, types, delay, callback) { | |
for (var i=0; i < types.length; ++i) { | |
var event = doc.createEvent('MouseEvent'); | |
event.initMouseEvent(types[i], true, true, doc.defaultView, 0, 0, 0, x, y, ctrl, alt, shift, false, 0, null); | |
element.dispatchEvent(event); | |
} | |
callback && setTimeout(callback, delay); | |
} | |
function emit_drag(element, type, delay, callback) { | |
var event = doc.createEvent('DragEvent'); | |
event.initMouseEvent(type, true, true, doc.defaultView, 0, 0, 0, x, y, ctrl, alt, shift, false, 0, null); | |
Object.setPrototypeOf(event, null); | |
event.dataTransfer = dataTransfer; | |
Object.setPrototypeOf(event, DragEvent.prototype); | |
element.dispatchEvent(event); | |
callback && setTimeout(callback, delay); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var t=arguments,e=t[0],n=t[1],i=t[2]||0,o=t[3]||0,r=t[4]||1,a=t[5]||'',s='alt'===a||'\ue00a'===a,l='ctrl'===a||'\ue009'===a,c='shift'===a||'\ue008'===a,u=e.ownerDocument,f=e.getBoundingClientRect(),g=n?n.getBoundingClientRect():f,p=f.left+f.width/2,d=f.top+f.height/2,h=g.left+(i||g.width/2),m=g.top+(o||g.height/2),v=u.elementFromPoint(p,d),y=u.elementFromPoint(h,m);if(!v||!y){var E=new Error('source or target element is not interactable');throw E.code=15,E}var _={constructor:DataTransfer,effectAllowed:null,dropEffect:null,types:[],files:Object.setPrototypeOf([],null),_items:Object.setPrototypeOf([],{add:function(t,e){this[this.length]={_data:''+t,kind:'string',type:e,getAsFile:function(){},getAsString:function(t){t(this._data)}},_.types.push(e)},remove:function(t){Array.prototype.splice.call(this,65535&t,1),_.types.splice(65535&t,1)},clear:function(t,e){this.length=0,_.types.length=0}}),setData:function(t,e){this.clearData(t),this._items.add(e,t)},getData:function(t){for(var e=this._items.length;e--&&this._items[e].type!==t;);return e>=0?this._items[e]._data:null},clearData:function(t){for(var e=this._items.length;e--&&this._items[e].type!==t;);this._items.remove(e)},setDragImage:function(t){}};function w(t,e,n,i){for(var o=0;o<e.length;++o){var r=u.createEvent('MouseEvent');r.initMouseEvent(e[o],!0,!0,u.defaultView,0,0,0,p,d,l,s,c,!1,0,null),t.dispatchEvent(r)}i&&setTimeout(i,n)}function D(t,e,n,i){var o=u.createEvent('DragEvent');o.initMouseEvent(e,!0,!0,u.defaultView,0,0,0,p,d,l,s,c,!1,0,null),Object.setPrototypeOf(o,null),o.dataTransfer=_,Object.setPrototypeOf(o,DragEvent.prototype),t.dispatchEvent(o),i&&setTimeout(i,n)}'items'in DataTransfer.prototype&&(_.items=_._items),w(v,['pointerdown','mousedown'],1,function(){for(var t=v;t&&!t.draggable;)t=t.parentElement;if(t&&t.contains(v)){var e=y.getBoundingClientRect();D(v,'dragstart',r,function(){var t=y.getBoundingClientRect();p=t.left+h-e.left,d=t.top+m-e.top,D(y,'dragenter',1,function(){D(y,'dragover',r,function(){D(u.elementFromPoint(p,d),'drop',1,function(){D(v,'dragend',1,function(){w(u.elementFromPoint(p,d),['mouseup','pointerup'])})})})})})}}) | |
Hi I'm currently working on an application which is developed in HTML5, so automating the drag and drops functionality has been a nightmare. I found your work to be really helpful. When implemented the code in my local test framework, I'm facing this error "TypeError: Object of type WalkthroughClient is not JSON serializable"
I have not include the drag_drop.js in the project folder. Is it because of this ?? If not please give me steps to implement
Hope below implementation steps by me helps you...:) happy coding
Were anyone able to drag and drop in this site with above piece od code?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Implimentation of "drag-drop.min.js" in Protractor typescript framework:
const DND = "function h(a,b,c,d){var k=l.createEvent('DragEvent');k.initMouseEvent(b,!0,!0,l.defaultView,0,0,0,m,n,w,x,y,!1,0,null);Object.setPrototypeOf(k,null);k.dataTransfer=g;Object.setPrototypeOf(k,DragEvent.prototype);a.dispatchEvent(k);setTimeout(d,c)}var a=arguments,c=a[0],d=a[1],q=a[2]||0,r=a[3]||0,t=a[4]||1;a=a[5]||'';var x='alt'===a||'\ue00a'===a,w='ctrl'===a||'\ue009'===a,y='shift'===a||'\ue008'===a,l=c.ownerDocument;a=c.getBoundingClientRect();var e=d?d.getBoundingClientRect():a,m=a.left+a.width/2,n=a.top+a.height/2,u=e.left+(q?q:e.width/2),v=e.top+(r?r:e.height/2),p=l.elementFromPoint(m,n),f=l.elementFromPoint(u,v);for(d=p;d&&!d.draggable;)d=d.parentElement;if(!d||!c.contains(p))throw c=Error('source element is not interactable/draggable'),c.code=15,c;if(!f)throw c=Error('target element is not interactable'),c.code=15,c;var g={constructor:DataTransfer,effectAllowed:null,dropEffect:null,types:[],files:Object.setPrototypeOf([],null),_items:Object.setPrototypeOf([],{add:function(a,b){this[this.length]={_data:''+_data,kind:'string',type:b,getAsFile:function(){},getAsString:function(a){a(this._data)}};g.types.push(b)},remove:function(a){Array.prototype.splice.call(this,a&65535,1);g.types.splice(a&65535,1)},clear:function(a,b){this.length=0;g.types.length=0}}),setData:function(a,b){this.clearData(a);this._items.add(b,a)},getData:function(a){for(var b=this._items.length;b--&&this._items[b].type!==a;);return 0<=b?this._items[b]._data:null},clearData:function(a){for(var b=this._items.length;b--&&this._items[b].type!==a;);this._items.remove(b)},setDragImage:function(a){}};'items'in DataTransfer.prototype&&(g.items=g._items);e=f.getBoundingClientRect();h(p,'dragstart',t,function(){var a=f.getBoundingClientRect();m=a.left+u-e.left;n=a.top+v-e.top;h(f,'dragenter',1,function(){h(f,'dragover',t,function(){f=l.elementFromPoint(m,n);h(f,'drop',1,function(){h(p,'dragend',1,function(){})})})})})";
await browser.executeScript(DND , dragingElement, droppingElement);
Note: Need to do changes to make your code look good.