mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Fix IE11 collapsed ranges in ReactDOMSelection
In IE10/11, it is apparently possible to have a Selection or Range object that has the following properties: - `anchorNode` === `focusNode` (Selection) or `startContainer` === `endContainer` (Range) - `anchorOffset` === `focusOffset` (Selection) or `startOffset` === `endOffset` (Range) - `isCollapsed` === `false` (Selection) or `collapsed` === `false` (Range) As defined in http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html, this doesn't really make sense. Since the nodes and offsets are the same, the "collapsed" value should be `true`. Moreover, when calling `selection.toString()` in this case, it appears that the entire text contents of `body` -- including `<script>` tag contents -- are considered within the selection. I thought maybe the selected nodes were missing from the DOM or something, but no, they're there. Sidestep all of this in `ReactDOMSelection` by calculating the `collapsed` property manually and setting the selection length directly to zero if it is actually collapsed. Side note: I think that for selection restoration on contenteditables, we shouldn't try to do this offset calculation. We should just use the structure provided natively (nodes and offsets) since we can restore using that structure as well.
This commit is contained in:
committed by
Paul O’Shannessy
parent
1b022e9b3a
commit
cc292c1e22
@@ -23,6 +23,15 @@ var ExecutionEnvironment = require('ExecutionEnvironment');
|
||||
var getNodeForCharacterOffset = require('getNodeForCharacterOffset');
|
||||
var getTextContentAccessor = require('getTextContentAccessor');
|
||||
|
||||
/**
|
||||
* While `isCollapsed` is available on the Selection object and `collapsed`
|
||||
* is available on the Range object, IE11 sometimes gets them wrong.
|
||||
* If the anchor/focus nodes and offsets are the same, the range is collapsed.
|
||||
*/
|
||||
function isCollapsed(anchorNode, anchorOffset, focusNode, focusOffset) {
|
||||
return anchorNode === focusNode && anchorOffset === focusOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the appropriate anchor and focus node/offset pairs for IE.
|
||||
*
|
||||
@@ -73,13 +82,31 @@ function getModernOffsets(node) {
|
||||
var focusOffset = selection.focusOffset;
|
||||
|
||||
var currentRange = selection.getRangeAt(0);
|
||||
var rangeLength = currentRange.toString().length;
|
||||
|
||||
// If the node and offset values are the same, the selection is collapsed.
|
||||
// `Selection.isCollapsed` is available natively, but IE sometimes gets
|
||||
// this value wrong.
|
||||
var isSelectionCollapsed = isCollapsed(
|
||||
selection.anchorNode,
|
||||
selection.anchorOffset,
|
||||
selection.focusNode,
|
||||
selection.focusOffset
|
||||
);
|
||||
|
||||
var rangeLength = isSelectionCollapsed ? 0 : currentRange.toString().length;
|
||||
|
||||
var tempRange = currentRange.cloneRange();
|
||||
tempRange.selectNodeContents(node);
|
||||
tempRange.setEnd(currentRange.startContainer, currentRange.startOffset);
|
||||
|
||||
var start = tempRange.toString().length;
|
||||
var isTempRangeCollapsed = isCollapsed(
|
||||
tempRange.startContainer,
|
||||
tempRange.startOffset,
|
||||
tempRange.endContainer,
|
||||
tempRange.endOffset
|
||||
);
|
||||
|
||||
var start = isTempRangeCollapsed ? 0 : tempRange.toString().length;
|
||||
var end = start + rangeLength;
|
||||
|
||||
// Detect whether the selection is backward.
|
||||
|
||||
Reference in New Issue
Block a user