How to prevent dragleave interfering with dragenter event on nested dropzone element? - javascript

With two nested elements in dropzone and dragging from outer to inner element, dragleave actions take precedence over dragenter.
I have initially one div as dropzone, which on dragenter changes class ('canDrop') to indicate if drop is possible, while on dragleave the class reverts to neutral ('plainDropZone').
On drop the draggable div becomes a child of the dropzone div. Now, when another draggable enters the dropzone, class is changed to 'noDrop' to indicate no more drops are possible. On dragleave the class reverts to neutral again ('plainDropZone')
The Problem: When dragging from outer dropzone div to the inner dropped div, the outer dropzone div should not revert to neutral, but still have the class 'noDrop'.
As far as I have found out this does not work as intended, because when moving from outer to inner div, dragleave gets fired after dragenter. This thread visualizes the problem nicely: HTML 5 drag events: 'dragleave' fired after 'dragenter'
Here is a full demo: https://jsfiddle.net/e12uadgh/
So what would be a way to assign the outer dropzone div the class 'noDrop', when it has a dropped inner div and the user drags a third div from outer dropzone div to inner dropped div?

Found a way to achieve the effect. When dragging an element from outer dropzone div to inner dropzone div, dragleave for outer div is fired after dragenter for inner div, so that any changes on dragenter get overridden by the changes made on dragleave.
So one solution is to make only changes on dragleave, if the next event target is not the inner div. Since this can not be done by examining event.target on dragleave, we can use a toggle instead, which is set to true on dragenter on inner div, and which becomes false on dragleave on inner div.
Here is a demo: https://jsfiddle.net/rookie_sen/2Lp5qg39/5/

Related

How to fire mouseenter event when cursor is hidden behind other HTML element?

I am trying to create draggable chess pieces but I can't find any way to drop a piece on a square because when I hover over a droppable position while dragging a piece then the mouseenter event is not firing. I have noticed that z-index is the reason because when I put a lower z-index on a draggable piece then the mouseenter event works but this is not ideal since I can't see a piece that I am dragging anymore.
Here is a codepen that simulates the same behaviour (you have to open a console). When mouse enters a black box then mouseenter event fires but if mouse enters while dragging a blue box then mouseenter event doesnt fire.
Is there a way to force the mouseenter or mouseover event to fire even when the mouse is hidden behind another HTML element? My goal is to detect when I am dragging over a droppable position so I can move my piece from one div to the other.
I have found similar issue in this old question but I really don't like either tracking x-y coords of every droppable div or creating transparent element over a droppable div with high z-index so I am hoping there is a cleaner solution for this.
Based on Forwarding Mouse Events through layers/divs, looks like you simply have to modify your draggable CSS by adding...
pointer-events: none;
...so that it becomes...
.draggable{
cursor: grab;
position:absolute;
z-index: 5;
--size: calc(100% - 2*var(--padding));
pointer-events: none;
}
What does this do? When the drag starts and applies the draggable class to the element being dragged, it turns off mouse events for the dragged element, thus allowing the mouse events to pass through the dragged element to any elements underneath.
(See https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events for complete list of options and browser support.)

Not all child elements trigger parent element click handler in Javascript (not preventDefault issue)

I have parent div - .parent - that has 300px height and 200 px width(doesn't matter).
I have a .child1,.child2, .child3 elements inside .parent div, each of them has content and height/width (this is just for simplicity, there are much more nesting in each of the child). All 3 children elements together occupy entire parent's container height. (e.g. every child has 100px height).
I have a click listener on .parent div:
$('.parent').click(function (){
console.log("Parent div clicked");
});
I noticed that my .parent click handler is triggered only if I clicked on .child3 element. When I am clicking on child1 or child2 - the event is not triggered.
What can be possible reasons why the parent click handler works only when clicking on .child3 and doesn't work when clicking on .child1,.child2?
I cannot share entire javascript/css of this issue, as there are a lot of it associated with every child and parent elements. I just wanted to get a hint where should I look?
My initial though was that there is some preventDefault/stopPropagation associated with .child1,.child2, which prevents click to be triggered on parent element, however, I didn't find any preventDefault associated with .child1 or .child2. Also, checked pointer-events too.
What else can impact that? Z-index? position:absolute?
UPDATE:
I also added click handler on document to see, what is a target when I click on .child1 or .child2. However, even this event is not triggered when I click on .child1 or .child2. It's triggered only if I click on .child3 (same as for .parent).
$(document).click(function(event) {
console.log("Document click: " + event);
});

Fire click events on div but pass through hover

I have a div that is absolutely positioned above other absolutely positioned divs and I want the divs below the have both mouseover, mouseout and click events and the top div to have click events also.
The only way I've been able to get mouse events on the divs below is to add pointer-events: none to the above div but then the above div does not get click events when that css property is present.
Here is a codepen showing the problem
http://codepen.io/Wryte/pen/qsEBp
#Wryte AH! ok, there is a problem with what you are trying to accomplish. The shade is not a container as a layer over the whole outer div that covers the rest of the inner DIVs. Since the shade div is not in the chain for event bubbling it won't get called or if you catch events on the shade DIV you won't get the events triggered on the inner DIVs.
What you can do, is to darken the outer DIV and add transparency to the inner DIVs. Why do you need to track events on the shade DIV by the way?

How to get a mouse event to fire on element obscured by another element?

I have one element that is out of position in terms of the normal css flow (it has absolute position). This means that it obscures areas of other elements.
What I want is for the element positionally below to receive mouse events when they occur on the obscuring element.
NB: I do not want to use the css pointer-events: none because I still need to see mouse events on the obscuring object.
See example:
http://jsfiddle.net/7ZpAp/6/
I want the "three" element to receive the mouse event.
Additional Info/Motivation: I'm trying to implement drag/drop functionality with Jquery UI. The "two" element is dragged from "one" to a "three" type element.
The dropping of an element (element "two" in example) should occur over the obscured element ("three"). There may be more than one element "two" can be dropped in - I want the event to detect which element it has been dropped in.
The mouseup event is the one I'm detecting, and the handler is attached to element "three". There currently appears to be a change in behaviour when "three" appears before "one" in the dom, as opposed to after! I have no idea why this would happen.
Try setting position: relative on the "three" element.

if cursor inside div then display block jquery

Here is a jsfiddle of the problem:
http://jsfiddle.net/MEJgb/
I want it so when you hover over anywhere in the footer the toggledown will become active and will remain active until you move the mouse from the footer.
Your problem is the following line:
jQuery('html,body').animate({
scrollTop: jQuery("#footer_copy_right").offset().top
}, 'slow');
This causes the whole page to move adn thus the item you were hovering over is no longer being hovered over so it triggers your event again and hides your text. When I was testing this was causing the hover content to move back under my mouse and thus trigger again...
I would personally not use hover in this situation and let the user click to expand and then click again to collapse.
If you want to keep using the hover option then you need to decide what the event to trigger the collapse should be. Clearly the current choice (mouse no longer over the arrow) is insufficient.
Often what I will do is attach the hover to a block containing the visible triggering block as well as the contents that are going to be displayed. This way your content won't collapse until you have moved off the newly displayed content.
http://jsfiddle.net/AjHwM/ is an example of such a thing.
Even if I'm not sure what your actual goal is, maybe the document.elementFromPoint() method is what helps you out here.
It is invoked like
if( document.elementFromPoint( event.pageX, event.pageY ) === $('#footer')[0] ) { }
That code, within your hover aka mouseenter / mouseleave handlers, would compare the node which lays under the current absolute mouse cursor X/Y positions against the #footer node.
Ref.: MDN doc, W3C doc

Categories