Issue when copying on IE in a modal with a focus trap

Hi !

We used a PM instance inside a modal & our modal implements a focus trap : the user is limit to the modal content when using tab to switch between element (some onblur event prevent focus to be given to an element outside of the modal)

But on IE, the “hack” to handle copy/paste does not work.

What’s happens :

When the PM view is blured (https://github.com/ProseMirror/prosemirror-view/blob/master/src/input.js#L474) the focus trap is focusing the default element of our modal (aka the close button) wich cause the selection (setted on https://github.com/ProseMirror/prosemirror-view/blob/master/src/input.js#L476).

The result is nothing is copied from PM.

Maybe someone had a similar issue ?

After some tests & research for a workaround I found something working :

On captureCopy function, make the wrap element editable & focus the wrap element instead of a blur on the pm View.

It works & seems to be an “acceptable” modification since it doesn’t change the initial hack behavior.

Here is the whole captureCopy function I suggest :

function captureCopy(view, dom) {
  // The extra wrapper is somehow necessary on IE/Edge to prevent the
  // content from being mangled when it is put onto the clipboard
  if (!view.dom.parentNode) return
  let wrap = view.dom.parentNode.appendChild(document.createElement("div"))
  wrap.appendChild(dom)
  wrap.style.cssText = "position: fixed; left: -10000px; top: 10px"
  wrap.setAttribute("contenteditable", "true")
  let sel = getSelection(), range = document.createRange()
  range.selectNodeContents(dom)
  // Done because IE will fire a selectionchange moving the selection
  // to its start when removeAllRanges is called and the editor still
  // has focus (which will mess up the editor's selection state).
  wrap.focus() // will cause blur on pm view
  sel.removeAllRanges()
  sel.addRange(range)
  setTimeout(() => {
    if (wrap.parentNode) wrap.parentNode.removeChild(wrap)
    view.focus()
  }, 50)
}

Do you think this modification could be added to the pm-view source code ? (I can do a PR about this, but I prefer having a feedback first)

& if not, what is the best way for me to implement it whitout using a fork of pm-view ?

Do I understand correctly that the patch attached to this issue doesn’t help with this?

Initialy I had an issue on pasting & copying/cutting.

The patch you mentionned fix the pasting issue, but not the copying/cutting issue.

@marijn did the fix i mentionned above looks OK for you ? I can do the PR if you want.

So your focus trap code is preventing you from having nothing focused (when activeElement is document.body)? Wouldn’t that rather be a bug in that code?

Yes right, see here

To be honest I don’t know, from my POV it’s more an implementation choice…

I mean we are talking about a focus-trap lib with 255k weekly download & nobody seems to complain about this behavior. Also my company used it on several other project/part without any problem.

Maybe I’m missing something, but the fix does not seem to be a big deal & it seems almost logical to me to have a focusable element here…

Playing with the demos of that library, I can select text in the trapping element even when the focus trap is active, and I can call blur on the active element to move focus to the body without any issues. So maybe this is related to the way you’re using the library?

Yes right. But for some reasons it does not work with prosemirror when copying a text

I made a simple demo with prosemirror & focus-trap (nothing more) :

I try this app in IE (https://confusion-freckle-caboc.glitch.me/) and here is the result :

I tried to inderstand why focus trap allow selection inside a trap but why it does not work with PM copy hack …

From what I saw focus-trap behavior is not exactly the same between modern browser & IE :

  • On chome, when user selecting a text inside a trap, the click event is fired, but the target is inside the trap so nothing happens.
  • But on IE, the same happens, but in addition IE fire an focusIn event with document as target & it causes focus-trap to focus again the 1st active element.

You can see ths behavior in action on IE on the demo page of focus-trap :

That seems like something you could report to focus-trap.