2

I'm creating a website that utilizes the HTML5 Drag and Drop API.

However, to increase the user experience, I'd like to prevent ghost images when a user drags non-draggable elements. Is this even possible?

Further, almost every element seems   " draggable "   by default. One can click and then quickly drag pretty much any element in a browser, which creates a ghost image along with a no-drop cursor. Is there any way to prevent this behaviour?

  • draggable="false" doesn't work.
  • user-select: none doesn't work.
  • pointer-events: none doesn't work.
  • event.preventDefault() on mousedown doesn't work.
  • event.preventDefault() on dragstart doesn't work either.

I'm out of ideas and so far it's proven incredibly difficult to find information about this online. I have found the following thread, but, again, draggable="false" doesn't seem to work in my case.

Below is a screenshot that demonstrates it doesn't work; of course you can't see my cursor in the screenshot, but you can see how I've dragged the numbers to the left despite that.

enter image description here

I believe the issue might have something to do with its parent having dragover and drop events associated with it. I'm still dumbfounded nonetheless.

HTML

...
<body>
  ...
  <div id="backgammon-board-container">
    <div class="column" id="left-column">
      <div class="quadrant" id="third-quadrant">
        <div class="point odd top-point" id="point-13-12"><text>13</text>
          <div class="checker player-one-checker" id="checker-03" draggable="true"></div>
        </div>
      </div>
    </div>
    ...
  </div>
</body>
</html>

CSS

#backgammon-board-container {
  height: 100vh;
  width: 60vw;
  position: absolute;
  right: 0;
  display: flex;
}

  .column {
    height: 100%;
    display: flex;
    flex-direction: column; /* column-reverse for player two perspective */
  }

  #left-column {
    flex: 6;
  }

    .quadrant {
      flex: 1;
      display: flex;
    }

      .point {
        flex: 1;
        padding: 10px 0;
        display: flex;
        flex-direction: column;
        align-items: center;
      }

        .checker {
          z-index: 1;
          width: 48px;
          height: 48px;
          border-radius: 50%;
        }

text {
  position: fixed;
  font-family: impact;
  font-size: 24px;
  color: white;
  display: flex;
  justify-content: center;
  align-items: center;

  user-select: none;
  pointer-events: none;
}

JS

const p1checkers = document.getElementsByClassName('player-one-checker');
const p2checkers = document.getElementsByClassName('player-two-checker');
const pointClass = document.getElementsByClassName('point');

function setTurn(player) {
  if (player === 'p1') {
    allowCheckerMovement = p1checkers;
    disallowCheckerMovement = p2checkers;
  } else {
    allowCheckerMovement = p2checkers;
    disallowCheckerMovement = p1checkers;
  }

  // enable checker control for player
  for (var i = 0; i < allowCheckerMovement.length; i++) {
    allowCheckerMovement[i].style.cursor = 'pointer';
    allowCheckerMovement[i].setAttribute('draggable', true);
    allowCheckerMovement[i].addEventListener('dragstart', start); // for drag-and-drop.js
    allowCheckerMovement[i].addEventListener('dragend', stop);    // for drag-and-drop.js
  }

  // disable checker control for player
  for (var i = 0; i < disallowCheckerMovement.length; i++) {
    disallowCheckerMovement[i].style.cursor = 'default';
    disallowCheckerMovement[i].setAttribute('draggable', false);
    disallowCheckerMovement[i].removeEventListener('dragstart', start); // for drag-and-drop.js
    disallowCheckerMovement[i].removeEventListener('dragend', stop);    // for drag-and-drop.js
  }

  // allow drag and drop
  for (var i = 0; i < pointClass.length; i++) {
    pointClass[i].addEventListener('dragover', allowDrop); // for drag-and-drop.js
    pointClass[i].addEventListener('drop', droppedOn);     // for drag-and-drop.js
  }
}

function start(event) {
  var checker = event.target;
  event.dataTransfer.setData('text/plain', checker.id);
  event.dataTransfer.effectAllowed = 'move';
  window.requestAnimationFrame(function(){
    checker.style.visibility = 'hidden';
  });
}

function allowDrop(event) {
  event.preventDefault();
}

function droppedOn(event) {
  event.preventDefault();
  var data = event.dataTransfer.getData('text/plain');
    event.target.appendChild(document.getElementById(data));
}

function stop(event){
  var element = event.srcElement;
  window.requestAnimationFrame(function(){
    element.style.visibility = 'visible';
  });
}
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
oldboy
  • 5,729
  • 6
  • 38
  • 86
  • To clarify, you mean dragging _selected_ text? Only images and links can be dragged by default to my knowledge. There are various ways to make text unselectable if that wouldn't be an issue for you. –  May 24 '17 at 05:26
  • @fay hm... i meant anything, but now that you mention it, i've noticed that although you can "drag" anything only the ghost image of the text will show up. for other elements it's simply a `no-drag` cursor. strange. – oldboy May 24 '17 at 05:32
  • 1
    I just played around with a quick demo, `draggable="false"` makes elements draggable (the presence of `draggable` is what matters, not the value). Removing `draggable` makes elements undraggable, even if they have events associated with them. –  May 24 '17 at 05:32
  • @fay interesting. however, it happens even when i don't use that HTML attribute. only its siblings have `draggable="true"` and only its parent and siblings have drag events associated with them. `dragover` and `drop` for the parent, whereas `dragstart` and `dragend` for its siblings – oldboy May 24 '17 at 05:34
  • If you added the code to your question I might be able to find the exact cause, it sounds circumstantial and I'm in the dark about the circumstances. –  May 24 '17 at 05:38
  • @fay i'll add the code right now. give me a sec. thanks btw – oldboy May 24 '17 at 05:40
  • @fay k i added the code. i tried to include only the possibly relevant stuff and tried to shorten it up quite a bit – oldboy May 24 '17 at 05:53
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/144986/discussion-between-fay-and-anthony). –  May 24 '17 at 05:56

1 Answers1

0

This is the solution you're looking for. ;)

For anything that DOES need to be draggable, just add the 'enable-drag' CSS class.

$('*:not(".enable-drag")').on('dragstart', function (e) {
    e.preventDefault();
    return false;
});
Flyingkiwi
  • 3,066
  • 3
  • 15
  • 17