-
Notifications
You must be signed in to change notification settings - Fork 46.9k
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
Support iframes (nested browsing contexts) in selection event handling #7866
Conversation
If an input inside a same-domain iframe is the actual activeElement, this change will make the ReactInputSelection module get from and restore selection to that input, rather than the iframe element itself
Had to remove some tests because they rely on DOM functionality that jsdom doesn’t yet support, like getSelection and iframe activeElement
I created a demo of a simple use case to illustrate the utility of this PR. I then duplicated the demo and have one using the current react and react-dom builds and one using built versions of those files made from this branch. Without the changes in this branch: http://codepen.io/acusti/pen/kkBpWA?editors=0011 |
One issue that remains is that the selection in the |
I updated the demo to include logic for maintaining the |
I made another demo that only changes the textarea value in the iframe on enter or blur and manually restores selection then focuses the iframe when appropriate (much like Without the changes in this branch: http://codepen.io/acusti/pen/EgQxJG?editors=0011 Makes me think that if |
Continuing this ongoing conversation with myself, above I wrote that:
I’ve since figured out how It’s seamless and makes for a really nice UX, plus it uses native browser functionality so has full a11y. This made me realize that in order to make |
The new PR which gets and restores selections for any iframes, not just the primary focused one, is #7936 |
I’m thinking I should close this in favor of #7936, because that implementation seems more complete to me based on the current behavior of ReactInputSelection, but it’s hard for me to know what people would be interested in without hearing from anyone. Any thoughts, comments, opinions? Should I close this one? Close #7936? |
React generally handles being rendered into another window context correctly (we have been doing this for a while in native Mac popovers). The main place where there are global window/document accesses are in places where we deal with the DOM selection (window.getSelection() and document.activeElement). There has been some discussion about this in the public React GitHub repo: facebook/fbjs#188 facebook#7866 facebook#7936 facebook#9184 While this was a good starting point, those proposed changes did not go far enough, since they assumed that React was executing in the top-most window, and the focus was in a child frame (in the same origin). Thus for them it was possible to check document.activeElement in the top window, find which iframe had focus and then recurse into it. In our case, the controller and view frames are siblings, and the top window is in another origin, so we can't use that code path. The main reason why we can't get the current window/document is that ReactInputSelection runs as a transaction wrapper, which doesn't have access to components or DOM nodes (and may run across multiple nodes). To work around this I added a ReactLastActiveThing which keeps track of the last DOM node that we mounted a component into (for the initial render) or the last component that we updated (for re-renders). It's kind of gross, but I couldn't think of any better alternatives. All of the modifications are no-ops when not running inside a frame, so this should have no impact for non-elements uses. I did not update any of the IE8 selection API code paths, we don't support it.
React generally handles being rendered into another window context correctly (we have been doing this for a while in native Mac popovers). The main place where there are global window/document accesses are in places where we deal with the DOM selection (window.getSelection() and document.activeElement). There has been some discussion about this in the public React GitHub repo: facebook/fbjs#188 facebook#7866 facebook#7936 facebook#9184 While this was a good starting point, those proposed changes did not go far enough, since they assumed that React was executing in the top-most window, and the focus was in a child frame (in the same origin). Thus for them it was possible to check document.activeElement in the top window, find which iframe had focus and then recurse into it. In our case, the controller and view frames are siblings, and the top window is in another origin, so we can't use that code path. The main reason why we can't get the current window/document is that ReactInputSelection runs as a transaction wrapper, which doesn't have access to components or DOM nodes (and may run across multiple nodes). To work around this I added a ReactLastActiveThing which keeps track of the last DOM node that we mounted a component into (for the initial render) or the last component that we updated (for re-renders). It's kind of gross, but I couldn't think of any better alternatives. All of the modifications are no-ops when not running inside a frame, so this should have no impact for non-elements uses. I did not update any of the IE8 selection API code paths, we don't support it. (cherry picked from commit 94b759b in the 0.14-stable. Appears to work mostly as is, needed to be updated to take 5c5d2ec into account)
Closing in favor of #11410 |
Fixes #427
dda228b depends on facebook/fbjs#188 to actually work. With the current version of fbjs, the doc argument will be ignored and
getActiveElement
will execute relative to the globaldocument
.Had some more tests for
ReactInputSelection
that rely on DOM functionality that jsdom doesn’t yet support. Includes this block, forsetSelection
, but requires a workinggetSelection()
implementation (see jsdom/jsdom#937):Also, had a suite for
getSelectionInformation/restoreSelection
for a focused element inside an iframe, but it requires jsdom to have accurateactiveElement
functionality with iframes. I made a PR to fix that part of jsdom (jsdom/jsdom#1621), so hopefully when that functionality gets added, I can add these tests in: