skpm / sketch-module-web-view

A sketch module for creating an complex UI with a webview
MIT License
289 stars 62 forks source link

The first click event is not registered in the UI when the panel is not focussed #10

Closed timohofmeijer closed 6 years ago

timohofmeijer commented 7 years ago

I’ve tried setting acceptsFirstClick to no avail. Do you happen to know if there is way to accept the first click event (maybe even the mouseover event)? Clicking twice is rather crippling to the experience in my case, since I use it to modify selected layer thus the panel is always blurred when accessed.

*I’m seriously grateful you took the time to craft and publish skpm by the way!

mathieudutour commented 7 years ago

based on this: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/EventOverview/HandlingMouseEvents/HandlingMouseEvents.html, it's acceptsFirstMouse and not acceptsFirstClick. Did you try it?

But I'm not an Cocoa expert so I don't really know haha

mathieudutour commented 7 years ago

just came across this: https://github.com/sureskumar/single-border/blob/master/Single-Border.sketchplugin/Contents/Sketch/scripts/common.js#L124-L156

Might be worth looking into if the acceptsFirstMouse doesn't work

cameronmcefee commented 6 years ago

Did either of you figure this one out? I'm willing to investigate acceptsFirstMouse if you can point me to where I should be implementing it. Would that be this repo something I'd do when initializing the webview? I presume this isn't the kind of thing that frameLoadDelegate handles. This doesn't work:

frameLoadDelegate: {
  'webView:acceptsFirstMouse': (webview, webframe) => {
    return true;
  }
}
mathieudutour commented 6 years ago

I think you would need to subclass the NSPanel using https://github.com/darknoon/cocoascript-class, add the method

'acceptFirstMouse:': (event) => true

and then use the subclass instead of the NSPanel.

I would do it on this PR: https://github.com/skpm/sketch-module-web-view/pull/24 since it's a complete rewrite that is much nicer. I need to find time to polish it and ship it. Hopefully soon

cameronmcefee commented 6 years ago

I see you beat me to it. Thanks for your work on this 😄

mathieudutour commented 6 years ago

yeah I tried the acceptFirstMouse approach but it doesn't work for a WebView 😢

So I found a "hack": when the panel is focused, I manually get the html element corresponding the click event and click on it

cameronmcefee commented 6 years ago

I've tried using it in your electron-api branch and it doesn't seem to work. Have you confirmed it works? Perhaps I'm misunderstanding what it should be doing.

    const options = {
      title: 'GuideGuide',
      identifier: 'com.guideguide.plugin',
      width: 260,
      height: 282,
      show: false,
      acceptsFirstMouse: true,
      //   onlyShowCloseButton: true,
      //   hideTitleBar: false,
      alwaysOnTop: true
    };

    this.ui = new BrowserWindow(options);

As an example, I expect that when this setting is enabled and the webUI window does not have focus, I could click a text field in the webUI and it would focus the text field (or click a button and have that button respond).

Are there any special considerations to be aware of? You mentioned your solution was a hack, so I'm wondering if my issue is something like the element that bubbles the event is not the one that receives your manual event.

mathieudutour commented 6 years ago

It was working for me. Maybe I messed up the coordinate computation?

Could you log the x and y here: https://github.com/skpm/sketch-module-web-view/blob/electron-api/lib/index.js#L220-L225? And then make sure that they are contained in the text field (document.elementFromPoint(' + x + ', ' + y + '))?

cameronmcefee commented 6 years ago

The computation looks right. I suspect that your hack just isn't complete yet. There's a few weird things that I intend to investigate (and submit a pr for) when I have more time.

I'm logging the element returned by elementFromPoint to see what it's tracking.

  1. It works on button elements

  2. When I click on an input, it logs the input element, but does not focus it. I suspect this will require handling inputs with focus rather than click.

  3. When I click on a link (which in my case functions as a button), nothing gets logged. If I try manually doing elementFromPoint from the console at the same coordinates, the contents of the link rather than the link itself are logged. This one will take more investigation to figure out.

cameronmcefee commented 6 years ago

I'm not sure why my initial tests on 3 weren't returning an element, but I've now got it logging and it's registering clicks on the child elements, not the links that contain them. I suspect that .click() doesn't bubble from children, because if you do the following (pulled from https://stackoverflow.com/a/13698694), it works as expected.

'var el = document.elementFromPoint(' + x + ', ' + y + '); var event = document.createEvent("MouseEvents"); event.initEvent("click", true, true); el.dispatchEvent(event); console.log(el)'

I want to do a little more research, because the Mozilla docs state that .click() should bubble up.

Based on this, I'll submit a PR that improves the snippet that gets run to determine the element it clicks and switch it's behavior accordingly.

cameronmcefee commented 6 years ago

I've got a working demo here: https://jsbin.com/favokeyaje/2/edit?html,js,console,output

The elementFromPoint() method of the Document interface returns the topmost element at the specified coordinates.

This shows that elementFromPoint is picking up the path inside the a, which doesn't have a click method. By instead dispatching a click event on it, the event bubbles up to the anchor, which has the handler on it.

As mentioned in my earlier message, I'll submit a PR with a fix. This will be a multi-line snippet. I'll do it as a string, like it is currently, but it might be better to include this as a client utility, if that's something you're interested in.