Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

False positive when a user highlights text inside the modal and drags cursor outside #205

Open
zelaznik opened this issue Mar 4, 2021 · 2 comments

Comments

@zelaznik
Copy link

zelaznik commented Mar 4, 2021

Summary:

I tried add this modifier to a modal in our app. The modal is supposed to close if a user clicks outside the main content region. It's closing the modal when it shouldn't:

  • Click inside the modal to highlight some text
  • Drag the cursor slightly past the edge of the modal content
  • Lift the mouse button

This behavior should not be considered an outside click. To check whether this behavior is intentional, try clicking your mouse anywhere on a webpage, dragging your cursor on top of an interactive element such as a button or a link, and then release the cursor. The browser does not behave as though you just clicked on that button.

Possible solution:

Before I knew that this library even existed, I built our own outside click handling for our modal and had to deal with this very problem. It involves adding mousedown and mouseover listeners for the target area, and also adding mousedown and mouseup listeners for the entire document. Those events update a state object to track whether the mouse was ever clicked down on the target area or dragged over the target area. If either of those answers is "Yes", it doesn't fire the callback.

Here's the code I implemented for a standalone modifier. I tried looking through your source code, but I haven't digested it well enough to feel confident that I could create a PR and not break any of your work.

import { modifier } from 'ember-modifier';

export default modifier(function onOutsideClick(element, [callback]) {
  const state = {
    global: { mouseIsDown: false },
    target: { mouseWasDown: false, mouseWasOver: false },
  };

  const listeners = {
    target: {
      mousedown() {
        state.target.mouseWasDown = true;
      },
      mouseover() {
        if (state.global.mouseIsDown) {
          state.target.mouseWasOver = true;
        }
      },
    },
    global: {
      mousedown() {
        state.global.mouseIsDown = true;
      },
      mouseup(e) {
        const { mouseWasDown, mouseWasOver } = state.target;

        state.global.mouseIsDown = false;
        state.target.mouseWasDown = false;
        state.target.mouseWasOver = false;

        if (!mouseWasDown && !mouseWasOver) {
          callback(e);
        }
      },
    },
  };

  for (const eventName in listeners.target) {
    element.addEventListener(eventName, listeners.target[eventName]);
  }

  for (const eventName in listeners.global) {
    document.addEventListener(eventName, listeners.global[eventName]);
  }

  return () => {
    for (const eventName in listeners.target) {
      element.removeEventListener(eventName, listeners.target[eventName]);
    }

    for (const eventName in listeners.global) {
      document.removeEventListener(eventName, listeners.global[eventName]);
    }
  };
});
@zelaznik zelaznik changed the title False positive when a user highlights text inside the modal and drags into the outside region False positive when a user highlights text inside the modal and drags cursor outside Mar 4, 2021
@mamiller93
Copy link

mamiller93 commented Mar 8, 2021

@zelaznik I don't have that problem in our app. Have you tried wrapping the inner clickable menu area in a stop-propagation modifier?

Example:

<div>
    <button
      type="button"
      {{on "click" (set this "menuIsOpen" (not this.menuIsOpen))}}
      {{on-click-outside
        (set this "menuIsOpen" false)
        eventType="mousedown"
        exceptSelector=(concat "#" this.menuId " *")
      }}
    >
    </button>
    {{#if this.menuIsOpen}}
      <div
        id={{this.menuId}}
        {{on "click" (stop-propagation (set this "menuIsOpen" true))}}
      >
       [some clickable stuff here]
      </div>
    {{/if}}
  </div>

@zeppelin
Copy link
Owner

@zelaznik Sorry, got buried by other notifications.

Related: #49

Will check what could be done in the coming days!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants