├── LICENSE
├── README.md
├── demo
├── demo-with-setdragimage-ie-datasrc.html
├── demo-with-setdragimage-ie.html
├── demo-without-setdragimage-ie.html
└── drag.png
├── setdragimage-ie.js
└── setdragimage-ie.min.js
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Mihai Valentin
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #setDragImage support for Internet Explorer 10+ Drag & Drop
2 |
3 | If you plan to use HTML5 Drag & Drop in your app, you will find out the hard way that Internet Explorer does not support the `setDragImage` method, which on Firefox / Chrome shows an arbitrary image next to the cursor while dragging.
4 |
5 | This polyfill provides the same functionality for Internet Explorer. It is less than 800 bytes compressed and gziped.
6 |
7 | ##Why should you use it?
8 |
9 | Generally the missing support for a drag image does not cause issues. However, there are cases when you want to give real feedback to the user related to what they are actually dragging. Let's say that if they drag one item, you should show an icon of a file, and when they drag multiple items you should show an icon of multiple files (and eventually a number). As Internet Explorer just shows as the drag element the element that is currently being dragged, the visual feedback can be confusing.
10 |
11 | ##Demo
12 |
13 | Check the demos in the `demo` folder
14 |
15 | ##How to use it?
16 |
17 | * include `setdragimage-ie.js` in your project
18 | * outside the `dragstart` event, (preferably when your application loads), call `setDragImageIEPreload(img)` to preload the image which you will later use.
19 | * Preloading ensures the image will be ready to be used when the first drag will happen
20 | * `img` is a HTML image (either an image element or a Image object)
21 | * inside the `dragstart` event, just use `ev.dataTransfer.setDragImage(img, x, y)` as you'd do it for Chrome / Firefox
22 | * start dragging and you'll also get the drag image on Internet Explorer as well
23 |
24 | ##How does this actually work?
25 |
26 | I noticed that if you make a change to the element's style (adding a class that changes appearance) inside the `dragstart` event and then removing it immediately in a `setTimeout`, Internet Explorer will make a bitmap copy of the modified element and will use it for dragging.
27 | So, what this library actually does is implement the `setDragImage` method that changes the target's element style by adding a class that includes the image that you want to appear while dragging, and then removes it. In this way, the browser displays the temporary style of the element as the drag image.
28 |
29 | ##Limitations
30 |
31 | Due to the technical details described above, this polyfill has the following limitations / issues:
32 |
33 | * there will be a very slight flicker when the drag will start
34 | * you cannot specify the mouse offsets (the second and third parameter for `setDragImage`
35 | * the reason is that when IE makes the bitmap copy, he does not understand transparency and uses white. Any attempt to position the background image will result in a lot of white near the image, creating a very ugly effect
36 | * the code is not in strict mode
37 | * the reason is that `setDragImage` is ran on the `DataTransfer` property of the event, so inside it the `this` is not the element or the event. To overcome this, I've used `caller` so I walk through the functions that called `setDragImage` and when I meet one that has the first parameter of type `DragEvent` (the `dragstart` event), I get it and then get it's target. Another idea would have been to add the fourth parameter so you can send the element directly, but it is not feasible, since new methods may be added on `setDragImage` in the future and it is not forward-compatible.
38 |
--------------------------------------------------------------------------------
/demo/demo-with-setdragimage-ie-datasrc.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
15 |
16 |
17 |
18 |
19 | Drag me
20 |
21 |
22 |
39 |
40 |
--------------------------------------------------------------------------------
/demo/demo-with-setdragimage-ie.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
15 |
16 |
17 |
18 |
19 | Drag me
20 |
21 |
22 |
35 |
36 |
--------------------------------------------------------------------------------
/demo/demo-without-setdragimage-ie.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
15 |
16 |
17 | This demo shows how Internet Explorer behaves without the setDragImage-IE polyfill. To view the polyfill in action, please check the other two demos
18 |
19 |
20 | Drag me
21 |
22 |
23 |
33 |
34 |
--------------------------------------------------------------------------------
/demo/drag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MihaiValentin/setDragImage-IE/819dfa74ac5ad6687a22c38421587cadab0b757a/demo/drag.png
--------------------------------------------------------------------------------
/setdragimage-ie.js:
--------------------------------------------------------------------------------
1 | /*global DataTransfer, DragEvent */
2 |
3 | /*! setDragImage-IE - polyfill for setDragImage method for Internet Explorer 10+
4 | https://github.com/MihaiValentin/setDragImage-IE */
5 |
6 | /**
7 | * this method preloads the image, so it will be already loaded when we will use it as a drag image
8 | * @param image
9 | */
10 | window.setDragImageIEPreload = function(image) {
11 | var bodyEl,
12 | preloadEl;
13 |
14 | bodyEl = document.body;
15 |
16 | // create the element that preloads the image
17 | preloadEl = document.createElement('div');
18 | preloadEl.style.background = 'url("' + image.src + '")';
19 | preloadEl.style.position = 'absolute';
20 | preloadEl.style.opacity = 0.001;
21 |
22 | bodyEl.appendChild(preloadEl);
23 |
24 | // after it has been preloaded, just remove the element so it won't stay forever in the DOM
25 | setTimeout(function() {
26 | bodyEl.removeChild(preloadEl);
27 | }, 5000);
28 | };
29 |
30 | // if the setDragImage is not available, implement it
31 | if ('function' !== typeof DataTransfer.prototype.setDragImage) {
32 | DataTransfer.prototype.setDragImage = function(image, offsetX, offsetY) {
33 | var randomDraggingClassName,
34 | dragStylesCSS,
35 | dragStylesEl,
36 | headEl,
37 | parentFn,
38 | eventTarget;
39 |
40 | // generate a random class name that will be added to the element
41 | randomDraggingClassName = 'setdragimage-ie-dragging-' + Math.round(Math.random() * Math.pow(10, 5)) + '-' + Date.now();
42 |
43 | // prepare the rules for the random class
44 | dragStylesCSS = [
45 | '.' + randomDraggingClassName,
46 | '{',
47 | 'background: url("' + image.src + '") no-repeat #fff 0 0 !important;',
48 | 'width: ' + image.width + 'px !important;',
49 | 'height: ' + image.height + 'px !important;',
50 | 'text-indent: -9999px !important;',
51 | 'border: 0 !important;',
52 | 'outline: 0 !important;',
53 | '}',
54 | '.' + randomDraggingClassName + ' * {',
55 | 'display: none !important;',
56 | '}'
57 | ];
58 | // create the element and add it to the head of the page
59 | dragStylesEl = document.createElement('style');
60 | dragStylesEl.innerText = dragStylesCSS.join('');
61 | headEl = document.getElementsByTagName('head')[0];
62 | headEl.appendChild(dragStylesEl);
63 |
64 | /*
65 | since we can't get the target element over which the drag start event occurred
66 | (because the `this` represents the DataTransfer object and not the element),
67 | we will walk through the parents of the current functions until we find one
68 | whose first argument is a drag event
69 | */
70 | parentFn = DataTransfer.prototype.setDragImage.caller;
71 | while (!(parentFn.arguments[0] instanceof DragEvent)) {
72 | parentFn = parentFn.caller;
73 | }
74 |
75 | // then, we get the target element from the event (event.target)
76 | eventTarget = parentFn.arguments[0].target;
77 | // and add the class we prepared to it
78 | eventTarget.classList.add(randomDraggingClassName);
79 |
80 | /* immediately after adding the class, we remove it. in this way the browser will
81 | have time to make a snapshot and use it just so it looks like the drag element */
82 | setTimeout(function() {
83 | // remove the styles
84 | headEl.removeChild(dragStylesEl);
85 | // remove the class
86 | eventTarget.classList.remove(randomDraggingClassName);
87 | }, 0);
88 | };
89 | }
--------------------------------------------------------------------------------
/setdragimage-ie.min.js:
--------------------------------------------------------------------------------
1 | /*! setDragImage-IE - polyfill for setDragImage method for Internet Explorer 10+
2 | https://github.com/MihaiValentin/setDragImage-IE */
3 | ;window.setDragImageIEPreload=function(image){var bodyEl,preloadEl;bodyEl=document.body;preloadEl=document.createElement("div");preloadEl.style.background='url("'+image.src+'")';preloadEl.style.position="absolute";preloadEl.style.opacity=0.001;bodyEl.appendChild(preloadEl);setTimeout(function(){bodyEl.removeChild(preloadEl);},5000);};if("function"!==typeof DataTransfer.prototype.setDragImage){DataTransfer.prototype.setDragImage=function(image,offsetX,offsetY){var randomDraggingClassName,dragStylesCSS,dragStylesEl,headEl,parentFn,eventTarget;randomDraggingClassName="setdragimage-ie-dragging-"+Math.round(Math.random()*Math.pow(10,5))+"-"+Date.now();dragStylesCSS=["."+randomDraggingClassName,"{",'background: url("'+image.src+'") no-repeat #fff 0 0 !important;',"width: "+image.width+"px !important;","height: "+image.height+"px !important;","text-indent: -9999px !important;","border: 0 !important;","outline: 0 !important;","}","."+randomDraggingClassName+" * {","display: none !important;","}"];dragStylesEl=document.createElement("style");dragStylesEl.innerText=dragStylesCSS.join("");headEl=document.getElementsByTagName("head")[0];headEl.appendChild(dragStylesEl);parentFn=DataTransfer.prototype.setDragImage.caller;while(!(parentFn.arguments[0] instanceof DragEvent)){parentFn=parentFn.caller;}eventTarget=parentFn.arguments[0].target;eventTarget.classList.add(randomDraggingClassName);setTimeout(function(){headEl.removeChild(dragStylesEl);eventTarget.classList.remove(randomDraggingClassName);},0);};}
--------------------------------------------------------------------------------