2

I'm using Angular with the angular-drag-and-drop-lists directive. It uses HTML5 API to implement drag & drop. I've noticed that when dragging an element onto the browser address bar, the address is re-written with the element's data and the driver navigates away from my site. Is there a way to prevent an element from being dragged onto the address bar or limiting it's dragging area?

Gabriel Kohen
  • 4,166
  • 4
  • 31
  • 46

2 Answers2

1

This is OS/browser-specific and at a lower level than your code allows. So you will not be able to do anything about it from your code.

Tyler
  • 11,272
  • 9
  • 65
  • 105
  • 1
    If in HTML 5 I'd be able to limit the movement outside of the document boundaries it would solve the issue. Could not find out how to do that with the drag and drop handlers yet. – Gabriel Kohen Sep 21 '15 at 18:45
  • 1
    If you figure out a way to prevent this, I'll eat my hat :) – Tyler Sep 21 '15 at 20:41
  • I have to agree with @GabrielKohen here, although I originally thought, like you, that this would be impossible because that is an event outside the viewport (thus OS-side), with a hack preventing cursor exit it should be possible. – tatsu Apr 10 '18 at 13:25
  • @tyler hat-eating time ;) also pics or it didn't happen! – tatsu Apr 12 '18 at 08:18
  • @tatsu The answer given is OS/browser-specific and not standardized (still 2.5 years later). I read the question as wanting a solution that worked in general, which unfortunately there is not. – Tyler Apr 12 '18 at 16:37
  • @tyler fair point. you get to keep you hat on your head this time : – tatsu Apr 13 '18 at 08:05
1

If you control the dragstart event you can define the effectAllowed of the drag data store. This will define how your system deals with the element you're dragging. You have different choices that will behave differently based on where you drop them and on the content. This will affect as well how it affects the drop in your address bar.

Here's a few examples of the behaviors you can set. For example, on Chrome, when you set the effect at 'none', dragging the element to the address bar won't do anything, but with 'copy' it'll search the text with type 'text/plain'. An image with 'copy' effectAllowed will open in the browser.

Behaviors will vary elsewhere also. If you drag the element in the finder for example (on Mac OS), it will either create the image, or a text file with the content of 'text/plain'. In Microsoft Word, the image will be inserted in the page, or the 'text/html' will be inserted, with format.

Like this:

document.getElementById('noneImg').addEventListener('dragstart', setEffect)

document.getElementById('copyImg').addEventListener('dragstart', setEffect)

document.getElementById('linkImg').addEventListener('dragstart', setEffect)

document.getElementById('noneText').addEventListener('dragstart', setEffect)

document.getElementById('copyText').addEventListener('dragstart', setEffect)

document.getElementById('linkText').addEventListener('dragstart', setEffect)


function setEffect(e) {
  if(e.target.tagName === 'DIV'){
      e.dataTransfer.setData('text/plain', 'test');
      e.dataTransfer.setData('text/html', '<b>bold</b>');
  }
 e.dataTransfer.effectAllowed = e.target.className;
}
img {
  width: 80px;
  height: 80px;
}
<img id="noneImg" class="none" src="http://koncha.890m.com/wp-content/uploads/2016/06/2.jpg"  />

<img id="copyImg" class="copy" src="http://koncha.890m.com/wp-content/uploads/2016/06/2.jpg"  />

<img id="linkImg" class="link" src="http://koncha.890m.com/wp-content/uploads/2016/06/2.jpg"  />

<div draggable="true" id="noneText" class="none">effect none</div>

<div draggable="true" id="copyText" class="copy">effect copy</div>

<div draggable="true" id="linkText" class="link">effect link</div>

See https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/effectAllowed

If you don't control the dragstart event, then there's not much you can do. This means everything that is dragged from your OS or other windows.

EDIT:

To clarify a bit, the way the drop will behave is dependent on 3 things:

  • the content of the drag data store,
  • the effectAllowed
  • and the application on which the drop is made

You need to consider each browser as a different application, so behaviors will vary depending on the browser, and will probably vary with the OS, and with the version of the browser. For example, on the browsers I have available, on Chrome, effectAllowed none won't do anything. But on Firefox it will trigger a drop.

Also, the drag data store is a complex set of data where you can have multiple data types, and depending on the application different data types will be used. So for example, if you have a 'text' data type, it'll put the content of the text data type in the address bar (on Chrome this happens with 'copy' effectAllowed, but not with 'link'. With Firefox it will drop it whichever effectAllowed is defined).

