open-ui icon indicating copy to clipboard operation
open-ui copied to clipboard

[Invokers] Expose API for default `invokeaction` handlers

Open shgysk8zer0 opened this issue 3 months ago • 1 comments

Addressing the need for polyfills, including support for any future elements or actions, we'll need adequate means of progressive enhancement for this. Namely, I think elements will need methods for listing actions/checking for a handled action, as well as to register new handlers for actions.

I'm currently experimenting with the API in Firefox by toggling dom.element.invokers.enabled, and I'm finding that, while it does dispatch invoke events, it does not currently provide any default handling for various actions. And I find myself lacking the means of detecting if some given action for an element has a default handler or if I need to manually handle it. This is obviously just a problem of an incomplete implementation in this case, but I can see the same issue arising whenever the defaults are expanded upon.

So, I propose the following methods:

  • HTMLElement.hasInvokeAction(action) -> Boolean
  • HTMLElement.addInvokeAction(action, callback) -> Boolean (if there was previously and invoke action handler)
  • HTMLElement.getAllInvokeActions() -> Array or Set (not strictly necessary)
  • HTMLElement.getInvokeAction(action) -> Function (not necessary, but helpful for polyfills)

I'm not set on the method names, and only hasInvokeAction() and addInvokeAction() are strictly necessary. But I am thinking these would be best as static methods, and where eg HTMLDialogElement overrides the methods on HTMLElement. At least the hasInvokeAction() and addInvokeAction() would need to be static since they apply to all such elements rather than a particular instance.

Alternatively, this could be exposed via a map-like static actions property and Element.actions.has(action) and Element.actions.set(action, handler).

Example Usage:

if (! HTMLDialogElement.hasInvokeAction('showModal')) {
  HTMLDialogElement.addInvokeAction('showModal', (invokeEvent) => {
    if (! invokeEvent.target.open) {
      invokeEvent.target.showModal();
    }
  });
}

if (! HTMLFooElement.hasInvokeAction('bar')) {
  // Allow for adding new default invoke handlers on new tags and actions
  HTMLFooElement.addInvokeAction('bar', function({ target, action, invoker {) {
   HTMLBarElement.getInvokeAction('bar').call(null, { target,  action, invoker });
  });
}

Example of getInvokeAction() in Polyfill:

someEl.addEventListener('invoke', event => {
  // Static methods do make it a bit clunky to add invoke listeners
  // But it does provide a convenient way of using added action handlers

  if (event.target.constructor.hasInvokeAction(event.action)) {
    event.target.constructor.getInvokeAction(event.action).call(null, event);
  }
});

shgysk8zer0 avatar Mar 26 '24 04:03 shgysk8zer0