fix: can not copy from white board and paste in editor

This commit is contained in:
QiShaoXuan 2022-08-17 23:28:18 +08:00
parent 8ccc997062
commit 3c8b04d91a
4 changed files with 84 additions and 14 deletions

View File

@ -5,7 +5,10 @@ import { getSession } from '@toeverything/components/board-sessions';
import { deepCopy, TldrawApp } from '@toeverything/components/board-state'; import { deepCopy, TldrawApp } from '@toeverything/components/board-state';
import { tools } from '@toeverything/components/board-tools'; import { tools } from '@toeverything/components/board-tools';
import { TDShapeType } from '@toeverything/components/board-types'; import { TDShapeType } from '@toeverything/components/board-types';
import { RecastBlockProvider } from '@toeverything/components/editor-core'; import {
RecastBlockProvider,
getClipDataOfBlocksById,
} from '@toeverything/components/editor-core';
import { services } from '@toeverything/datasource/db-service'; import { services } from '@toeverything/datasource/db-service';
import { AsyncBlock, BlockEditor } from '@toeverything/framework/virgo'; import { AsyncBlock, BlockEditor } from '@toeverything/framework/virgo';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
@ -16,7 +19,11 @@ interface AffineBoardProps {
rootBlockId: string; rootBlockId: string;
} }
const AffineBoard = ({ workspace, rootBlockId }: AffineBoardProps) => { const AffineBoard = ({
workspace,
rootBlockId,
editor,
}: AffineBoardProps & { editor: BlockEditor }) => {
const [app, set_app] = useState<TldrawApp>(); const [app, set_app] = useState<TldrawApp>();
const [document] = useState(() => { const [document] = useState(() => {
@ -62,6 +69,14 @@ const AffineBoard = ({ workspace, rootBlockId }: AffineBoardProps) => {
onMount(app) { onMount(app) {
set_app(app); set_app(app);
}, },
async onCopy(e, groupIds) {
const [mimeType, data] = await getClipDataOfBlocksById(
editor,
groupIds
);
e.clipboardData?.setData(mimeType, data);
},
onChangePage(app, shapes, bindings, assets) { onChangePage(app, shapes, bindings, assets) {
Promise.all( Promise.all(
Object.entries(shapes).map(async ([id, shape]) => { Object.entries(shapes).map(async ([id, shape]) => {
@ -130,7 +145,11 @@ export const AffineBoardWitchContext = ({
}, [editor, rootBlockId]); }, [editor, rootBlockId]);
return page ? ( return page ? (
<RecastBlockProvider block={page}> <RecastBlockProvider block={page}>
<AffineBoard workspace={workspace} rootBlockId={rootBlockId} /> <AffineBoard
workspace={workspace}
rootBlockId={rootBlockId}
editor={editor}
/>
</RecastBlockProvider> </RecastBlockProvider>
) : null; ) : null;
}; };

View File

@ -171,6 +171,10 @@ interface TDCallbacks {
* (optional) A callback to run when the user exports their page or selection. * (optional) A callback to run when the user exports their page or selection.
*/ */
onExport?: (app: TldrawApp, info: TDExport) => Promise<void>; onExport?: (app: TldrawApp, info: TDExport) => Promise<void>;
/**
* (optional) A callback to run when the shape is copied.
*/
onCopy?: (e: ClipboardEvent, ids: string[]) => void;
} }
export interface TldrawAppCtorProps { export interface TldrawAppCtorProps {
@ -1898,12 +1902,14 @@ export class TldrawApp extends StateManager<TDSnapshot> {
/** /**
* Copy one or more shapes to the clipboard. * Copy one or more shapes to the clipboard.
* @param ids The ids of the shapes to copy. * @param ids The ids of the shapes to copy.
* @param pageId
* @param e
*/ */
copy = ( copy = async (
ids = this.selectedIds, ids = this.selectedIds,
pageId = this.currentPageId, pageId = this.currentPageId,
e?: ClipboardEvent e?: ClipboardEvent
): this => { ) => {
e?.preventDefault(); e?.preventDefault();
this.clipboard = this.get_clipboard(ids, pageId); this.clipboard = this.get_clipboard(ids, pageId);
@ -1919,17 +1925,24 @@ export class TldrawApp extends StateManager<TDSnapshot> {
if (e) { if (e) {
e.clipboardData?.setData('text/html', tldrawString); e.clipboardData?.setData('text/html', tldrawString);
await this.callbacks.onCopy?.(e, this.selectedIds);
} }
if (navigator.clipboard && window.ClipboardItem) { /**
navigator.clipboard.write([ * Reasons for not using Clipboard API for now:
new ClipboardItem({ * 1. The `clipboardData.setData` method temporarily satisfies the need for replication functionality
'text/html': new Blob([tldrawString], { * 2. Clipboard API requires the user to agree to access(https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API)
type: 'text/html', *
}), * **/
}), // if (navigator.clipboard && window.ClipboardItem) {
]); // navigator.clipboard.write([
} // new ClipboardItem({
// 'text/html': new Blob([tldrawString], {
// type: 'text/html',
// }),
// }),
// ]);
// }
this.pasteInfo.offset = [0, 0]; this.pasteInfo.offset = [0, 0];
this.pasteInfo.center = [0, 0]; this.pasteInfo.center = [0, 0];

View File

@ -1,4 +1,6 @@
import { Editor } from '../editor'; import { Editor } from '../editor';
import { ClipBlockInfo, OFFICE_CLIPBOARD_MIMETYPE } from './types';
import { Clip } from './clip';
export const shouldHandlerContinue = (event: Event, editor: Editor) => { export const shouldHandlerContinue = (event: Event, editor: Editor) => {
const filterNodes = ['INPUT', 'SELECT', 'TEXTAREA']; const filterNodes = ['INPUT', 'SELECT', 'TEXTAREA'];
@ -12,3 +14,38 @@ export const shouldHandlerContinue = (event: Event, editor: Editor) => {
return editor.selectionManager.currentSelectInfo.type !== 'None'; return editor.selectionManager.currentSelectInfo.type !== 'None';
}; };
export const getClipInfoOfBlockById = async (
editor: Editor,
blockId: string
) => {
const block = await editor.getBlockById(blockId);
const blockView = editor.getView(block.type);
const blockInfo: ClipBlockInfo = {
type: block.type,
properties: blockView.getSelProperties(block, {}),
children: [] as ClipBlockInfo[],
};
const children = await block?.children();
for (let i = 0; i < children.length; i++) {
const childInfo = await getClipInfoOfBlockById(editor, children[i].id);
blockInfo.children.push(childInfo);
}
return blockInfo;
};
export const getClipDataOfBlocksById = async (
editor: Editor,
blockIds: string[]
) => {
const clipInfos = await Promise.all(
blockIds.map(blockId => getClipInfoOfBlockById(editor, blockId))
);
return [
OFFICE_CLIPBOARD_MIMETYPE.DOCS_DOCUMENT_SLICE_CLIP_WRAPPED,
JSON.stringify({
data: clipInfos,
}),
];
};

View File

@ -10,3 +10,4 @@ export { BlockDropPlacement, HookType, GroupDirection } from './types';
export type { Plugin, PluginCreator, PluginHooks, Virgo } from './types'; export type { Plugin, PluginCreator, PluginHooks, Virgo } from './types';
export { BaseView, getTextHtml, getTextProperties } from './views/base-view'; export { BaseView, getTextHtml, getTextProperties } from './views/base-view';
export type { ChildrenView, CreateView } from './views/base-view'; export type { ChildrenView, CreateView } from './views/base-view';
export { getClipDataOfBlocksById } from './clipboard/utils';