{"version":3,"file":"index.js","sources":["../../src/components/Editor/RichTextEditor/index.tsx"],"sourcesContent":["import React from \"react\";\r\nimport PropTypes from \"prop-types\";\r\nimport { Editor, EditorState, DraftEditorCommand, RichUtils, Modifier, ContentState, convertToRaw, ContentBlock, CompositeDecorator, Entity, SelectionState, AtomicBlockUtils } from \"draft-js\";\r\nimport styles from \"./RichTextEditor.less\";\r\n\r\ninterface RichTextEditorProps {}\r\ninterface RichTextEditorState {\r\n editorState: EditorState;\r\n}\r\n\r\n// 自定义组件,用于超链接\r\nconst Link = (props: any) => {\r\n // 这里通过contentState来获取entity�,之后通过getData获取entity中包含的数据\r\n const { url } = props.contentState.getEntity(props.entityKey).getData();\r\n return (\r\n \r\n {props.children}\r\n \r\n )\r\n}\r\n// decorator,用于超链接\r\nconst decorator = new CompositeDecorator([\r\n {\r\n strategy (contentBlock, callback, contentState) {\r\n\r\n // 这个方法接收2个函数作为参数,如果第一个参数的函数执行时�返回true,就会执行第二个参数函数,同时会�将匹配的�字符的起始位置和结束位置传递给第二个参数。\r\n contentBlock.findEntityRanges(\r\n (character) => {\r\n const entityKey = character.getEntity();\r\n return (\r\n entityKey !== null &&\r\n contentState.getEntity(entityKey).getType() === 'LINK'\r\n );\r\n }, (...arr) => {\r\n callback(...arr)\r\n }\r\n );\r\n },\r\n component: Link\r\n },\r\n {\r\n strategy (contentBlock, callback, contentState) {\r\n contentBlock.findEntityRanges(\r\n (character) => {\r\n const entityKey = character.getEntity();\r\n return (\r\n entityKey !== null &&\r\n contentState.getEntity(entityKey).getType() === 'EMOJI'\r\n );\r\n }, (...arr) => {\r\n callback(...arr);\r\n }\r\n )\r\n },\r\n // component: (props: any) => ([Emoji])\r\n component: (props: any) => (\r\n {`e`})\r\n }\r\n]);\r\n\r\nclass RichTextEditor extends React.Component<\r\n RichTextEditorProps,\r\n RichTextEditorState\r\n> {\r\n constructor(props: RichTextEditorProps) {\r\n super(props);\r\n this.state = {\r\n editorState: EditorState.createEmpty(decorator)\r\n };\r\n this.onChange = (editorState: EditorState) =>\r\n this.setState({ editorState });\r\n this.handleKeyCommand = this.handleKeyCommand.bind(this);\r\n this.defaultBlockStyleFn = this.defaultBlockStyleFn.bind(this);\r\n }\r\n\r\n onChange: (editorState: EditorState) => void;\r\n handleKeyCommand(command: DraftEditorCommand, editorState: EditorState) {\r\n const newState = RichUtils.handleKeyCommand(editorState, command);\r\n console.log('command: ', command);\r\n console.log('newState: ', newState);\r\n if (newState) {\r\n this.onChange(newState);\r\n return \"handled\";\r\n }\r\n\r\n switch (command) {\r\n case 'backspace': \r\n const contentState = editorState.getCurrentContent();\r\n const selectionState = editorState.getSelection();\r\n const [startOffset, endOffset] = [selectionState.getStartOffset(), selectionState.getEndOffset()];\r\n if (startOffset === endOffset) {\r\n // 未选中状态\r\n console.log(selectionState.getAnchorKey());\r\n }\r\n // 选中状态\r\n\r\n break;\r\n case 'backspace-word': \r\n case 'backspace-to-start-of-line':\r\n break;\r\n }\r\n \r\n return \"not-handled\";\r\n }\r\n\r\n _onBoldClick() {\r\n this.onChange(RichUtils.toggleInlineStyle(this.state.editorState, 'BOLD'));\r\n }\r\n\r\n _onLinkClick() {\r\n const { editorState } = this.state;\r\n const contentState = editorState.getCurrentContent();\r\n const selectionState = editorState.getSelection();\r\n const contentStateWithEntity = contentState.createEntity('LINK', 'MUTABLE', {\r\n url: 'http://www.zombo.com',\r\n });\r\n const entityKey = contentStateWithEntity.getLastCreatedEntityKey();\r\n const contentStateWithLink = Modifier.applyEntity(\r\n contentStateWithEntity,\r\n selectionState,\r\n entityKey,\r\n );\r\n const newEditorState = EditorState.push(editorState, contentStateWithLink, 'apply-entity');\r\n this.onChange(newEditorState);\r\n }\r\n\r\n _onEmojiClick(e: React.MouseEvent, emojiCode: string) {\r\n const { editorState } = this.state;\r\n const contentState = editorState.getCurrentContent();\r\n const selectionState = editorState.getSelection();\r\n const EMOJIEntity: ContentState = contentState.createEntity('EMOJI', 'IMMUTABLE', { emojiCode });\r\n const entityKey = EMOJIEntity.getLastCreatedEntityKey();\r\n const ncsWithEntity = Modifier.insertText(contentState, selectionState, 'e', undefined, entityKey);\r\n const newEditorState = EditorState.push(editorState, ncsWithEntity, 'insert-characters');\r\n // const newEditorState = AtomicBlockUtils.insertAtomicBlock(\r\n // editorState,\r\n // entityKey,\r\n // ' '\r\n // );\r\n this.onChange(newEditorState);\r\n }\r\n\r\n _onCheckRange() {\r\n console.log(this.state.editorState.getCurrentContent());\r\n console.log(convertToRaw(this.state.editorState.getCurrentContent()));\r\n }\r\n\r\n defaultBlockStyleFn(contentBlock: ContentBlock) {\r\n const type = contentBlock.getType();\r\n return \"\";\r\n }\r\n\r\n defaultBlockRenderFn(contentBlock: ContentBlock) {\r\n const type = contentBlock.getType();\r\n return contentBlock;\r\n }\r\n\r\n render() {\r\n const { editorState } = this.state;\r\n return (\r\n