UNPKG

@wordpress/block-editor

Version:
8 lines (7 loc) 9.44 kB
{ "version": 3, "sources": ["../../../src/components/list-view/use-clipboard-handler.js"], "sourcesContent": ["/**\n * WordPress dependencies\n */\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 { focusListItem } from './utils';\nimport { getPasteBlocks, setClipboardBlocks } from '../writing-flow/utils';\n\n// This hook borrows from useClipboardHandler in ../writing-flow/use-clipboard-handler.js\n// and adds behaviour for the list view, while skipping partial selection.\nexport default function useClipboardHandler( { selectBlock } ) {\n\tconst registry = useRegistry();\n\tconst {\n\t\tgetBlockOrder,\n\t\tgetBlockRootClientId,\n\t\tgetBlocksByClientId,\n\t\tgetPreviousBlockClientId,\n\t\tgetSelectedBlockClientIds,\n\t\tgetSettings,\n\t\tcanInsertBlockType,\n\t\tcanRemoveBlocks,\n\t} = useSelect( blockEditorStore );\n\tconst { flashBlock, removeBlocks, replaceBlocks, insertBlocks } =\n\t\tuseDispatch( blockEditorStore );\n\tconst notifyCopy = useNotifyCopy();\n\n\treturn useRefEffect( ( node ) => {\n\t\tfunction updateFocusAndSelection( focusClientId, shouldSelectBlock ) {\n\t\t\tif ( shouldSelectBlock ) {\n\t\t\t\tselectBlock( undefined, focusClientId, null, null );\n\t\t\t}\n\n\t\t\tfocusListItem( focusClientId, node );\n\t\t}\n\n\t\t// Determine which blocks to update:\n\t\t// If the current (focused) block is part of the block selection, use the whole selection.\n\t\t// If the focused block is not part of the block selection, only update the focused block.\n\t\tfunction getBlocksToUpdate( clientId ) {\n\t\t\tconst selectedBlockClientIds = getSelectedBlockClientIds();\n\t\t\tconst isUpdatingSelectedBlocks =\n\t\t\t\tselectedBlockClientIds.includes( clientId );\n\t\t\tconst firstBlockClientId = isUpdatingSelectedBlocks\n\t\t\t\t? selectedBlockClientIds[ 0 ]\n\t\t\t\t: clientId;\n\t\t\tconst firstBlockRootClientId =\n\t\t\t\tgetBlockRootClientId( firstBlockClientId );\n\n\t\t\tconst blocksToUpdate = isUpdatingSelectedBlocks\n\t\t\t\t? selectedBlockClientIds\n\t\t\t\t: [ clientId ];\n\n\t\t\treturn {\n\t\t\t\tblocksToUpdate,\n\t\t\t\tfirstBlockClientId,\n\t\t\t\tfirstBlockRootClientId,\n\t\t\t\toriginallySelectedBlockClientIds: selectedBlockClientIds,\n\t\t\t};\n\t\t}\n\n\t\tfunction handler( event ) {\n\t\t\tif ( event.defaultPrevented ) {\n\t\t\t\t// This was possibly already handled in rich-text/use-paste-handler.js.\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Only handle events that occur within the list view.\n\t\t\tif ( ! node.contains( event.target.ownerDocument.activeElement ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Retrieve the block clientId associated with the focused list view row.\n\t\t\t// This enables applying copy / cut / paste behavior to the focused block,\n\t\t\t// rather than just the blocks that are currently selected.\n\t\t\tconst listViewRow =\n\t\t\t\tevent.target.ownerDocument.activeElement?.closest(\n\t\t\t\t\t'[role=row]'\n\t\t\t\t);\n\t\t\tconst clientId = listViewRow?.dataset?.block;\n\t\t\tif ( ! clientId ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst {\n\t\t\t\tblocksToUpdate: selectedBlockClientIds,\n\t\t\t\tfirstBlockClientId,\n\t\t\t\tfirstBlockRootClientId,\n\t\t\t\toriginallySelectedBlockClientIds,\n\t\t\t} = getBlocksToUpdate( clientId );\n\n\t\t\tif ( selectedBlockClientIds.length === 0 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tevent.preventDefault();\n\n\t\t\tif ( event.type === 'copy' || event.type === 'cut' ) {\n\t\t\t\tif ( selectedBlockClientIds.length === 1 ) {\n\t\t\t\t\tflashBlock( selectedBlockClientIds[ 0 ] );\n\t\t\t\t}\n\n\t\t\t\tnotifyCopy( event.type, selectedBlockClientIds );\n\t\t\t\tconst blocks = getBlocksByClientId( selectedBlockClientIds );\n\t\t\t\tsetClipboardBlocks( event, blocks, registry );\n\t\t\t}\n\n\t\t\tif ( event.type === 'cut' ) {\n\t\t\t\t// Don't update the selection if the blocks cannot be deleted.\n\t\t\t\tif ( ! canRemoveBlocks( selectedBlockClientIds ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet blockToFocus =\n\t\t\t\t\tgetPreviousBlockClientId( firstBlockClientId ) ??\n\t\t\t\t\t// If the previous block is not found (when the first block is deleted),\n\t\t\t\t\t// fallback to focus the parent block.\n\t\t\t\t\tfirstBlockRootClientId;\n\n\t\t\t\t// Remove blocks, but don't update selection, and it will be handled below.\n\t\t\t\tremoveBlocks( selectedBlockClientIds, false );\n\n\t\t\t\t// Update the selection if the original selection has been removed.\n\t\t\t\tconst shouldUpdateSelection =\n\t\t\t\t\toriginallySelectedBlockClientIds.length > 0 &&\n\t\t\t\t\tgetSelectedBlockClientIds().length === 0;\n\n\t\t\t\t// If there's no previous block nor parent block, focus the first block.\n\t\t\t\tif ( ! blockToFocus ) {\n\t\t\t\t\tblockToFocus = getBlockOrder()[ 0 ];\n\t\t\t\t}\n\n\t\t\t\tupdateFocusAndSelection( blockToFocus, shouldUpdateSelection );\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} = getSettings();\n\t\t\t\tconst blocks = getPasteBlocks(\n\t\t\t\t\tevent,\n\t\t\t\t\tcanUserUseUnfilteredHTML\n\t\t\t\t);\n\n\t\t\t\tif ( selectedBlockClientIds.length === 1 ) {\n\t\t\t\t\tconst [ selectedBlockClientId ] = selectedBlockClientIds;\n\n\t\t\t\t\t// If a single block is focused, and the blocks to be posted can\n\t\t\t\t\t// be inserted within the block, then append the pasted blocks\n\t\t\t\t\t// within the focused block. For example, if you have copied a paragraph\n\t\t\t\t\t// block and paste it within a single Group block, this will append\n\t\t\t\t\t// the paragraph block within the Group block.\n\t\t\t\t\tif (\n\t\t\t\t\t\tblocks.every( ( block ) =>\n\t\t\t\t\t\t\tcanInsertBlockType(\n\t\t\t\t\t\t\t\tblock.name,\n\t\t\t\t\t\t\t\tselectedBlockClientId\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\t\tinsertBlocks(\n\t\t\t\t\t\t\tblocks,\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\tselectedBlockClientId\n\t\t\t\t\t\t);\n\t\t\t\t\t\tupdateFocusAndSelection( blocks[ 0 ]?.clientId, false );\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treplaceBlocks(\n\t\t\t\t\tselectedBlockClientIds,\n\t\t\t\t\tblocks,\n\t\t\t\t\tblocks.length - 1,\n\t\t\t\t\t-1\n\t\t\t\t);\n\t\t\t\tupdateFocusAndSelection( blocks[ 0 ]?.clientId, false );\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": ["import_utils", "blockEditorStore"] }