Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

editOnPaste.js 6.5 KiB

il y a 3 ans
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /**
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. *
  7. * @format
  8. *
  9. * @emails oncall+draft_js
  10. */
  11. 'use strict';
  12. var BlockMapBuilder = require("./BlockMapBuilder");
  13. var CharacterMetadata = require("./CharacterMetadata");
  14. var DataTransfer = require("fbjs/lib/DataTransfer");
  15. var DraftModifier = require("./DraftModifier");
  16. var DraftPasteProcessor = require("./DraftPasteProcessor");
  17. var EditorState = require("./EditorState");
  18. var RichTextEditorUtil = require("./RichTextEditorUtil");
  19. var getEntityKeyForSelection = require("./getEntityKeyForSelection");
  20. var getTextContentFromFiles = require("./getTextContentFromFiles");
  21. var isEventHandled = require("./isEventHandled");
  22. var splitTextIntoTextBlocks = require("./splitTextIntoTextBlocks");
  23. /**
  24. * Paste content.
  25. */
  26. function editOnPaste(editor, e) {
  27. e.preventDefault();
  28. var data = new DataTransfer(e.clipboardData); // Get files, unless this is likely to be a string the user wants inline.
  29. if (!data.isRichText()) {
  30. var files = data.getFiles();
  31. var defaultFileText = data.getText();
  32. if (files.length > 0) {
  33. // Allow customized paste handling for images, etc. Otherwise, fall
  34. // through to insert text contents into the editor.
  35. if (editor.props.handlePastedFiles && isEventHandled(editor.props.handlePastedFiles(files))) {
  36. return;
  37. }
  38. /* $FlowFixMe This comment suppresses an error found DataTransfer was
  39. * typed. getFiles() returns an array of <Files extends Blob>, not Blob
  40. */
  41. getTextContentFromFiles(files, function (
  42. /*string*/
  43. fileText) {
  44. fileText = fileText || defaultFileText;
  45. if (!fileText) {
  46. return;
  47. }
  48. var editorState = editor._latestEditorState;
  49. var blocks = splitTextIntoTextBlocks(fileText);
  50. var character = CharacterMetadata.create({
  51. style: editorState.getCurrentInlineStyle(),
  52. entity: getEntityKeyForSelection(editorState.getCurrentContent(), editorState.getSelection())
  53. });
  54. var currentBlockType = RichTextEditorUtil.getCurrentBlockType(editorState);
  55. var text = DraftPasteProcessor.processText(blocks, character, currentBlockType);
  56. var fragment = BlockMapBuilder.createFromArray(text);
  57. var withInsertedText = DraftModifier.replaceWithFragment(editorState.getCurrentContent(), editorState.getSelection(), fragment);
  58. editor.update(EditorState.push(editorState, withInsertedText, 'insert-fragment'));
  59. });
  60. return;
  61. }
  62. }
  63. var textBlocks = [];
  64. var text = data.getText();
  65. var html = data.getHTML();
  66. var editorState = editor._latestEditorState;
  67. if (editor.props.handlePastedText && isEventHandled(editor.props.handlePastedText(text, html, editorState))) {
  68. return;
  69. }
  70. if (text) {
  71. textBlocks = splitTextIntoTextBlocks(text);
  72. }
  73. if (!editor.props.stripPastedStyles) {
  74. // If the text from the paste event is rich content that matches what we
  75. // already have on the internal clipboard, assume that we should just use
  76. // the clipboard fragment for the paste. This will allow us to preserve
  77. // styling and entities, if any are present. Note that newlines are
  78. // stripped during comparison -- this is because copy/paste within the
  79. // editor in Firefox and IE will not include empty lines. The resulting
  80. // paste will preserve the newlines correctly.
  81. var internalClipboard = editor.getClipboard();
  82. if (data.isRichText() && internalClipboard) {
  83. if ( // If the editorKey is present in the pasted HTML, it should be safe to
  84. // assume this is an internal paste.
  85. html.indexOf(editor.getEditorKey()) !== -1 || // The copy may have been made within a single block, in which case the
  86. // editor key won't be part of the paste. In this case, just check
  87. // whether the pasted text matches the internal clipboard.
  88. textBlocks.length === 1 && internalClipboard.size === 1 && internalClipboard.first().getText() === text) {
  89. editor.update(insertFragment(editor._latestEditorState, internalClipboard));
  90. return;
  91. }
  92. } else if (internalClipboard && data.types.includes('com.apple.webarchive') && !data.types.includes('text/html') && areTextBlocksAndClipboardEqual(textBlocks, internalClipboard)) {
  93. // Safari does not properly store text/html in some cases.
  94. // Use the internalClipboard if present and equal to what is on
  95. // the clipboard. See https://bugs.webkit.org/show_bug.cgi?id=19893.
  96. editor.update(insertFragment(editor._latestEditorState, internalClipboard));
  97. return;
  98. } // If there is html paste data, try to parse that.
  99. if (html) {
  100. var htmlFragment = DraftPasteProcessor.processHTML(html, editor.props.blockRenderMap);
  101. if (htmlFragment) {
  102. var contentBlocks = htmlFragment.contentBlocks,
  103. entityMap = htmlFragment.entityMap;
  104. if (contentBlocks) {
  105. var htmlMap = BlockMapBuilder.createFromArray(contentBlocks);
  106. editor.update(insertFragment(editor._latestEditorState, htmlMap, entityMap));
  107. return;
  108. }
  109. }
  110. } // Otherwise, create a new fragment from our pasted text. Also
  111. // empty the internal clipboard, since it's no longer valid.
  112. editor.setClipboard(null);
  113. }
  114. if (textBlocks.length) {
  115. var character = CharacterMetadata.create({
  116. style: editorState.getCurrentInlineStyle(),
  117. entity: getEntityKeyForSelection(editorState.getCurrentContent(), editorState.getSelection())
  118. });
  119. var currentBlockType = RichTextEditorUtil.getCurrentBlockType(editorState);
  120. var textFragment = DraftPasteProcessor.processText(textBlocks, character, currentBlockType);
  121. var textMap = BlockMapBuilder.createFromArray(textFragment);
  122. editor.update(insertFragment(editor._latestEditorState, textMap));
  123. }
  124. }
  125. function insertFragment(editorState, fragment, entityMap) {
  126. var newContent = DraftModifier.replaceWithFragment(editorState.getCurrentContent(), editorState.getSelection(), fragment); // TODO: merge the entity map once we stop using DraftEntity
  127. // like this:
  128. // const mergedEntityMap = newContent.getEntityMap().merge(entityMap);
  129. return EditorState.push(editorState, newContent.set('entityMap', entityMap), 'insert-fragment');
  130. }
  131. function areTextBlocksAndClipboardEqual(textBlocks, blockMap) {
  132. return textBlocks.length === blockMap.size && blockMap.valueSeq().every(function (block, ii) {
  133. return block.getText() === textBlocks[ii];
  134. });
  135. }
  136. module.exports = editOnPaste;