4

With this code, I get only the URL. So I have to call this URL to restore the image.

Is it possible to get the image data itself directly without calling this URL again?

That's to avoid CORS depending on some server.

var dropbox = document.getElementById('dropbox');
dropbox.addEventListener('dragenter', noopHandler, false);
dropbox.addEventListener('dragexit', noopHandler, false);
dropbox.addEventListener('dragover', noopHandler, false);
dropbox.addEventListener('drop', drop, false);

function noopHandler(evt) {
  evt.stopPropagation();
  evt.preventDefault();
}

function drop(evt) {
  evt.stopPropagation();
  evt.preventDefault();
  var imageUrl = evt.dataTransfer.getData('URL');
  console.log(imageUrl)
  alert(imageUrl);
}
#dropbox {
  border: solid 1px red;
  width: 200px;
  height: 200px;
}
<div>Drag this image to the drop zone:</div>

<img src="http://www.google.com/logos/2012/Julia_Child-2012-hp.jpg" alt="" />

<div id="dropbox">
  DropZone => you could drop any image from any page here
</div>
TSR
  • 17,242
  • 27
  • 93
  • 197
  • Please expand on what you mean by *"from another tab"* and what environment you are running this code in.... directly in a page window or browser extension perhaps? Too many unknowns here – charlietfl Mar 07 '21 at 21:45
  • What you are asking for is not possible. the other tab needs to hand you a base64 string or a file by modifying the datatransfer and [add items](http://man.hubwiz.com/docset/JavaScript.docset/Contents/Resources/Documents/developer.mozilla.org/en-US/docs/Web/API/DataTransferItemList/add.html) to the drag start event. You might have better luck with looking into copy/paste instead – Endless Mar 07 '21 at 22:58
  • Yeah, you cannot get anything but the URL unless if it is a local file. Just make your own cors server or use `await (await fetch('https://corsanywhere.herokuapp.com/http://www.google.com/logos/2012/Julia_Child-2012-hp.jpg')).blob()` to get the images data. If you are trying to bypass cors, DataTransfer is not going to be what solves your problem. I get that you may not want to use someone else's server. That is completely fine. In fact, I don't. Go to [Repl.it](https://www.repl.it) and create a Node.JS repl that provides a cross origin proxy. I use the `Request` library as well as Express :-) – quicVO Mar 14 '21 at 00:46
  • I just realized how to do it. Create a canvas and image element. Wait for the image element to load, then write it to the canvas. Export the canvas as a data URI. – quicVO Mar 14 '21 at 01:01

2 Answers2

0

That's to avoid CORS

It sounds rather like you are trying to avoid Same-Origin-Policy (SOP).
CORS is a way to relax SOP, so it doesn't block some domains to access resources on your server.
SOP is a protection, if you find a way to avoid it that's a security issue, and you should probably report this to browser vendors since they can be generous with such bug reports.

So to answer your question, No, you can't.

As you have already thought, having the image's data passed into the DataTransfer would mean that a cross-origin script would be able to read the content of a cross-domain resource, and we don't want this to happen.

What you can do, as you already found too, is to fetch again that resource using the URL that has been passed into the DataTransfer, but if the server there doesn't allow you to read that content, you still won't be able to do so.

Ps: If the image on the other page was served through CORS, or simply same-origin, and you had access to that page, you could then append the data as a File in the DataTransfer. But I guess if you were in that situation, you could also simply setup your server so that it allows your other ones to read the data there.

Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • Please provide link to official documentation that only URL can be obtained as I did. I already search the parameters of DataTransfer.getData by I found it says only DOMSTrings. What are DOMStrings? Can't the image Data be extracted through one of these DomStrings? – TSR Mar 13 '21 at 17:52
  • 1
    https://html.spec.whatwg.org/multipage/dnd.html#drag-and-drop-processing-model only text, html and url. A DOMString is simply a string. And a function parameter is what **you** pass to the function, completely unrelated to its return value.... – Kaiido Mar 14 '21 at 00:42
0

Please, run the snippet below. Before the "ev.target.appendChild(document.getElementById(data))" over this code, you must to follow this instructions:

How can I convert an image into Base64 string using JavaScript?

...It's possible inside<Canvas>

function DopHere(ev) {
    ev.preventDefault();
}
function image_drags(ev) {
    ev.dataTransfer.setData("text", ev.target.id);
}
function drop(ev,div_id) {
       ev.preventDefault();
     
       var hasImages =hasImage(div_id);
       var data = ev.dataTransfer.getData("text");
       if(hasImages==false){       
         var data = ev.dataTransfer.getData("text");
         ev.target.appendChild(document.getElementById(data));
       }else{
alert('div already have an image.');
}
   }
function hasImage(id) {
       var arrival_div=document.getElementById(id);
       var childElements = document.getElementById(id).childNodes;
       for (var i = 0; i < childElements.length; i++) {
         if (childElements[i].localName != null && childElements[i].localName.toLowerCase() == "img") {
           return true;
         }
       }  
       return false;
     }
#drop_container{border:1px solid #000; width:170px; height:100px; padding:5px; float:left; margin:20px;}
#dropback_container{border:1px solid #000; width:170px; height:100px; padding:5px;float:left; margin:20px;}

img{
max-width:170px;
height:auto;
}
<div id="drop_container" ondrop="drop(event,'drop_container')" ondragover="DopHere(event)"><img id="image_drag" src="http://www.google.com/logos/2012/Julia_Child-2012-hp.jpg" draggable="true"
ondragstart="image_drags(event)"></div>
<div id="dropback_container" ondrop="drop(event,'dropback_container')" ondragover="DopHere(event)"></div>

https://jsfiddle.net/b7p8k5cf/1/

Pedro Cardoso
  • 163
  • 2
  • 6