-
Notifications
You must be signed in to change notification settings - Fork 86
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use editor3 internal clipboard to copy entities from open editors #2509
Changes from 6 commits
8eb3cdb
8bbb853
74efd48
b1407ca
d3ecbc1
ab0ed09
50f25d3
733b6eb
9561daa
0a13240
a37dfa7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
patch-package | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need this file? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ioanpocol I added a new dependency: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
--- a/node_modules/@types/draft-js/index.d.ts | ||
+++ b/node_modules/@types/draft-js/index.d.ts | ||
@@ -950,6 +950,7 @@ import Editor = Draft.Component.Base.DraftEditor; | ||
import EditorProps = Draft.Component.Base.DraftEditorProps; | ||
import EditorBlock = Draft.Component.Components.DraftEditorBlock; | ||
import EditorState = Draft.Model.ImmutableData.EditorState; | ||
+import EditorChangeType = Draft.Model.ImmutableData.EditorChangeType; | ||
|
||
import CompositeDecorator = Draft.Model.Decorators.CompositeDraftDecorator; | ||
import Entity = Draft.Model.Entity.DraftEntity; | ||
@@ -999,6 +1000,7 @@ export { | ||
EditorProps, | ||
EditorBlock, | ||
EditorState, | ||
+ EditorChangeType, | ||
|
||
CompositeDecorator, | ||
Entity, |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,14 @@ | ||
import {EditorState, ContentState, Modifier, genKey, CharacterMetadata, ContentBlock} from 'draft-js'; | ||
import {List, OrderedSet} from 'immutable'; | ||
import {EditorState, ContentState, Modifier, genKey, CharacterMetadata, ContentBlock, DraftHandleValue, EditorChangeType} from 'draft-js'; | ||
import {EDITOR_GLOBAL_REFS, Editor3ComponentProps} from 'core/editor3/components/Editor3Component'; | ||
import {List, OrderedMap} from 'immutable'; | ||
import {getContentStateFromHtml} from '../html/from-html'; | ||
import * as Suggestions from '../helpers/suggestions'; | ||
import {sanitizeContent, inlineStyles} from '../helpers/inlineStyles'; | ||
import {getAllCustomDataFromEditor, setAllCustomDataForEditor} from '../helpers/editor3CustomData'; | ||
import {getCurrentAuthor} from '../helpers/author'; | ||
import {htmlComesFromDraftjsEditor} from '../helpers/htmlComesFromDraftjsEditor'; | ||
|
||
function removeMediaFromHtml(htmlString) { | ||
function removeMediaFromHtml(htmlString) : string { | ||
const element = document.createElement('div'); | ||
|
||
element.innerHTML = htmlString; | ||
|
@@ -19,8 +20,26 @@ function removeMediaFromHtml(htmlString) { | |
return element.innerHTML; | ||
} | ||
|
||
const HANDLED = 'handled'; | ||
const NOT_HANDLED = 'not-handled'; | ||
function pasteContentFromOpenEditor( | ||
html: string, editorState: EditorState, onChange: Function, editorFormat: Array<string>) : DraftHandleValue { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's alright for now, but try avoiding the use of
and then access
|
||
for (const editorKey in window[EDITOR_GLOBAL_REFS]) { | ||
if (html.includes(editorKey)) { | ||
const editor = window[EDITOR_GLOBAL_REFS][editorKey]; | ||
const internalClipboard = editor.getClipboard(); | ||
|
||
if (internalClipboard) { | ||
const blocksArray = []; | ||
|
||
internalClipboard.forEach((b) => blocksArray.push(b)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why aren't you passing |
||
const contentState = ContentState.createFromBlockArray(blocksArray); | ||
|
||
return insertContentInState(editorState, contentState, onChange, editorFormat); | ||
} | ||
} | ||
} | ||
|
||
return 'not-handled'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's wrong with |
||
} | ||
|
||
/** | ||
* @ngdoc method | ||
|
@@ -31,46 +50,51 @@ const NOT_HANDLED = 'not-handled'; | |
* @description Handles pasting into the editor, in cases where the content contains | ||
* atomic blocks that need special handling in editor3. | ||
*/ | ||
export function handlePastedText(text, _html) { | ||
export function handlePastedText(text: string, _html: string) : DraftHandleValue { | ||
const author = getCurrentAuthor(); | ||
let html = _html; | ||
|
||
if (typeof html === 'string') { | ||
html = removeMediaFromHtml(html); | ||
} | ||
|
||
const {editorState, suggestingMode, onPasteFromSuggestingMode} = this.props; | ||
const {editorState, suggestingMode, onPasteFromSuggestingMode, onChange, editorFormat} = this.props; | ||
|
||
if (!html && !text) { | ||
return HANDLED; | ||
return 'handled'; | ||
} | ||
|
||
if (suggestingMode) { | ||
if (!Suggestions.allowEditSuggestionOnLeft(editorState, author) | ||
&& !Suggestions.allowEditSuggestionOnRight(editorState, author)) { | ||
return HANDLED; | ||
return 'handled'; | ||
} | ||
|
||
const content = html ? getContentStateFromHtml(html) : ContentState.createFromText(text); | ||
|
||
onPasteFromSuggestingMode(content); | ||
return HANDLED; | ||
return 'handled'; | ||
} | ||
|
||
if (pasteContentFromOpenEditor(html, editorState, onChange, editorFormat) === 'handled') { | ||
return 'handled'; | ||
} | ||
|
||
|
||
if (htmlComesFromDraftjsEditor(html)) { | ||
return NOT_HANDLED; | ||
return 'not-handled'; | ||
} | ||
|
||
return processPastedHtml(this.props, html || text); | ||
} | ||
|
||
// Checks if there are atomic blocks in the paste content. If there are, we need to set | ||
// the 'atomic' block type using the Modifier tool and add these entities to the | ||
// contentState. | ||
function processPastedHtml(props, html) { | ||
const {onChange, editorState, editorFormat} = props; | ||
let pastedContent = getContentStateFromHtml(html); | ||
const blockMap = pastedContent.getBlockMap(); | ||
function insertContentInState( | ||
editorState: EditorState, | ||
pastedContent: ContentState, | ||
onChange: Function, | ||
editorFormat: Array<string>) : DraftHandleValue { | ||
let _pastedContent = pastedContent; | ||
const blockMap = _pastedContent.getBlockMap(); | ||
const hasAtomicBlocks = blockMap.some((block) => block.getType() === 'atomic'); | ||
const acceptedInlineStyles = | ||
Object.keys(inlineStyles) | ||
|
@@ -86,7 +110,7 @@ function processPastedHtml(props, html) { | |
selection = contentState.getSelectionAfter(); | ||
} | ||
|
||
pastedContent = sanitizeContent(EditorState.createWithContent(pastedContent), acceptedInlineStyles) | ||
_pastedContent = sanitizeContent(EditorState.createWithContent(_pastedContent), acceptedInlineStyles) | ||
.getCurrentContent(); | ||
|
||
blockMap.forEach((block) => { | ||
|
@@ -95,7 +119,7 @@ function processPastedHtml(props, html) { | |
} | ||
|
||
const entityKey = block.getEntityAt(0); | ||
const entity = pastedContent.getEntity(entityKey); | ||
const entity = _pastedContent.getEntity(entityKey); | ||
|
||
contentState = contentState.addEntity(entity); | ||
|
||
|
@@ -109,9 +133,11 @@ function processPastedHtml(props, html) { | |
contentState = Modifier.setBlockType(contentState, selection, 'atomic'); | ||
} | ||
|
||
const newBlockMap = OrderedMap<string, ContentBlock>(blocks.map((b) => ([b.getKey(), b]))); | ||
|
||
let nextEditorState = EditorState.push( | ||
editorState, | ||
Modifier.replaceWithFragment(contentState, selection, OrderedSet(blocks)), | ||
Modifier.replaceWithFragment(contentState, selection, newBlockMap), | ||
'insert-fragment' | ||
); | ||
|
||
|
@@ -133,7 +159,21 @@ function processPastedHtml(props, html) { | |
|
||
onChange(nextEditorState); | ||
|
||
return HANDLED; | ||
return 'handled'; | ||
} | ||
|
||
// Checks if there are atomic blocks in the paste content. If there are, we need to set | ||
// the 'atomic' block type using the Modifier tool and add these entities to the | ||
// contentState. | ||
function processPastedHtml(props: Editor3ComponentProps, html: string) : DraftHandleValue { | ||
let pastedContent = getContentStateFromHtml(html); | ||
|
||
return insertContentInState( | ||
props.editorState, | ||
pastedContent, | ||
props.onChange, | ||
props.editorFormat | ||
); | ||
} | ||
|
||
// Returns an empty block. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ import {getDraftSelectionForEntireContent} from './getDraftSelectionForEntireCon | |
import {resizeDraftSelection} from './resizeDraftSelection'; | ||
import {clearInlineStyles} from './clearInlineStyles'; | ||
import {changeSuggestionsTypes, blockStylesDescription, paragraphSuggestionTypes} from '../highlightsConfig'; | ||
import _ from 'lodash'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
export const paragraphSeparator = '¶'; | ||
|
||
|
@@ -266,7 +267,8 @@ export function canAddHighlight(editorState, highlightType) { | |
* @param {Boolean} firstFound - if true return first style found otherwise return all styles found | ||
* @description the highlight style from the new possition specified by offset. | ||
*/ | ||
export function getHighlightStyleAtOffset(editorState, types, selection, offset, fromEnd = false, firstFound = true) { | ||
export function getHighlightStyleAtOffset( | ||
editorState, types, selection, offset, fromEnd = false, firstFound = true) : string | Array<string> { | ||
const {block, newOffset} = getBlockAndOffset(editorState, selection, offset, fromEnd); | ||
|
||
if (block == null) { | ||
|
@@ -354,7 +356,7 @@ export function getHighlightAuthor(editorState, style) { | |
* @description the highlight associated data from the new possition specified by offset. | ||
*/ | ||
export function getHighlightDataAtOffset(editorState, types, selection, offset, fromEnd = false) { | ||
const style = getHighlightStyleAtOffset(editorState, types, selection, offset, fromEnd); | ||
const style = getHighlightStyleAtOffset(editorState, types, selection, offset, fromEnd) as string; | ||
|
||
if (style == null) { | ||
return null; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might not cause any issues, but I'd lock the version.