One way to adjust the behavior would be to use clearData. This clears the drag data store. Once this is done, you can define your own types if wanted. For example, using custom types you can clear out all other behaviors and keep only the ones you need in your page.

So here for example, you can drop and depending on which drop, you have access different to data and there are no interactions with other applications.

document.getElementById('noneImg').addEventListener('dragstart', setEffect)

document.getElementById('copyImg').addEventListener('dragstart', setEffect)

document.getElementById('linkImg').addEventListener('dragstart', setEffect)

document.getElementById('noneText').addEventListener('dragstart', setEffect)

document.getElementById('copyText').addEventListener('dragstart', setEffect)

document.getElementById('linkText').addEventListener('dragstart', setEffect)

function setEffect(e) {
  e.dataTransfer.clearData();
  e.dataTransfer.setData('custom', 'custom data');
  e.dataTransfer.setData('custom2', 'other custom data');
  e.dataTransfer.effectAllowed = e.target.className;
}

document.getElementById('drop').addEventListener('dragover', (e) => {
  e.preventDefault();
  e.target.style.backgroundColor = 'blue';
});

document.getElementById('drop').addEventListener('dragleave', (e) => {
  e.preventDefault();
  e.target.style.backgroundColor = "";
});

document.getElementById('drop').addEventListener('drop', (e) => {
  console.log(e.dataTransfer.getData('custom'));
  e.target.style.backgroundColor = "";
  e.preventDefault();
});

document.getElementById('drop2').addEventListener('dragover', (e) => {
  e.preventDefault();
  e.target.style.backgroundColor = 'blue';
});

document.getElementById('drop2').addEventListener('dragleave', (e) => {
  e.preventDefault();
  e.target.style.backgroundColor = "";
})

document.getElementById('drop2').addEventListener('drop', (e) => {
  console.log(e.dataTransfer.getData('custom2'));
  e.target.style.backgroundColor = "";
  e.preventDefault();
});
img {
  width: 80px;
  height: 80px;
}

#drop,
#drop2,
#drop3 {
  width: 200px;
  height: 200px;
  border: solid 1px black;
  float: left;
}
<img id="noneImg" class="none" src="http://koncha.890m.com/wp-content/uploads/2016/06/2.jpg" />

<img id="copyImg" class="copy" src="http://koncha.890m.com/wp-content/uploads/2016/06/2.jpg" />

<img id="linkImg" class="link" src="http://koncha.890m.com/wp-content/uploads/2016/06/2.jpg" />

<div draggable="true" id="noneText" class="none">effect none</div>

<div draggable="true" id="copyText" class="copy">effect copy</div>

<div draggable="true" id="linkText" class="link">effect link</div>

<div id="drop">

</div>

<div id="drop2">

</div>
Julien Grégoire
  • 16,864
  • 4
  • 32
  • 57
  • well if you have 'none' as an effect you might as well have no drag and drop at all... or am I missing something? With this example : http://visjs.org/examples/timeline/other/drag&drop.html how would I preserve drag and drop functionality but prevent drop on address bar? (you can access the uncompiled code with inspector on that page) – tatsu Apr 11 '18 at 09:32
  • see my edit, in your example, instead of using event.dataTransfer.setData("text", JSON.stringify(objectItem)); use clearData and event.dataTransfer.setData("custom", JSON.stringify(objectItem)); making sure you change in bis.js as well to getData('custom') – Julien Grégoire Apr 11 '18 at 15:13
  • ok so this is indeed an issue of none of the browsers being quite up to speed. I opened this answer in three browsers, ie11, firefox50 and chrome65. firefox could not open stackoverflow in a non broken state at all but this is probably my company's firewall at work. but the test I coded myself confirmed that I could indeed get a drag and drop event fired correctly on my drop zone with 'none', that being said even though it didn't redirect, it did place the html content into the address bar. But it didn't redirect so that's better. but with my target being ie11 this is not helping. – tatsu Apr 12 '18 at 08:08
  • also I should mention that in IE the above snipet failed to run when I click the button. I'm awarding you the points because of your astoundingly complete answer. thanks alot this was illuminating. – tatsu Apr 12 '18 at 08:11
  • woops and I just realized that in IE `link` does the perfect job. Thank you! – tatsu Apr 12 '18 at 08:12
  • AND in Chrome!! wow! but in firefox it still drops html text into the address bar but it's better because it doesn't redirect. – tatsu Apr 12 '18 at 08:13