-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
fix Safari bug with dropping element inside grid #1738
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
thanks for taking a stab. I'll have to take a look this weekend. I thought |
Yep,
to
causes a bug where the grid it belongs to loses all drag and drop capabilities. I think in v3, there was logic that performed a similar check but the prop was named differently which gets set in the dropover event
|
please change if (this.el.contains(event.relatedTarget as HTMLElement)) return; to // Note: Safari Mac has null relatedTarget which causes #1684 but handled elsewhere
if (event.relatedTarget && this.el.contains(event.relatedTarget as HTMLElement)) return; assuming there isn't another field we could use there instead ???? and in V3 we had // fix #1578 when dragging fast, we might get leave after other grid gets enter (which calls us to clean)
// so skip this one if we're not the active grid really..
if (!node.grid || node.grid === this) {
this._leave(node, el, helper, true); // MATCH line 166
} in V3: .on(this.el, 'dropover', (event, el: GridItemHTMLElement) => {
// ignore drop enter on ourself, and prevent parent from receiving event
let node = el.gridstackNode;
if (node && node.grid === this) {
delete node._added; // reset this to track placeholder again in case we were over other grid #1484 (dropout doesn't always clear)
return false;
}
// load any element attributes if we don't have a node
if (!node) {
node = this._readAttr(el);
}
// if the item came from another grid, let it know it was added here to removed duplicate shadow #393
if (node.grid && node.grid !== this) {
node._added = true;
}
// if not calculate the grid size based on element outer size
let w = node.w || Math.round(el.offsetWidth / this.cellWidth()) || 1;
let h = node.h || Math.round(el.offsetHeight / this.getCellHeight(true)) || 1;
// copy the node original values (min/max/id/etc...) but override width/height/other flags which are this grid specific
let newNode = this.engine.prepareNode({...node, ...{w, h, _added: false, _temporary: true}});
newNode._isOutOfGrid = true;
el.gridstackNode = newNode;
el._gridstackNodeOrig = node;
GridStackDD.get().on(el, 'drag', onDrag);
return false; // prevent parent from receiving msg (which may be grid as well)
})
.on(this.el, 'dropout', (event, el: GridItemHTMLElement) => {
let node = el.gridstackNode;
if (!node) return;
// clear any added flag now that we are leaving #1484
delete node._added;
// jquery-ui bug. Must verify widget is being dropped out
// check node variable that gets set when widget is out of grid
if (!node._isOutOfGrid) {
return;
} and note that the comment said jquery-ui bug (which was the only plugging originally) yet your bug only happens in H5 or JQ as well? |
That change will not work - the reason why the dropout event is being called is because it's failing the conditional, it should be true and returning early but it's not. Since
|
The bug only happens in H5, JQ seems to be fine. It seems to be just an issue with the HTML5 dragleave event |
I didn't mean my suggestion was the fix, more a documenting the Safari bug where it matters. worth checking if Safari sends any params we could use instead to fix at the right place. as I mentioned Safari HTML5 draggable is rather buggy vs other browsers I tried and why (and mobile) I may need to do a mouse pointer + touch event rather in a future release |
Ah got it, will do - I'll document the bug in the handler
I think the only other params we could utilize is checking if the DragEvent occurred inside the Grid by comparing the DOMRect position. I've updated the PR to use that logic instead. I realized that my earlier fix did not work as intended, it actually introduced another bug so definitely not the correct solution. And agreed, I think a native mouse and touch event would provide better cross-browser compatibility. I didn't realize how buggy HTML5 draggable was even after being released for so long |
yes, thanks. I like that fix much better :) |
// Note: Safari Mac has null relatedTarget which causes #1684 so check if DragEvent is inside the grid instead | ||
if (!event.relatedTarget) { | ||
const { bottom, left, right, top } = this.el.getBoundingClientRect(); | ||
if (event.x < right && event.x > left && event.y < bottom && event.y > top) return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be <=
if (!event.relatedTarget) { | ||
const { bottom, left, right, top } = this.el.getBoundingClientRect(); | ||
if (event.x < right && event.x > left && event.y < bottom && event.y > top) return; | ||
} | ||
if (this.el.contains(event.relatedTarget as HTMLElement)) return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
else if (this.el.contains(event.relatedTarget as HTMLElement)) return;
no reason to check with null value.
Description
This should fix #1684
In Safari, relatedTarget is null, causing the
dragleave
event to fire thedropout
event early. To detect if we've actually dropped out, I've added a check to make sure the node has the_temporaryRemoved
prop set. There was similar logic in place in thedropout
event in v3 so this might have been the fix for that.I've also tested that this is still working in Chrome and Edge, but was having issues trying to run the local build on Firefox
Current behavior

With fix

Checklist
yarn test
)