kweb-core icon indicating copy to clipboard operation
kweb-core copied to clipboard

Add preventDefault() ability while handling events

Open marad opened this issue 4 years ago • 6 comments

Hi I'm experimenting a bit with KWeb on my side project and I'd like to create custom keyboard shortcuts, but unfortunately on Ctrl+P there is browser print function.

I did this:

doc.body.on.keyup {
  if (it.ctrlKey && it.key == "p") {
    println("ctrl+p pressed")
  }
}

The message is shown, but also browser print dialog pops up.

marad avatar Apr 25 '20 09:04 marad

For now I kinda hacked around with custom events. I just register regular JS shortcut with Mousetrap which sends my action event:

Mousetrap.bind('ctrl+p', function(e) {
    var event = new CustomEvent('searchPageAction');
    document.dispatchEvent(event);
    return false;
});

Then in KWeb I can catch that and do what needs to be done. The best part of coming up with this is that I can actually use onImmediate to show the dialog without a lag (which would not be an option with preventDefault on server):

doc.body.onImmediate.event("searchPageAction") {
  // show search dialog
}

doc.body.on.event("searchPageAction") {
  // do things that should be done on the server (if any)
}

marad avatar Apr 25 '20 09:04 marad

Actually I've made a little plugin for that:

import kweb.WebBrowser
import kweb.plugins.KwebPlugin
import org.jsoup.nodes.Document

class MousetrapPlugin : KwebPlugin() {
    override fun decorate(doc: Document) {
        doc.head().appendElement("script")
            .attr("src", "//cdnjs.cloudflare.com/ajax/libs/mousetrap/1.4.6/mousetrap.min.js")
    }
}

private fun makeEventName(eventName: String) = "action_$eventName"

public fun WebBrowser.registerAction(shortcut: String, actionName: String) {
    evaluate(
        """
            Mousetrap.bind("$shortcut", function() {
              var event = new CustomEvent("${makeEventName(actionName)}");
              document.body.dispatchEvent(event);
              return false;
            });
        """.trimIndent()
    )
}

public fun WebBrowser.onAction(actionName: String, callback: () -> Unit) {
    doc.body.on.event(makeEventName(actionName)) {
        callback()
    }
}

public fun WebBrowser.onImmediateAction(actionName: String, callback: () -> Unit) {
    doc.body.onImmediate.event(makeEventName(actionName)) {
        callback()
    }
}

And usage:

Kweb(port = 12345, plugins = listOf(MousetrapPlugin()) {
    registerAction("ctrl+p", "myAction")
    onAction("myAction") {
        println("Do my action")
    }
}

marad avatar Apr 25 '20 10:04 marad

Very cool, just trying to figure out what the most general version of this is.

Is the main need here the ability to call preventDefault() from within the event handler on the client before the event is reported to the server?

Could this be achieved with something like:

element.on(preventDefault = true).click {
  println("Element clicked")
}

(onImmediate would have similar functionality).

sanity avatar Apr 25 '20 14:04 sanity

@sanity I guess it depends on what the user wants to achieve. In my case that would totally work, but I can imagine that someone would want to cancel an event based on some data from within the event.

marad avatar Apr 25 '20 15:04 marad

Yes, that's a possibility - although hopefully a rare use-case in practice.

sanity avatar Apr 25 '20 15:04 sanity

I've to little experience with frontend development to tell. It's your call :)

marad avatar Apr 25 '20 18:04 marad

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

github-actions[bot] avatar Oct 12 '22 03:10 github-actions[bot]

Not sure if this is still relevant.

sanity avatar Oct 12 '22 06:10 sanity

Apparently fixed 7/17/2021

sanity avatar Oct 12 '22 16:10 sanity