function editOnInput(editor) {
	  if (editor._pendingStateFromBeforeInput !== undefined) {
	    editor.update(editor._pendingStateFromBeforeInput);
	    editor._pendingStateFromBeforeInput = undefined;
	  }

	  var domSelection = global.getSelection();

	  var anchorNode = domSelection.anchorNode,
	      isCollapsed = domSelection.isCollapsed;

	  var isNotTextNode = anchorNode.nodeType !== Node.TEXT_NODE;
	  var isNotTextOrElementNode = anchorNode.nodeType !== Node.TEXT_NODE && anchorNode.nodeType !== Node.ELEMENT_NODE;

	  if (DraftFeatureFlags.draft_killswitch_allow_nontextnodes) {
	    if (isNotTextNode) {
	      return;
	    }
	  } else {
	    if (isNotTextOrElementNode) {
	      // TODO: (t16149272) figure out context for this change
	      return;
	    }
	  }

	  if (anchorNode.nodeType === Node.TEXT_NODE && (anchorNode.previousSibling !== null || anchorNode.nextSibling !== null)) {
	    // When typing at the beginning of a visual line, Chrome splits the text
	    // nodes into two. Why? No one knows. This commit is suspicious:
	    // https://chromium.googlesource.com/chromium/src/+/a3b600981286b135632371477f902214c55a1724
	    // To work around, we'll merge the sibling text nodes back into this one.
	    var span = anchorNode.parentNode;
	    anchorNode.nodeValue = span.textContent;
	    for (var child = span.firstChild; child !== null; child = child.nextSibling) {
	      if (child !== anchorNode) {
	        span.removeChild(child);
	      }
	    }
	  }

	  var domText = anchorNode.textContent;
	  var editorState = editor._latestEditorState;
	  var offsetKey = nullthrows(findAncestorOffsetKey(anchorNode));

	  var _DraftOffsetKey$decod = DraftOffsetKey.decode(offsetKey),
	      blockKey = _DraftOffsetKey$decod.blockKey,
	      decoratorKey = _DraftOffsetKey$decod.decoratorKey,
	      leafKey = _DraftOffsetKey$decod.leafKey;

	  var _editorState$getBlock = editorState.getBlockTree(blockKey).getIn([decoratorKey, 'leaves', leafKey]),
	      start = _editorState$getBlock.start,
	      end = _editorState$getBlock.end;

	  var content = editorState.getCurrentContent();
	  var block = content.getBlockForKey(blockKey);
	  var modelText = block.getText().slice(start, end);

	  // Special-case soft newlines here. If the DOM text ends in a soft newline,
	  // we will have manually inserted an extra soft newline in DraftEditorLeaf.
	  // We want to remove this extra newline for the purpose of our comparison
	  // of DOM and model text.
	  if (domText.endsWith(DOUBLE_NEWLINE)) {
	    domText = domText.slice(0, -1);
	  }

	  // No change -- the DOM is up to date. Nothing to do here.
	  if (domText === modelText) {
	    // This can be buggy for some Android keyboards because they don't fire
	    // standard onkeydown/pressed events and only fired editOnInput
	    // so domText is already changed by the browser and ends up being equal
	    // to modelText unexpectedly
	    return;
	  }

	  var selection = editorState.getSelection();

	  // We'll replace the entire leaf with the text content of the target.
	  var targetRange = selection.merge({
	    anchorOffset: start,
	    focusOffset: end,
	    isBackward: false
	  });

	  var entityKey = block.getEntityAt(start);
	  var entity = entityKey && content.getEntity(entityKey);
	  var entityType = entity && entity.getMutability();
	  var preserveEntity = entityType === 'MUTABLE';

	  // Immutable or segmented entities cannot properly be handled by the
	  // default browser undo, so we have to use a different change type to
	  // force using our internal undo method instead of falling through to the
	  // native browser undo.
	  var changeType = preserveEntity ? 'spellcheck-change' : 'apply-entity';

	  var newContent = DraftModifier.replaceText(content, targetRange, domText, block.getInlineStyleAt(start), preserveEntity ? block.getEntityAt(start) : null);

	  var anchorOffset, focusOffset, startOffset, endOffset;

	  if (isGecko) {
	    // Firefox selection does not change while the context menu is open, so
	    // we preserve the anchor and focus values of the DOM selection.
	    anchorOffset = domSelection.anchorOffset;
	    focusOffset = domSelection.focusOffset;
	    startOffset = start + Math.min(anchorOffset, focusOffset);
	    endOffset = startOffset + Math.abs(anchorOffset - focusOffset);
	    anchorOffset = startOffset;
	    focusOffset = endOffset;
	  } else {
	    // Browsers other than Firefox may adjust DOM selection while the context
	    // menu is open, and Safari autocorrect is prone to providing an inaccurate
	    // DOM selection. Don't trust it. Instead, use our existing SelectionState
	    // and adjust it based on the number of characters changed during the
	    // mutation.
	    var charDelta = domText.length - modelText.length;
	    startOffset = selection.getStartOffset();
	    endOffset = selection.getEndOffset();

	    anchorOffset = isCollapsed ? endOffset + charDelta : startOffset;
	    focusOffset = endOffset + charDelta;
	  }

	  // Segmented entities are completely or partially removed when their
	  // text content changes. For this case we do not want any text to be selected
	  // after the change, so we are not merging the selection.
	  var contentWithAdjustedDOMSelection = newContent.merge({
	    selectionBefore: content.getSelectionAfter(),
	    selectionAfter: selection.merge({ anchorOffset: anchorOffset, focusOffset: focusOffset })
	  });

	  editor.update(EditorState.push(editorState, contentWithAdjustedDOMSelection, changeType));
	}
This function is intended to handle spellcheck and autocorrect changes,
which occur in the DOM natively without any opportunity to observe or
interpret the changes before they occur.

The `input` event fires in contentEditable elements reliably for non-IE
browsers, immediately after changes occur to the editor DOM. Since our other
handlers override or otherwise handle cover other varieties of text input,
the DOM state should match the model in all controlled input cases. Thus,
when an `input` change leads to a DOM/model mismatch, the change should be
due to a spellcheck change, and we can incorporate it into our model.