|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 |
- /**
- * 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
- */
- 'use strict';
-
- var BlockMapBuilder = require("./BlockMapBuilder");
-
- var CharacterMetadata = require("./CharacterMetadata");
-
- var DataTransfer = require("fbjs/lib/DataTransfer");
-
- var DraftModifier = require("./DraftModifier");
-
- var DraftPasteProcessor = require("./DraftPasteProcessor");
-
- var EditorState = require("./EditorState");
-
- var RichTextEditorUtil = require("./RichTextEditorUtil");
-
- var getEntityKeyForSelection = require("./getEntityKeyForSelection");
-
- var getTextContentFromFiles = require("./getTextContentFromFiles");
-
- var isEventHandled = require("./isEventHandled");
-
- var splitTextIntoTextBlocks = require("./splitTextIntoTextBlocks");
- /**
- * Paste content.
- */
-
-
- function editOnPaste(editor, e) {
- e.preventDefault();
- var data = new DataTransfer(e.clipboardData); // Get files, unless this is likely to be a string the user wants inline.
-
- if (!data.isRichText()) {
- var files = data.getFiles();
- var defaultFileText = data.getText();
-
- if (files.length > 0) {
- // Allow customized paste handling for images, etc. Otherwise, fall
- // through to insert text contents into the editor.
- if (editor.props.handlePastedFiles && isEventHandled(editor.props.handlePastedFiles(files))) {
- return;
- }
- /* $FlowFixMe This comment suppresses an error found DataTransfer was
- * typed. getFiles() returns an array of <Files extends Blob>, not Blob
- */
-
-
- getTextContentFromFiles(files, function (
- /*string*/
- fileText) {
- fileText = fileText || defaultFileText;
-
- if (!fileText) {
- return;
- }
-
- var editorState = editor._latestEditorState;
- var blocks = splitTextIntoTextBlocks(fileText);
- var character = CharacterMetadata.create({
- style: editorState.getCurrentInlineStyle(),
- entity: getEntityKeyForSelection(editorState.getCurrentContent(), editorState.getSelection())
- });
- var currentBlockType = RichTextEditorUtil.getCurrentBlockType(editorState);
- var text = DraftPasteProcessor.processText(blocks, character, currentBlockType);
- var fragment = BlockMapBuilder.createFromArray(text);
- var withInsertedText = DraftModifier.replaceWithFragment(editorState.getCurrentContent(), editorState.getSelection(), fragment);
- editor.update(EditorState.push(editorState, withInsertedText, 'insert-fragment'));
- });
- return;
- }
- }
-
- var textBlocks = [];
- var text = data.getText();
- var html = data.getHTML();
- var editorState = editor._latestEditorState;
-
- if (editor.props.handlePastedText && isEventHandled(editor.props.handlePastedText(text, html, editorState))) {
- return;
- }
-
- if (text) {
- textBlocks = splitTextIntoTextBlocks(text);
- }
-
- if (!editor.props.stripPastedStyles) {
- // If the text from the paste event is rich content that matches what we
- // already have on the internal clipboard, assume that we should just use
- // the clipboard fragment for the paste. This will allow us to preserve
- // styling and entities, if any are present. Note that newlines are
- // stripped during comparison -- this is because copy/paste within the
- // editor in Firefox and IE will not include empty lines. The resulting
- // paste will preserve the newlines correctly.
- var internalClipboard = editor.getClipboard();
-
- if (data.isRichText() && internalClipboard) {
- if ( // If the editorKey is present in the pasted HTML, it should be safe to
- // assume this is an internal paste.
- html.indexOf(editor.getEditorKey()) !== -1 || // The copy may have been made within a single block, in which case the
- // editor key won't be part of the paste. In this case, just check
- // whether the pasted text matches the internal clipboard.
- textBlocks.length === 1 && internalClipboard.size === 1 && internalClipboard.first().getText() === text) {
- editor.update(insertFragment(editor._latestEditorState, internalClipboard));
- return;
- }
- } else if (internalClipboard && data.types.includes('com.apple.webarchive') && !data.types.includes('text/html') && areTextBlocksAndClipboardEqual(textBlocks, internalClipboard)) {
- // Safari does not properly store text/html in some cases.
- // Use the internalClipboard if present and equal to what is on
- // the clipboard. See https://bugs.webkit.org/show_bug.cgi?id=19893.
- editor.update(insertFragment(editor._latestEditorState, internalClipboard));
- return;
- } // If there is html paste data, try to parse that.
-
-
- if (html) {
- var htmlFragment = DraftPasteProcessor.processHTML(html, editor.props.blockRenderMap);
-
- if (htmlFragment) {
- var contentBlocks = htmlFragment.contentBlocks,
- entityMap = htmlFragment.entityMap;
-
- if (contentBlocks) {
- var htmlMap = BlockMapBuilder.createFromArray(contentBlocks);
- editor.update(insertFragment(editor._latestEditorState, htmlMap, entityMap));
- return;
- }
- }
- } // Otherwise, create a new fragment from our pasted text. Also
- // empty the internal clipboard, since it's no longer valid.
-
-
- editor.setClipboard(null);
- }
-
- if (textBlocks.length) {
- var character = CharacterMetadata.create({
- style: editorState.getCurrentInlineStyle(),
- entity: getEntityKeyForSelection(editorState.getCurrentContent(), editorState.getSelection())
- });
- var currentBlockType = RichTextEditorUtil.getCurrentBlockType(editorState);
- var textFragment = DraftPasteProcessor.processText(textBlocks, character, currentBlockType);
- var textMap = BlockMapBuilder.createFromArray(textFragment);
- editor.update(insertFragment(editor._latestEditorState, textMap));
- }
- }
-
- function insertFragment(editorState, fragment, entityMap) {
- var newContent = DraftModifier.replaceWithFragment(editorState.getCurrentContent(), editorState.getSelection(), fragment); // TODO: merge the entity map once we stop using DraftEntity
- // like this:
- // const mergedEntityMap = newContent.getEntityMap().merge(entityMap);
-
- return EditorState.push(editorState, newContent.set('entityMap', entityMap), 'insert-fragment');
- }
-
- function areTextBlocksAndClipboardEqual(textBlocks, blockMap) {
- return textBlocks.length === blockMap.size && blockMap.valueSeq().every(function (block, ii) {
- return block.getText() === textBlocks[ii];
- });
- }
-
- module.exports = editOnPaste;
|