@wordpress/block-editor
Version:
196 lines (195 loc) • 6.79 kB
JavaScript
// packages/block-editor/src/components/writing-flow/use-clipboard-handler.js
import {
pasteHandler,
findTransform,
getBlockTransforms,
hasBlockSupport,
switchToBlockType
} from "@wordpress/blocks";
import {
documentHasSelection,
documentHasUncollapsedSelection
} from "@wordpress/dom";
import { useDispatch, useRegistry, useSelect } from "@wordpress/data";
import { useRefEffect } from "@wordpress/compose";
import { store as blockEditorStore } from "../../store";
import { useNotifyCopy } from "../../utils/use-notify-copy";
import { setClipboardBlocks } from "./utils";
import { getPasteEventData } from "../../utils/pasting";
function useClipboardHandler() {
const registry = useRegistry();
const {
getBlocksByClientId,
getSelectedBlockClientIds,
hasMultiSelection,
getSettings,
getBlockName,
__unstableIsFullySelected,
__unstableIsSelectionCollapsed,
__unstableIsSelectionMergeable,
__unstableGetSelectedBlocksWithPartialSelection,
canInsertBlockType,
getBlockRootClientId
} = useSelect(blockEditorStore);
const {
flashBlock,
removeBlocks,
replaceBlocks,
__unstableDeleteSelection,
__unstableExpandSelection,
__unstableSplitSelection
} = useDispatch(blockEditorStore);
const notifyCopy = useNotifyCopy();
return useRefEffect((node) => {
function handler(event) {
if (event.defaultPrevented) {
return;
}
const selectedBlockClientIds = getSelectedBlockClientIds();
if (selectedBlockClientIds.length === 0) {
return;
}
if (!hasMultiSelection()) {
const { target } = event;
const { ownerDocument } = target;
const hasSelection = event.type === "copy" || event.type === "cut" ? documentHasUncollapsedSelection(ownerDocument) : documentHasSelection(ownerDocument) && !ownerDocument.activeElement.isContentEditable;
if (hasSelection) {
return;
}
}
const { activeElement } = event.target.ownerDocument;
if (!node.contains(activeElement)) {
return;
}
const isSelectionMergeable = __unstableIsSelectionMergeable();
const shouldHandleWholeBlocks = __unstableIsSelectionCollapsed() || __unstableIsFullySelected();
const expandSelectionIsNeeded = !shouldHandleWholeBlocks && !isSelectionMergeable;
if (event.type === "copy" || event.type === "cut") {
event.preventDefault();
if (selectedBlockClientIds.length === 1) {
flashBlock(selectedBlockClientIds[0]);
}
if (expandSelectionIsNeeded) {
__unstableExpandSelection();
} else {
notifyCopy(event.type, selectedBlockClientIds);
let blocks;
if (shouldHandleWholeBlocks) {
blocks = getBlocksByClientId(selectedBlockClientIds);
} else {
const [head, tail] = __unstableGetSelectedBlocksWithPartialSelection();
const inBetweenBlocks = getBlocksByClientId(
selectedBlockClientIds.slice(
1,
selectedBlockClientIds.length - 1
)
);
blocks = [head, ...inBetweenBlocks, tail];
}
setClipboardBlocks(event, blocks, registry);
}
}
if (event.type === "cut") {
if (shouldHandleWholeBlocks && !expandSelectionIsNeeded) {
removeBlocks(selectedBlockClientIds);
} else {
event.target.ownerDocument.activeElement.contentEditable = false;
__unstableDeleteSelection();
}
} else if (event.type === "paste") {
const {
__experimentalCanUserUseUnfilteredHTML: canUserUseUnfilteredHTML,
mediaUpload
} = getSettings();
const isInternal = event.clipboardData.getData("rich-text") === "true";
if (isInternal) {
return;
}
const { plainText, html, files } = getPasteEventData(event);
const isFullySelected = __unstableIsFullySelected();
let blocks = [];
if (files.length) {
if (!mediaUpload) {
event.preventDefault();
return;
}
const fromTransforms = getBlockTransforms("from");
blocks = files.reduce((accumulator, file) => {
const transformation = findTransform(
fromTransforms,
(transform) => transform.type === "files" && transform.isMatch([file])
);
if (transformation) {
accumulator.push(
transformation.transform([file])
);
}
return accumulator;
}, []).flat();
} else {
blocks = pasteHandler({
HTML: html,
plainText,
mode: isFullySelected ? "BLOCKS" : "AUTO",
canUserUseUnfilteredHTML
});
}
if (typeof blocks === "string") {
return;
}
if (isFullySelected) {
replaceBlocks(
selectedBlockClientIds,
blocks,
blocks.length - 1,
-1
);
event.preventDefault();
return;
}
if (!hasMultiSelection() && !hasBlockSupport(
getBlockName(selectedBlockClientIds[0]),
"splitting",
false
) && !event.__deprecatedOnSplit) {
return;
}
const [firstSelectedClientId] = selectedBlockClientIds;
const rootClientId = getBlockRootClientId(
firstSelectedClientId
);
const newBlocks = [];
for (const block of blocks) {
if (canInsertBlockType(block.name, rootClientId)) {
newBlocks.push(block);
} else {
const rootBlockName = getBlockName(rootClientId);
const switchedBlocks = block.name !== rootBlockName ? switchToBlockType(block, rootBlockName) : [block];
if (!switchedBlocks) {
return;
}
for (const switchedBlock of switchedBlocks) {
for (const innerBlock of switchedBlock.innerBlocks) {
newBlocks.push(innerBlock);
}
}
}
}
__unstableSplitSelection(newBlocks);
event.preventDefault();
}
}
node.ownerDocument.addEventListener("copy", handler);
node.ownerDocument.addEventListener("cut", handler);
node.ownerDocument.addEventListener("paste", handler);
return () => {
node.ownerDocument.removeEventListener("copy", handler);
node.ownerDocument.removeEventListener("cut", handler);
node.ownerDocument.removeEventListener("paste", handler);
};
}, []);
}
export {
useClipboardHandler as default
};
//# sourceMappingURL=use-clipboard-handler.js.map