8

I'm trying to make a little menu, that opens when you click on it, and closes when you click outside it. I managed to do that, mostly. The button I press to open the menu has some padding, and when I click specifically on the padding the menu that opens has all it's text selected, which is weird, and I don't understand why it happens. I have looked through MDN's documentation, my favorite search engine, and IRC(freenode) for a solution, but so far no luck.

I made a minimal working example, which I link to at the bottom, and I added a few comments to it about some lines you can comment to change the behavior. Simply, you can press the blue square, and the letter 'a' will show up selected, the expected behavior is that the letter 'a' should show up, but unselected. If you understand what is going on please let me know. ^_^

Edit: I see some discussion bellow about different results on different browsers. I'm currently using Firefox 59.0.1 64-bit on Linux(Fedora 27). A suggestion was made that this might be a bug, I can't rule that out.

https://jsfiddle.net/16k672tt/4/

function outside_function(event) {
    var outside = event.target;
    outside.classList.remove("outside");
    var menu_list = document.getElementById("menu-list");
    menu_list.classList.remove("menu-list-open");
    event.stopPropagation();
  }
  var outside = document.getElementById("outside");
  outside.addEventListener("click", outside_function);

  function menu_click_event(event) {
    var menu_list = document.getElementById("menu-list");
    var outside = document.getElementById("outside");
    menu_list.classList.add("menu-list-open");
    outside.classList.add("outside");
    event.stopPropagation();
  }
  var menu = document.getElementById("menu");
  menu.addEventListener("click", menu_click_event);
.menu {
  /* If you comment the next line, it renders the way I expect */
  display: flex;
  width: 2.5rem;
  height: 2.5rem;
  background-color: #0000ff80;
}

.outside {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}

.menu-list {
  display: none;
}

.menu-list-open {
  display: block;
  /* If you comment the next line, it renders the way I expect */
  /* In fact if you decrease the alpha value to 0 it works as well (#ffffff00) */
  background-color: #ffffffc0;
}
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <div id="outside"></div>
    <div id="menu" class="menu">
      <div id="menu-list" class="menu-list">
        a
      </div>
    </div>
  </body>
</html>
xor
  • 611
  • 6
  • 15

1 Answers1

0

I had a little talk with emilio on the #servo channel of mozilla's IRC network. He suggested the mouse down event is being triggered on the menu element, and the mouse up event is being triggered on the outside element. The browser assumes this was a drag motion, and selects the text in between. The problem seems to be the mouse up event is placed in the event queue after the click event. So even if the event propagation is stopped, there is already another event on the queue, mouse up, that will end up targeting the newly placed outside element. This could be a bug, so I'm off to https://bugzilla.mozilla.org/ to see if that is the case.

There have been work-arounds suggested, like using CSS's user-select to make the text unselectable, and the use of Javascript's preventDefault() to avoid running the default event handlers. Other stackoverflow users mentioned these but were unfortunately down-voted, and subsequently deleted their answers. I'm leaving these work-arounds here anyway, for anyone that might need them.

Thanks to all the people that helped look into this issue.

xor
  • 611
  • 6
  • 15
  • FWIW I’m pretty sure the other answers were downvoted because they were wrong (despite containing workarounds). One of them was “the text isn’t actually being selected, it just looks like it” and the other was “you must be double-clicking by accident”. – Ry- Mar 29 '18 at 01:57