Opting out of `dragenter` and `dragover` events (html5) - html

I have a collection of draggable "content" elements, and a root-level "feedback" UI element which is displayed above them to provide feedback during drag and drop.
The problem is, during the drag operation, hovering over the "feedback" element causes the dragenter and dragover events to be fired on that element, rather than the underlying content element. It effectively "blocks" the dragenter event from firing on the correct element.
Is there a way for an element to cancel, or "opt out" of a dragenter/dragover event? I could display the feedback element underneath the content, but I'd rather not do that.
jsFiddle: http://jsfiddle.net/jact8/1/
I'm using the HTML drag/drop API, not jQuery or anything like that.

I've created a new fiddle. I think you want to use currentTarget instead of target in your handler on the columns to ensure that the event you receive is from the element you added the listener to (column) rather than the element it originated from (italicised text). See explanation here (it's for ActionScript but I believe it's valid for JavaScript also).
I'm assuming the listener on the insertionCaret element is for debug purposes only and have removed it (let me know if I'm mistaken here). You won't receive the event if you don't listen for it so won't need to opt out of it!

Related

Programmatic focus of web components

What's the proper way to handle programmatic focus of web components?
Calling focus() on a web component should focus the appropriate element in the shadow DOM. This means overwriting the focus method.
This is not enough though, because the web browser is not aware that the component is interactive. One consequence it that clicking an anchor pointing to the element will not focus it as it would a native interactive html element like <button>. There may be other implications that I'm not aware of.
The only way I know to make an element interactive is to give it a tabindex value. But tabindex="0" will create an extra tab stop, while tabindex="-1" will remove all tab stops inside the component. So neither works. My next step is to set tabindex="0", then switch the value on focus() and blur(). It seems crazy to me that I have to do all this hacky work for such a basic requirement (making a web component properly interactive and accessible). Am I missing something? Is there a better solution?
I was missing something indeed. Web components have a specific API for this: delegatesFocus. MDN docs.
When set to true:
calling focus() on the host element brings the first focusable element within the shadow DOM into focus.
so does clicking inside the component on any non focusable element
the tab sequence is unchanged
:focus styles on the host are applied
It's part of the web components specs so no worries about support.

Did html spec require focus fire after mousedown?

Or it's just every browser happen to implement same behaviour? Only place I found in spec is in click event section which says
If the event target is focusable, the default action MUST be to give that element document focus.
But actually focus is the default action of mousedown event, which is widely used in today's frontend development, so I'd like to know why
Isn't the answer in the very quote you've posted?
If the event target is focusable, the default action MUST be to give that element document focus.
And then https://www.w3.org/TR/uievents/#event-type-focus
4.2.4.2. focus
...
A user agent MUST dispatch this event when an event target receives focus.
In other words: the spec indeed requires focus event to be fired when and if an element receives focus
By the way, the focus as event and focus as a property - is two different things.
But!.. The quote is actually from click event, not from mousedown
And if you test it in browsers you'll see that:
They behave differently (at least mine Chrome 81 and FF 75).
If you click inside <textarea>, but move out an only then release the button Chrome won't send click to the <textarea>, but FF will
But they give focus to <textarea> and fire focus event right after mousedown.
So that probably means, that:
No the spec doesn't require focus event to be fired after mousedown. (Instead it requires it to be fired after click)
Yes it's just so happens that every browser (well... at least those two I've tested) implement same non-standard behavior
So far the only thing I found in spec is
Many implementations use the mousedown event to begin a variety of contextually dependent default actions. These default actions can be prevented if this event is canceled. Some of these default actions could include: beginning a drag/drop interaction with an image or link, starting text selection, etc. Additionally, some implementations provide a mouse-driven panning feature that is activated when the middle mouse button is pressed at the time the mousedown event is dispatched.
Although it didn't explicitly says focus, I guess it's still enough evidence

How can I monitor focus events in Chrome?

I'm trying to track which element gets focus in a web app. I came across the monitorEvents API, but I'm having difficulty using it for control or focus events. Other events on body are working as expected, but not the control events. Any advice?
I'm not sure how exactly you want to "monitor" control events, but you can set event listener breakpoints on the entire category, or individual events like focus. Whenever a focus listener runs for any node on the page, DevTools pauses on the first line of the listener.
I was trying to monitor focus and blur events on the entire document today.
When using monitorEvents(document.body, 'control') I would only see the event fired when I left the tab entirely and then refocused. I believe what's happening is that once you're focused on the body, it'll never change when you focus on child elements since the listener is at a high level and the events just bubble up to the body with no change in focus.
I tried monitoring events on a few specific child elements and saw that those triggered how I expected. So I decided to add an event listener to each element in the document and that worked well. Here's the one-liner for that.
document.querySelectorAll("*").forEach((el)=> monitorEvents(el, 'control'))

Restrict event listeners of elements in HTML

Is it possible for an HTML element (DOM node) to have only a single event listener always?(meaning it should not further be possible to attach secondary events apart from the predefined (first) event listener).
Example :
<input type="button" id="button1" value="I HAVE ONLY ONE EVENT LISTENER" onclick="one_and_only_eventhandler()"/>
then it should not be possible to add secondary events using addEventListener/attachEvent/Onclick property further.
OR say it the other way a HTML element (DOM node) should only listen to its first event listener and should not listen to secondary events.
You can't really prevent that since most events go through the capture phase first and code could register an event listener on the document level capturing clicks long before they reach the inline handler.
And inline handlers are generally discouraged anyway. What you're trying to do sounds either like you're "fighting" against other javascript code or that your program design relies on something that DOM events are not designed to support. Either case would be very fragile.

Page flip effect on button press in html5

I'm looking at this:
http://www.netmagazine.com/tutorials/create-page-flip-effect-html5-canvas
However, I have one problem with that - I need to be able to click on the pages, even the edges, without triggering the page turn. I want the pages to turn when a button outside of the canvas is pressed. Is this possible using the base they provided, or do I need to go an entirely different direction?
Yes that can be done.
From what i can see, you need a click event that doesnt trigger the page drag. You need to assign a flag for this.
Let Drag = mouse drag/mouse move, down = mouse down, release = mouse release events respectively.
Initialize your flag variable as false. When a drag event is encountered it becomes true. Otherwise it remains false. As long as it is false when the mouse release event occurs it can be treated as a click. Thats the basic principle behind using mousedown and mouseup as a click event.
You will have to use e.srcElement or e.target to give you the element your cursor is currently positioned over inorder to trigger click functions relative to that element.
If you want a more detailed explanation on the page flip technique then check this out. Helped me lot.