2
votes

Dojo Dijit Buttons hide the "real" button offscreen using CSS:

.dijitOffScreen { 
    position: absolute !important;
    left: -10000px !important;
    top: -10000px !important;
}    
  • Why does this cause HTML5 drag and drop to not function correctly in Chrome and FireFox?
  • What are alternative methods to hide the input element and maintain the same Dojo Dijit Button behavior? (Adding display:none to the offscreen input element seems to work, but does that functionally alter the behavior of the input and thus widget?)

Original question:

Sometimes the default 'ghost' HTML5 drag image is smaller in size or not rendered at all. It varies by browser and there seems to be an interaction with Dojo Dijits involved.

After adding a Dijit Button to a draggable Dijit ContentPane, what causes the drag icon to be tiny in FireFox and not rendered at all in Chrome?

Simple jsFiddle repro:

var cp1 = new ContentPane({
    style: "width: 400px; height: 124px; background:red",
    content: "cp1: 'ghost 'drag icon is tiny or not visible :(<br />",
});

// Make draggable
domProp.set(cp1.domNode, 'draggable', 'true');
cp1.on('dragstart', onDragStartHandler); // otherwise FF doesn't show drag icon

// PROBLEM -> adding button messes up drag icon
button = new Button({label: 'Dijit Button'});
button.placeAt(cp1.containerNode);

update:

  • In addition to rendering the drag icon incorrectly, other HTML5 drag and drop events no longer function correctly. On Chrome, the entire document just disappears after dragover and/or end events are added. On FireFox, the processing of drag events is significantly slower.
  • Adding generic HTML button inputs instead of Dijit buttons does not result in any of these side effects: definitely Dojo Dijit interfering somehow...

update 2:

  • Root cause: Dijit Button hides an HTML button input element via the dijitOffScreen class. Removing left: 10000px !important and top: 10000px !important styles from the element restores drag and drop at the expense of showing a blank button. credit: Kenneth G. Franqueiro
2

2 Answers

2
votes

According to the spec, you can use "setDragImage" to specify an image element to use on drag, like this:

      // First, create draggable ContentPane with weird drag icon
      var cp1 = new ContentPane({
        style: "width: 400px; height: 124px; background:red",
        content: "cp1: 'ghost 'drag icon is full-sized and visible :)<br />",
      });
      var img = document.getElementById("drag-image");
      onDragStartHandler1 = function (ev) {
        console.log(ev);
        console.log('DragStart:', ev.target.id);
        ev.dataTransfer.setData("Text", ev.target.id);
        // Define "ghost" image here, with proper offset
        ev.dataTransfer.setDragImage(img, ev.x, ev.y);
      }
      // PROBLEM -> adding button messes up drag icon
      button = new Button({
        label: 'Dijit Button'
      });
      button.placeAt(cp1.containerNode);

      // Make draggable
      domProp.set(cp1.domNode, 'draggable', 'true');
      cp1.on('dragstart', onDragStartHandler1); // otherwise FF doesn't show drag icon

      // Add to document
      cp1.placeAt(document.body);
      cp1.startup();

Here's your fiddle, fixed.

Edit:

I guess I shouldn't really say 'fixed', more like work-arounded... It is odd that it doesn't display the element during drag by default, but, as you said, maybe it's a weird dojo-related thing. Regardless, it seems that "setDragImage" is probably there to unambiguously define the user feedback in such cases...

1
votes

I never found the exact reason those CSS styles mess up HTML5 drag and drop (my guess is the browsers were trying to construct a very large drag and drop image that included the 'offscreen' elements).

However, I have found two work-arounds (the CSS styles were attached to automatically created sub-nodes of the element I wanted to drag and drop):

  • Remove the dom nodes with offending CSS styles
  • Add display:none styles to the dom nodes with offending CSS styles

Both work-arounds restore expected HTML5 drag and drop behavior; I have not noticed any unwanted side effects, yet.


update:
.dijitOffScreen { 
    top: 0;
    left: 0;
    z-index: -9999;
}