function addFocusToSelection()

in src/component/selection/setDraftEditorSelection.js [238:327]


function addFocusToSelection(
  selection: SelectionObject,
  node: ?Node,
  offset: number,
  selectionState: SelectionState,
): void {
  const activeElement = getActiveElement();
  const extend = selection.extend;
  // containsNode returns false if node is null.
  // Let's refine the type of this value out here so flow knows.
  if (extend && node != null && containsNode(activeElement, node)) {
    // If `extend` is called while another element has focus, an error is
    // thrown. We therefore disable `extend` if the active element is somewhere
    // other than the node we are selecting. This should only occur in Firefox,
    // since it is the only browser to support multiple selections.
    // See https://bugzilla.mozilla.org/show_bug.cgi?id=921444.

    // logging to catch bug that is being reported in t16250795
    if (offset > getNodeLength(node)) {
      // the call to 'selection.extend' is about to throw
      DraftJsDebugLogging.logSelectionStateFailure({
        anonymizedDom: getAnonymizedEditorDOM(node),
        extraParams: JSON.stringify({offset}),
        selectionState: JSON.stringify(selectionState.toJS()),
      });
    }

    // logging to catch bug that is being reported in t18110632
    const nodeWasFocus = node === selection.focusNode;
    try {
      // Fixes some reports of "InvalidStateError: Failed to execute 'extend' on
      // 'Selection': This Selection object doesn't have any Ranges."
      // Note: selection.extend does not exist in IE.
      if (selection.rangeCount > 0 && selection.extend) {
        selection.extend(node, offset);
      }
    } catch (e) {
      DraftJsDebugLogging.logSelectionStateFailure({
        anonymizedDom: getAnonymizedEditorDOM(node, function (n) {
          const labels = [];
          if (n === activeElement) {
            labels.push('active element');
          }
          if (n === selection.anchorNode) {
            labels.push('selection anchor node');
          }
          if (n === selection.focusNode) {
            labels.push('selection focus node');
          }
          return labels;
        }),
        extraParams: JSON.stringify(
          {
            activeElementName: activeElement ? activeElement.nodeName : null,
            nodeIsFocus: node === selection.focusNode,
            nodeWasFocus,
            selectionRangeCount: selection.rangeCount,
            selectionAnchorNodeName: selection.anchorNode
              ? selection.anchorNode.nodeName
              : null,
            selectionAnchorOffset: selection.anchorOffset,
            selectionFocusNodeName: selection.focusNode
              ? selection.focusNode.nodeName
              : null,
            selectionFocusOffset: selection.focusOffset,
            message: e ? '' + e : null,
            offset,
          },
          null,
          2,
        ),
        selectionState: JSON.stringify(selectionState.toJS(), null, 2),
      });
      // allow the error to be thrown -
      // better than continuing in a broken state
      throw e;
    }
  } else {
    // IE doesn't support extend. This will mean no backward selection.
    // Extract the existing selection range and add focus to it.
    // Additionally, clone the selection range. IE11 throws an
    // InvalidStateError when attempting to access selection properties
    // after the range is detached.
    if (node && selection.rangeCount > 0) {
      const range = selection.getRangeAt(0);
      range.setEnd(node, offset);
      selection.addRange(range.cloneRange());
    }
  }
}