import { EditorState , Entity , Modifier , RichUtils , SelectionState , CompositeDecorator , } from 'draft-js' ; import Link from './LinkControls/Link' ; import linkStrategy from './LinkControls/linkStrategy' ; import getSelectionEntities from './getSelectionEntities' ; export const getEntitySelectionState = ( editorState , selectionState , entityType ) => { const currentContent = editorState . getCurrentContent ( ) ; const endOffset = selectionState . getEndOffset ( ) ; const block = currentContent . getBlockForKey ( selectionState . getStartKey ( ) ) ; let entitySelectionState ; block . findEntityRanges ( ( character ) => { const entityKey = character . getEntity ( ) ; return entityKey && Entity . get ( entityKey ) . getType ( ) === entityType ; } , ( start , end ) => { const isSelected = end >= endOffset && start <= endOffset ; if ( isSelected ) { entitySelectionState = selectionState . merge ( { anchorOffset : start , focusOffset : end , } ) ; } } ) ; return entitySelectionState ; } ; export const getSelectedBlocks = ( contentState , selectionState ) => { const anchorKey = selectionState . getStartKey ( ) ; const focusKey = selectionState . getEndKey ( ) ; const isSameBlock = anchorKey === focusKey ; const startingBlock = contentState . getBlockForKey ( anchorKey ) ; if ( ! startingBlock ) { return [ ] ; } let selectedBlocks = [ startingBlock ] ; if ( ! isSameBlock ) { let blockKey = anchorKey ; while ( blockKey !== focusKey ) { const nextBlock = contentState . getBlockAfter ( blockKey ) ; if ( ! nextBlock ) { selectedBlocks = [ ] ; break ; } selectedBlocks = [ ... selectedBlocks , nextBlock ] ; blockKey = nextBlock . getKey ( ) ; } } return selectedBlocks ; } ; export const getBlockSelectionState = ( contentBlock , selectionState ) => { const anchorKey = selectionState . getStartKey ( ) ; const focusKey = selectionState . getEndKey ( ) ; const blockKey = contentBlock . getKey ( ) ; const startOffset = blockKey === anchorKey ? selectionState . getStartOffset ( ) : 0 ; const endOffset = blockKey === focusKey ? selectionState . getEndOffset ( ) : contentBlock . getText ( ) . length ; return SelectionState . createEmpty ( blockKey ) . merge ( { anchorOffset : startOffset , focusOffset : endOffset , } ) ; } ; export default { toggleInlineStyle : ( editorState , inlineStyle ) => { if ( inlineStyle . indexOf ( ':' ) > 0 ) { let contentWithoutStyle = editorState . getCurrentContent ( ) ; const prefix = inlineStyle . split ( ':' ) [ 0 ] ; const styles = editorState . getCurrentInlineStyle ( ) . filter ( ( style ) => style . startsWith ( prefix ) ) ; if ( styles . size > 0 ) { styles . forEach ( ( style ) => { contentWithoutStyle = Modifier . removeInlineStyle ( contentWithoutStyle , editorState . getSelection ( ) , style ) ; } ) ; return RichUtils . toggleInlineStyle ( EditorState . push ( editorState , contentWithoutStyle , 'change-inline-style' ) , inlineStyle ) ; } } return RichUtils . toggleInlineStyle ( editorState , inlineStyle ) ; } , toggleLink : ( editorState , data ) => { let editorStateMutable = editorState ; const selection = editorState . getSelection ( ) ; if ( ! selection . isCollapsed ( ) ) { const contentState = editorState . getCurrentContent ( ) ; const arrayBlocks = getSelectedBlocks ( contentState , selection ) ; arrayBlocks . forEach ( block => { const entity = block . getEntityAt ( 0 ) ; if ( entity ) { if ( block . getType ( ) === 'atomic' ) { if ( ! data ) { Entity . mergeData ( entity , { href : null } ) ; } else { Entity . mergeData ( entity , data ) ; } } } } ) ; return editorStateMutable ; } else { const selectionEntity = getSelectionEntities ( editorState , 'LINK' ) . last ( ) ; if ( selectionEntity ) { Entity . mergeData ( ( selectionEntity as any ) . entityKey , data ) ; } return editorState ; } } , getEntityInstance : ( editorState , selectionState , entityType ) => { const entitySelectionState = getEntitySelectionState ( editorState , selectionState , entityType ) ; if ( entitySelectionState ) { const block = editorState . getCurrentContent ( ) . getBlockForKey ( entitySelectionState . getStartKey ( ) ) ; const entityKey = block . getEntityAt ( entitySelectionState . getStartOffset ( ) ) ; return entityKey ? Entity . get ( entityKey ) : undefined ; } return false ; } , customColor : ( style ) => { let output = { } ; const color = style . filter ( ( value ) => value . startsWith ( 'color' ) ) . last ( ) ; if ( color ) { output = { ... output , color : color . replace ( 'color:' , '' ) . replace ( ';' , '' ) . trim ( ) , } ; } return output ; } , customSizeAndFamily : ( style ) => { let output = { } ; const fontSize = style . filter ( ( value ) => value . startsWith ( 'font-size' ) ) . last ( ) ; if ( fontSize ) { const value = fontSize . replace ( 'font-size:' , '' ) . replace ( 'px' , '' ) . replace ( ';' , '' ) . trim ( ) ; output = { ... output , fontSize : Number ( value ) , } ; } const fontFamily = style . filter ( ( value ) => value . startsWith ( 'font-family' ) ) . last ( ) ; if ( fontFamily ) { output = { ... output , fontFamily : fontFamily . replace ( 'font-family:' , '' ) . replace ( ';' , '' ) . trim ( ) , } ; } return output ; } , blockRendererFn : ( block , Media ) => { if ( block . getType ( ) === 'atomic' ) { return { component : Media , } ; } return false ; } , decorator : new CompositeDecorator ( [ { strategy : linkStrategy , component : Link } , ] ) , } ;