UNPKG

@wordpress/block-editor

Version:
8 lines (7 loc) 12.3 kB
{ "version": 3, "sources": ["../../../src/components/writing-flow/use-clipboard-handler.js"], "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport {\n\tpasteHandler,\n\tfindTransform,\n\tgetBlockTransforms,\n\thasBlockSupport,\n\tswitchToBlockType,\n} from '@wordpress/blocks';\nimport {\n\tdocumentHasSelection,\n\tdocumentHasUncollapsedSelection,\n} from '@wordpress/dom';\nimport { useDispatch, useRegistry, useSelect } from '@wordpress/data';\nimport { useRefEffect } from '@wordpress/compose';\n\n/**\n * Internal dependencies\n */\nimport { store as blockEditorStore } from '../../store';\nimport { useNotifyCopy } from '../../utils/use-notify-copy';\nimport { setClipboardBlocks } from './utils';\nimport { getPasteEventData } from '../../utils/pasting';\n\nexport default function useClipboardHandler() {\n\tconst registry = useRegistry();\n\tconst {\n\t\tgetBlocksByClientId,\n\t\tgetSelectedBlockClientIds,\n\t\thasMultiSelection,\n\t\tgetSettings,\n\t\tgetBlockName,\n\t\t__unstableIsFullySelected,\n\t\t__unstableIsSelectionCollapsed,\n\t\t__unstableIsSelectionMergeable,\n\t\t__unstableGetSelectedBlocksWithPartialSelection,\n\t\tcanInsertBlockType,\n\t\tgetBlockRootClientId,\n\t} = useSelect( blockEditorStore );\n\tconst {\n\t\tflashBlock,\n\t\tremoveBlocks,\n\t\treplaceBlocks,\n\t\t__unstableDeleteSelection,\n\t\t__unstableExpandSelection,\n\t\t__unstableSplitSelection,\n\t} = useDispatch( blockEditorStore );\n\tconst notifyCopy = useNotifyCopy();\n\n\treturn useRefEffect( ( node ) => {\n\t\tfunction handler( event ) {\n\t\t\tif ( event.defaultPrevented ) {\n\t\t\t\t// This was likely already handled in rich-text/use-paste-handler.js.\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst selectedBlockClientIds = getSelectedBlockClientIds();\n\n\t\t\tif ( selectedBlockClientIds.length === 0 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Let native copy/paste behaviour take over in input fields.\n\t\t\t// But always handle multiple selected blocks.\n\t\t\tif ( ! hasMultiSelection() ) {\n\t\t\t\tconst { target } = event;\n\t\t\t\tconst { ownerDocument } = target;\n\t\t\t\t// If copying, only consider actual text selection as selection.\n\t\t\t\t// Otherwise, any focus on an input field is considered.\n\t\t\t\tconst hasSelection =\n\t\t\t\t\tevent.type === 'copy' || event.type === 'cut'\n\t\t\t\t\t\t? documentHasUncollapsedSelection( ownerDocument )\n\t\t\t\t\t\t: documentHasSelection( ownerDocument ) &&\n\t\t\t\t\t\t ! ownerDocument.activeElement.isContentEditable;\n\n\t\t\t\t// Let native copy behaviour take over in input fields.\n\t\t\t\tif ( hasSelection ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst { activeElement } = event.target.ownerDocument;\n\n\t\t\tif ( ! node.contains( activeElement ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst isSelectionMergeable = __unstableIsSelectionMergeable();\n\t\t\tconst shouldHandleWholeBlocks =\n\t\t\t\t__unstableIsSelectionCollapsed() || __unstableIsFullySelected();\n\t\t\tconst expandSelectionIsNeeded =\n\t\t\t\t! shouldHandleWholeBlocks && ! isSelectionMergeable;\n\t\t\tif ( event.type === 'copy' || event.type === 'cut' ) {\n\t\t\t\tevent.preventDefault();\n\n\t\t\t\tif ( selectedBlockClientIds.length === 1 ) {\n\t\t\t\t\tflashBlock( selectedBlockClientIds[ 0 ] );\n\t\t\t\t}\n\t\t\t\t// If we have a partial selection that is not mergeable, just\n\t\t\t\t// expand the selection to the whole blocks.\n\t\t\t\tif ( expandSelectionIsNeeded ) {\n\t\t\t\t\t__unstableExpandSelection();\n\t\t\t\t} else {\n\t\t\t\t\tnotifyCopy( event.type, selectedBlockClientIds );\n\t\t\t\t\tlet blocks;\n\t\t\t\t\t// Check if we have partial selection.\n\t\t\t\t\tif ( shouldHandleWholeBlocks ) {\n\t\t\t\t\t\tblocks = getBlocksByClientId( selectedBlockClientIds );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst [ head, tail ] =\n\t\t\t\t\t\t\t__unstableGetSelectedBlocksWithPartialSelection();\n\t\t\t\t\t\tconst inBetweenBlocks = getBlocksByClientId(\n\t\t\t\t\t\t\tselectedBlockClientIds.slice(\n\t\t\t\t\t\t\t\t1,\n\t\t\t\t\t\t\t\tselectedBlockClientIds.length - 1\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\t\t\t\t\t\tblocks = [ head, ...inBetweenBlocks, tail ];\n\t\t\t\t\t}\n\n\t\t\t\t\tsetClipboardBlocks( event, blocks, registry );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( event.type === 'cut' ) {\n\t\t\t\t// We need to also check if at the start we needed to\n\t\t\t\t// expand the selection, as in this point we might have\n\t\t\t\t// programmatically fully selected the blocks above.\n\t\t\t\tif ( shouldHandleWholeBlocks && ! expandSelectionIsNeeded ) {\n\t\t\t\t\tremoveBlocks( selectedBlockClientIds );\n\t\t\t\t} else {\n\t\t\t\t\tevent.target.ownerDocument.activeElement.contentEditable = false;\n\t\t\t\t\t__unstableDeleteSelection();\n\t\t\t\t}\n\t\t\t} else if ( event.type === 'paste' ) {\n\t\t\t\tconst {\n\t\t\t\t\t__experimentalCanUserUseUnfilteredHTML:\n\t\t\t\t\t\tcanUserUseUnfilteredHTML,\n\t\t\t\t\tmediaUpload,\n\t\t\t\t} = getSettings();\n\t\t\t\tconst isInternal =\n\t\t\t\t\tevent.clipboardData.getData( 'rich-text' ) === 'true';\n\t\t\t\tif ( isInternal ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst { plainText, html, files } = getPasteEventData( event );\n\t\t\t\tconst isFullySelected = __unstableIsFullySelected();\n\t\t\t\tlet blocks = [];\n\n\t\t\t\tif ( files.length ) {\n\t\t\t\t\tif ( ! mediaUpload ) {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst fromTransforms = getBlockTransforms( 'from' );\n\t\t\t\t\tblocks = files\n\t\t\t\t\t\t.reduce( ( accumulator, file ) => {\n\t\t\t\t\t\t\tconst transformation = findTransform(\n\t\t\t\t\t\t\t\tfromTransforms,\n\t\t\t\t\t\t\t\t( transform ) =>\n\t\t\t\t\t\t\t\t\ttransform.type === 'files' &&\n\t\t\t\t\t\t\t\t\ttransform.isMatch( [ file ] )\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tif ( transformation ) {\n\t\t\t\t\t\t\t\taccumulator.push(\n\t\t\t\t\t\t\t\t\ttransformation.transform( [ file ] )\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn accumulator;\n\t\t\t\t\t\t}, [] )\n\t\t\t\t\t\t.flat();\n\t\t\t\t} else {\n\t\t\t\t\tblocks = pasteHandler( {\n\t\t\t\t\t\tHTML: html,\n\t\t\t\t\t\tplainText,\n\t\t\t\t\t\tmode: isFullySelected ? 'BLOCKS' : 'AUTO',\n\t\t\t\t\t\tcanUserUseUnfilteredHTML,\n\t\t\t\t\t} );\n\t\t\t\t}\n\n\t\t\t\t// Inline paste: let rich text handle it.\n\t\t\t\tif ( typeof blocks === 'string' ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif ( isFullySelected ) {\n\t\t\t\t\treplaceBlocks(\n\t\t\t\t\t\tselectedBlockClientIds,\n\t\t\t\t\t\tblocks,\n\t\t\t\t\t\tblocks.length - 1,\n\t\t\t\t\t\t-1\n\t\t\t\t\t);\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// If a block doesn't support splitting, let rich text paste\n\t\t\t\t// inline.\n\t\t\t\tif (\n\t\t\t\t\t! hasMultiSelection() &&\n\t\t\t\t\t! hasBlockSupport(\n\t\t\t\t\t\tgetBlockName( selectedBlockClientIds[ 0 ] ),\n\t\t\t\t\t\t'splitting',\n\t\t\t\t\t\tfalse\n\t\t\t\t\t) &&\n\t\t\t\t\t! event.__deprecatedOnSplit\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst [ firstSelectedClientId ] = selectedBlockClientIds;\n\t\t\t\tconst rootClientId = getBlockRootClientId(\n\t\t\t\t\tfirstSelectedClientId\n\t\t\t\t);\n\n\t\t\t\tconst newBlocks = [];\n\n\t\t\t\tfor ( const block of blocks ) {\n\t\t\t\t\tif ( canInsertBlockType( block.name, rootClientId ) ) {\n\t\t\t\t\t\tnewBlocks.push( block );\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If a block cannot be inserted in a root block, try\n\t\t\t\t\t\t// converting it to that root block type and insert the\n\t\t\t\t\t\t// inner blocks.\n\t\t\t\t\t\t// Example: paragraphs cannot be inserted into a list,\n\t\t\t\t\t\t// so convert the paragraphs to a list for list items.\n\t\t\t\t\t\tconst rootBlockName = getBlockName( rootClientId );\n\t\t\t\t\t\tconst switchedBlocks =\n\t\t\t\t\t\t\tblock.name !== rootBlockName\n\t\t\t\t\t\t\t\t? switchToBlockType( block, rootBlockName )\n\t\t\t\t\t\t\t\t: [ block ];\n\n\t\t\t\t\t\tif ( ! switchedBlocks ) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tfor ( const switchedBlock of switchedBlocks ) {\n\t\t\t\t\t\t\tfor ( const innerBlock of switchedBlock.innerBlocks ) {\n\t\t\t\t\t\t\t\tnewBlocks.push( innerBlock );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t__unstableSplitSelection( newBlocks );\n\t\t\t\tevent.preventDefault();\n\t\t\t}\n\t\t}\n\n\t\tnode.ownerDocument.addEventListener( 'copy', handler );\n\t\tnode.ownerDocument.addEventListener( 'cut', handler );\n\t\tnode.ownerDocument.addEventListener( 'paste', handler );\n\n\t\treturn () => {\n\t\t\tnode.ownerDocument.removeEventListener( 'copy', handler );\n\t\t\tnode.ownerDocument.removeEventListener( 'cut', handler );\n\t\t\tnode.ownerDocument.removeEventListener( 'paste', handler );\n\t\t};\n\t}, [] );\n}\n"], "mappings": "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", "names": [] }