Immediate event handlers - need some clarification


I am trying to do custom handling of ‘copy’ events. This will require calling back into a port, in order to run document.execCommand('copy') on the JS side. This must be done immediately in the event handler, in order to know that it occured as the result of user input, and not some malicious code running in the background.

I knew there was stuff added in 0.19, to better support this kind of immediate handling. The documentation for it can be found here:

Can someone provide some clarification on Note 2:

Note 2: Some actions, like uploading and downloading files, are only allowed when the JavaScript event loop is running because of user input. This is for security! So when an event occurs, we call update and send any port messages immediately, all within the same tick of the event loop. This makes it possible to handle user-instigated events in ports.

Does this apply to all event handlers in Elm? Or is it only some of the kinds of handler defined by the Handler type? I think MayPreventDefault is what I will be using, or possibly Custom if I need to.


Stackoverflow answer here gives some good detail on custom handling of copy to the clipboard:

There is also the doc comment on Html.Event.custom adding to the confusion:

It says:

Note: If you need something even more custom (like capture phase) check out the lower-level event API in elm/virtual-dom .

My guess is that all the different ways of attaching event handlers all go to the VirtualDom.on function, that all event handling processing is handled synchronously, and that includes port Cmds coming out of the event handling update.

From the Elm side, this applies to all event handlers. Note 3 specifically talks about the view, which may happen only after an animation frame. update and synchronous commands are always called immediately though:

The elm-internal event callback calls currentEventNode here (an interesting name choice IMO), where eventNode is a linked list of all calls + the final Process.sendToApp. sendToApp gets injected by Platform.initialize.This first calls the update function, and then immediately calls enqueueEffects on all returned commands, which immediately starts dispatching effects if it isn’t doing that already.The effect manager for ports then calls all registered callbacks synchronously.

Elm Kernel code is always “fun” to decipher :smiley:

I’m not quite sure how all of this interacts with passive event listeners, though. This would be a browser issue then - whether or not passive listeners are still considered to run “after user interaction”.

Edit: elm/html does not contain any Kernel Code, it just provides some wrapper functions on top of elm/virtual-dom, like common nodes, attributes and events. So everything goes through the functions in virtual-dom eventually.

1 Like

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.