mar10/jquery-ui-contextmenu

preventSelect: true breaks IE 11 text selection

Closed this issue · 6 comments

Under IE 11 (tested 11.0.9600), executing $(document).contextmenu( { preventSelect: true } ) breaks all text input controls (e.g. <input type="text" /> or <textarea></textarea>) anywhere on the page, such that you can no longer drag the mouse to select anything in them (you can still click into them to type, but selection is broken), and persists from then on. Note that this happens as soon as the context menu is created by the above statement --- you do not need to actually open the context menu.

This behaviour is IE-only; Chrome & Firefox are fine. It took me ages to realise that the context menu was causing this, and track down the cause!

mar10 commented

This was caused because the mandatory delegate option was ommitted. Some browsers seem to interpret this as 'match all'. (I will add a check for this with the next release.)

The preventSelect option then applied users-select: none to the delegate selector.

Thank you again for answering!

(BTW, if delegate is that mandatory, you might look at some of your documentation examples and put it in, because it's not there in most examples.)

In that case, I think I need some clarification on what to set your delegate to. I am using an external framework with its own objects. It raises an event like itsObject.onContextMenu() to which I can attach a handler, and in that handler I create & open your context menu programmatically (so the context menu has autotrigger: false). I don't really have an HTML element on which I could place, say, a CSS class. I use $(document).contextmenu() to create & open your menu.

So should I set perhaps delegate: 'body'? And that will mean that, in IE 11 at least, it will not permanently block selections in all input controls?

OK, I have now played with delegate when preventSelect: true, and seen what you are doing to the page. It's complicated.

First, I think you should be aware of different behaviours under different browsers. I have a page body, and it has a textarea as a descendent. I have tried setting delegate: 'body' and delegate: '#idTextArea'. (These are not the right things as triggers of my context menu, but it exemplifies behaviour of user-select: none.)

  1. Under Chrome, neither has any effect at all on selection in the textarea.
  2. Under IE11 they both block selection in textarea.
  3. Under Firefox, textarea user-select: none blocks textarea selection but body user-select: none does not block descendent textarea, despite Moz docs claiming it applies to sub-elements.

That explains why IE was blocking when the others were not.

That raises two questions:

  1. Just what precisely do you want us to use preventSelect: true, which is user-select: none, for? Your docs state "Prevent accidental text selection of potential menu targets on doubleclick or drag", but that's not clear at all to me. I was using it because the element a user can right-click on can also be dragged; but I certainly don't want to block text selection inside it as per IE 11's behaviour. It seems I had just better not use preventSelect: true at all....

  2. Now I understand the relationship between delegate & preventSelect. However, does delegate have any effect when preventSelect: false? If so, precisely what? If you also read my previous post, if I am not sure what was right-clicked for the context menu what do you want me to set delegate to, because now body looks dangerous....

Many thanks for your attention. I do hope this is of use to you too, and you don't take my comments as complaining!

mar10 commented

Many thanks for your attention. I do hope this is of use to you too, and you don't take my comments as complaining!

Sure, I appreciate any kind of constructive feedback.

(BTW, if delegate is that mandatory, you might look at some of your documentation examples and put it in, because it's not there in most examples.)

Hmm, I thought I did that in most examples (only replacing with "..." where the advanced examples are focused on event handlers, for example). Which samples are you referring to?
Btw. If you think you can improve the Wiki: feel free to edit.

OK, I have now played with delegate when preventSelect: true, and seen what you are doing to the page. It's complicated.

Hopefully not ;) Let's forget about 'preventSelect' for now.
This plugin is based implemented as jQuery plugin, so we need this call syntax:

$("selector").contextmenu({...});

The selector defines the top/root element, where the context menu is attached to and listens for contextmenu events.
This is may be the id of a container div. If you want menus for elements on the whole page, use document or body.

The plugin uses event delegation to catch events.
The delegate option decides which elements can trigger a menu (other event targets are ignored).

Note that even if you open the menu programmatically, this is done by triggering a contextmenu event on the target element. This element must be matched by the delegate selector, otherwise it would be ignored.

I don't really have an HTML element

I think you probably have one, since you are passing it to contextmenu("open", ...)?

Just what precisely do you want us to use preventSelect: true, which is user-select: none, for?

This is just a convenience feature and off by default. Right clicking on a span with text sometimes selects the word. Often we don't want this, so user-select: none helps.
If you don't need that, don't set this option (especially if your delegate selector includes text inputs).

I don't really have an HTML element

I think you probably have one, since you are passing it to contextmenu("open", ...) ?

No, I don't! That is why I wrote that I am using $(document).contextmenu(...)! And it is precisely because I am using document that we have discovered all my text input controls anywhere on the page (under IE 11, which truly inherits the user-select: none down the whole hierarchy) were getting blocked by the preventSelect: true.

I agree that I do not need the preventSelect: true, and now that I have removed it all is much better.

All that then leaves is --- assuming we are not using preventSelect --- what precisely is the effect of the delegate? I see that when the context menu is created you inject a class onto the element (but without preventSelect you do not inject the style: user-select: none). Does that class have any effect/visuals (if it's placed on an element rather than the document)? Do you do anything other than that?

For example, at present my code does not even create the context menu (and then immediately open it) until the framework reports a right-click to me, whereas you normally expect the context menu to have been created in advance; so mine will not get any styling/behaviour before the first right-click. It also means I execute the create multiple times. You may not like that. I'm thinking I ought go change code to create all my context menus at document ready time instead of at click time....

Also, I don't get the distinction between the element contextmenu() is called on versus the delegate. Suppose:

$('#element_1').contextmenu( { delegate: '#element_2' } )

What happens/is done to/styled to element_1 and what happens to element_2?