import { __require as requireDraftModifier } from './DraftModifier.js';
import { __require as requireEditorState } from './EditorState.js';
import { __require as requireUserAgent } from '../../../../fbjs@2.0.0/node_modules/fbjs/lib/UserAgent.js';
import { __require as requireGetEntityKeyForSelection } from './getEntityKeyForSelection.js';
import { __require as requireIsEventHandled } from './isEventHandled.js';
import { __require as requireIsSelectionAtLeafStart } from './isSelectionAtLeafStart.js';
import { __require as requireNullthrows } from '../../../../fbjs@2.0.0/node_modules/fbjs/lib/nullthrows.js';
import { __require as requireSetImmediate } from '../../../../fbjs@2.0.0/node_modules/fbjs/lib/setImmediate.js';

/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 * 
 * @emails oncall+draft_js
 */

var editOnBeforeInput_1;
var hasRequiredEditOnBeforeInput;

function requireEditOnBeforeInput () {
	if (hasRequiredEditOnBeforeInput) return editOnBeforeInput_1;
	hasRequiredEditOnBeforeInput = 1;

	var DraftModifier = requireDraftModifier();

	var EditorState = requireEditorState();

	var UserAgent = requireUserAgent();

	var getEntityKeyForSelection = requireGetEntityKeyForSelection();

	var isEventHandled = requireIsEventHandled();

	var isSelectionAtLeafStart = requireIsSelectionAtLeafStart();

	var nullthrows = requireNullthrows();

	var setImmediate = requireSetImmediate(); // When nothing is focused, Firefox regards two characters, `'` and `/`, as
	// commands that should open and focus the "quickfind" search bar. This should
	// *never* happen while a contenteditable is focused, but as of v28, it
	// sometimes does, even when the keypress event target is the contenteditable.
	// This breaks the input. Special case these characters to ensure that when
	// they are typed, we prevent default on the event to make sure not to
	// trigger quickfind.


	var FF_QUICKFIND_CHAR = "'";
	var FF_QUICKFIND_LINK_CHAR = '/';
	var isFirefox = UserAgent.isBrowser('Firefox');

	function mustPreventDefaultForCharacter(character) {
	  return isFirefox && (character == FF_QUICKFIND_CHAR || character == FF_QUICKFIND_LINK_CHAR);
	}
	/**
	 * Replace the current selection with the specified text string, with the
	 * inline style and entity key applied to the newly inserted text.
	 */


	function replaceText(editorState, text, inlineStyle, entityKey, forceSelection) {
	  var contentState = DraftModifier.replaceText(editorState.getCurrentContent(), editorState.getSelection(), text, inlineStyle, entityKey);
	  return EditorState.push(editorState, contentState, 'insert-characters', forceSelection);
	}
	/**
	 * When `onBeforeInput` executes, the browser is attempting to insert a
	 * character into the editor. Apply this character data to the document,
	 * allowing native insertion if possible.
	 *
	 * Native insertion is encouraged in order to limit re-rendering and to
	 * preserve spellcheck highlighting, which disappears or flashes if re-render
	 * occurs on the relevant text nodes.
	 */


	function editOnBeforeInput(editor, e) {
	  if (editor._pendingStateFromBeforeInput !== undefined) {
	    editor.update(editor._pendingStateFromBeforeInput);
	    editor._pendingStateFromBeforeInput = undefined;
	  }

	  var editorState = editor._latestEditorState;
	  var chars = e.data; // In some cases (ex: IE ideographic space insertion) no character data
	  // is provided. There's nothing to do when this happens.

	  if (!chars) {
	    return;
	  } // Allow the top-level component to handle the insertion manually. This is
	  // useful when triggering interesting behaviors for a character insertion,
	  // Simple examples: replacing a raw text ':)' with a smile emoji or image
	  // decorator, or setting a block to be a list item after typing '- ' at the
	  // start of the block.


	  if (editor.props.handleBeforeInput && isEventHandled(editor.props.handleBeforeInput(chars, editorState, e.timeStamp))) {
	    e.preventDefault();
	    return;
	  } // If selection is collapsed, conditionally allow native behavior. This
	  // reduces re-renders and preserves spellcheck highlighting. If the selection
	  // is not collapsed, we will re-render.


	  var selection = editorState.getSelection();
	  var selectionStart = selection.getStartOffset();
	  var anchorKey = selection.getAnchorKey();

	  if (!selection.isCollapsed()) {
	    e.preventDefault();
	    editor.update(replaceText(editorState, chars, editorState.getCurrentInlineStyle(), getEntityKeyForSelection(editorState.getCurrentContent(), editorState.getSelection()), true));
	    return;
	  }

	  var newEditorState = replaceText(editorState, chars, editorState.getCurrentInlineStyle(), getEntityKeyForSelection(editorState.getCurrentContent(), editorState.getSelection()), false); // Bunch of different cases follow where we need to prevent native insertion.

	  var mustPreventNative = false;

	  if (!mustPreventNative) {
	    // Browsers tend to insert text in weird places in the DOM when typing at
	    // the start of a leaf, so we'll handle it ourselves.
	    mustPreventNative = isSelectionAtLeafStart(editor._latestCommittedEditorState);
	  }

	  if (!mustPreventNative) {
	    // Let's say we have a decorator that highlights hashtags. In many cases
	    // we need to prevent native behavior and rerender ourselves --
	    // particularly, any case *except* where the inserted characters end up
	    // anywhere except exactly where you put them.
	    //
	    // Using [] to denote a decorated leaf, some examples:
	    //
	    // 1. 'hi #' and append 'f'
	    // desired rendering: 'hi [#f]'
	    // native rendering would be: 'hi #f' (incorrect)
	    //
	    // 2. 'x [#foo]' and insert '#' before 'f'
	    // desired rendering: 'x #[#foo]'
	    // native rendering would be: 'x [##foo]' (incorrect)
	    //
	    // 3. '[#foobar]' and insert ' ' between 'foo' and 'bar'
	    // desired rendering: '[#foo] bar'
	    // native rendering would be: '[#foo bar]' (incorrect)
	    //
	    // 4. '[#foo]' and delete '#' [won't use this beforeinput codepath though]
	    // desired rendering: 'foo'
	    // native rendering would be: '[foo]' (incorrect)
	    //
	    // 5. '[#foo]' and append 'b'
	    // desired rendering: '[#foob]'
	    // native rendering would be: '[#foob]'
	    // (native insertion here would be ok for decorators like simple spans,
	    // but not more complex decorators. To be safe, we need to prevent it.)
	    //
	    // It is safe to allow native insertion if and only if the full list of
	    // decorator ranges matches what we expect native insertion to give, and
	    // the range lengths have not changed. We don't need to compare the content
	    // because the only possible mutation to consider here is inserting plain
	    // text and decorators can't affect text content.
	    var oldBlockTree = editorState.getBlockTree(anchorKey);
	    var newBlockTree = newEditorState.getBlockTree(anchorKey);
	    mustPreventNative = oldBlockTree.size !== newBlockTree.size || oldBlockTree.zip(newBlockTree).some(function (_ref) {
	      var oldLeafSet = _ref[0],
	          newLeafSet = _ref[1];
	      // selectionStart is guaranteed to be selectionEnd here
	      var oldStart = oldLeafSet.get('start');
	      var adjustedStart = oldStart + (oldStart >= selectionStart ? chars.length : 0);
	      var oldEnd = oldLeafSet.get('end');
	      var adjustedEnd = oldEnd + (oldEnd >= selectionStart ? chars.length : 0);
	      var newStart = newLeafSet.get('start');
	      var newEnd = newLeafSet.get('end');
	      var newDecoratorKey = newLeafSet.get('decoratorKey');
	      return (// Different decorators
	        oldLeafSet.get('decoratorKey') !== newDecoratorKey || // Different number of inline styles
	        oldLeafSet.get('leaves').size !== newLeafSet.get('leaves').size || // Different effective decorator position
	        adjustedStart !== newStart || adjustedEnd !== newEnd || // Decorator already existed and its length changed
	        newDecoratorKey != null && newEnd - newStart !== oldEnd - oldStart
	      );
	    });
	  }

	  if (!mustPreventNative) {
	    mustPreventNative = mustPreventDefaultForCharacter(chars);
	  }

	  if (!mustPreventNative) {
	    mustPreventNative = nullthrows(newEditorState.getDirectionMap()).get(anchorKey) !== nullthrows(editorState.getDirectionMap()).get(anchorKey);
	  }

	  if (mustPreventNative) {
	    e.preventDefault();
	    newEditorState = EditorState.set(newEditorState, {
	      forceSelection: true
	    });
	    editor.update(newEditorState);
	    return;
	  } // We made it all the way! Let the browser do its thing and insert the char.


	  newEditorState = EditorState.set(newEditorState, {
	    nativelyRenderedContent: newEditorState.getCurrentContent()
	  }); // The native event is allowed to occur. To allow user onChange handlers to
	  // change the inserted text, we wait until the text is actually inserted
	  // before we actually update our state. That way when we rerender, the text
	  // we see in the DOM will already have been inserted properly.

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

	editOnBeforeInput_1 = editOnBeforeInput;
	return editOnBeforeInput_1;
}

export { requireEditOnBeforeInput as __require };
//# sourceMappingURL=editOnBeforeInput.js.map
