mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-22 12:32:00 +08:00
feat: add clipboardEvent2Blocks for white board to paste
This commit is contained in:
@@ -10,7 +10,6 @@ export class Clipboard {
|
|||||||
private _clipboardEventDispatcher: ClipboardEventDispatcher;
|
private _clipboardEventDispatcher: ClipboardEventDispatcher;
|
||||||
private _copy: Copy;
|
private _copy: Copy;
|
||||||
private _paste: Paste;
|
private _paste: Paste;
|
||||||
private readonly _supportMarkdownPaste = true;
|
|
||||||
public clipboardUtils: ClipboardUtils;
|
public clipboardUtils: ClipboardUtils;
|
||||||
private _clipboardTarget: HTMLElement;
|
private _clipboardTarget: HTMLElement;
|
||||||
|
|
||||||
@@ -19,7 +18,7 @@ export class Clipboard {
|
|||||||
this._clipboardTarget = clipboardTarget;
|
this._clipboardTarget = clipboardTarget;
|
||||||
this._copy = new Copy(editor);
|
this._copy = new Copy(editor);
|
||||||
|
|
||||||
this._paste = new Paste(editor, this._supportMarkdownPaste);
|
this._paste = new Paste(editor);
|
||||||
|
|
||||||
this._clipboardEventDispatcher = new ClipboardEventDispatcher(
|
this._clipboardEventDispatcher = new ClipboardEventDispatcher(
|
||||||
editor,
|
editor,
|
||||||
@@ -49,7 +48,9 @@ export class Clipboard {
|
|||||||
return this._clipboardTarget;
|
return this._clipboardTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
setEditorContainer(container: HTMLElement) {}
|
public clipboardEvent2Blocks(e: ClipboardEvent) {
|
||||||
|
return this._paste.clipboardEvent2Blocks(e);
|
||||||
|
}
|
||||||
|
|
||||||
public dispose() {
|
public dispose() {
|
||||||
this._clipboardEventDispatcher.dispose(this.clipboardTarget);
|
this._clipboardEventDispatcher.dispose(this.clipboardTarget);
|
||||||
|
|||||||
@@ -147,14 +147,14 @@ export class ClipboardUtils {
|
|||||||
).join('');
|
).join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
async convertHTMLString2Blocks(html: string) {
|
async convertHTMLString2Blocks(html: string): Promise<ClipBlockInfo[]> {
|
||||||
const htmlEl = document.createElement('html');
|
const htmlEl = document.createElement('html');
|
||||||
htmlEl.innerHTML = html;
|
htmlEl.innerHTML = html;
|
||||||
htmlEl.querySelector('head')?.remove();
|
htmlEl.querySelector('head')?.remove();
|
||||||
|
|
||||||
return this.convertHtml2Block(htmlEl);
|
return this.convertHtml2Blocks(htmlEl);
|
||||||
}
|
}
|
||||||
async convertHtml2Block(element: Element): Promise<ClipBlockInfo[]> {
|
async convertHtml2Blocks(element: Element): Promise<ClipBlockInfo[]> {
|
||||||
const editableViews = this._editor.getEditableViews();
|
const editableViews = this._editor.getEditableViews();
|
||||||
// 如果block能够捕捉htmlElement则返回block的html2block
|
// 如果block能够捕捉htmlElement则返回block的html2block
|
||||||
const [clipBlockInfos] = (
|
const [clipBlockInfos] = (
|
||||||
@@ -174,7 +174,7 @@ export class ClipboardUtils {
|
|||||||
return (
|
return (
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
Array.from(element.children).map(async childElement => {
|
Array.from(element.children).map(async childElement => {
|
||||||
const clipBlockInfos = await this.convertHtml2Block(
|
const clipBlockInfos = await this.convertHtml2Blocks(
|
||||||
childElement
|
childElement
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -19,13 +19,10 @@ type TextValueItem = {
|
|||||||
export class Paste {
|
export class Paste {
|
||||||
private _editor: Editor;
|
private _editor: Editor;
|
||||||
private _markdownParse: MarkdownParser;
|
private _markdownParse: MarkdownParser;
|
||||||
private readonly _supportMarkdownPaste: boolean = true;
|
|
||||||
private _utils: ClipboardUtils;
|
private _utils: ClipboardUtils;
|
||||||
constructor(editor: Editor, supportMarkdownPaste?: boolean) {
|
constructor(editor: Editor) {
|
||||||
this._markdownParse = new MarkdownParser();
|
this._markdownParse = new MarkdownParser();
|
||||||
this._editor = editor;
|
this._editor = editor;
|
||||||
this._supportMarkdownPaste =
|
|
||||||
supportMarkdownPaste ?? this._supportMarkdownPaste;
|
|
||||||
|
|
||||||
this._utils = new ClipboardUtils(editor);
|
this._utils = new ClipboardUtils(editor);
|
||||||
this.handlePaste = this.handlePaste.bind(this);
|
this.handlePaste = this.handlePaste.bind(this);
|
||||||
@@ -37,17 +34,21 @@ export class Paste {
|
|||||||
OFFICE_CLIPBOARD_MIMETYPE.TEXT,
|
OFFICE_CLIPBOARD_MIMETYPE.TEXT,
|
||||||
];
|
];
|
||||||
|
|
||||||
public handlePaste(e: ClipboardEvent) {
|
public async handlePaste(e: ClipboardEvent) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
const clipboardData = e.clipboardData;
|
const blocks = await this.clipboardEvent2Blocks(e);
|
||||||
|
await this._insertBlocks(blocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async clipboardEvent2Blocks(e: ClipboardEvent) {
|
||||||
|
const clipboardData = e.clipboardData;
|
||||||
const isPureFile = Paste._isPureFileInClipboard(clipboardData);
|
const isPureFile = Paste._isPureFileInClipboard(clipboardData);
|
||||||
|
|
||||||
if (isPureFile) {
|
if (isPureFile) {
|
||||||
this._pasteFile(clipboardData);
|
return this._file2Blocks(clipboardData);
|
||||||
} else {
|
|
||||||
this._pasteContent(clipboardData);
|
|
||||||
}
|
}
|
||||||
|
return this._clipboardData2Blocks(clipboardData);
|
||||||
}
|
}
|
||||||
// Get the most needed clipboard data based on `_optimalMimeTypes` order
|
// Get the most needed clipboard data based on `_optimalMimeTypes` order
|
||||||
public getOptimalClip(clipboardData: ClipboardEvent['clipboardData']) {
|
public getOptimalClip(clipboardData: ClipboardEvent['clipboardData']) {
|
||||||
@@ -66,43 +67,41 @@ export class Paste {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _pasteContent(clipboardData: ClipboardEvent['clipboardData']) {
|
private async _clipboardData2Blocks(
|
||||||
|
clipboardData: ClipboardEvent['clipboardData']
|
||||||
|
): Promise<ClipBlockInfo[]> {
|
||||||
const optimalClip = this.getOptimalClip(clipboardData);
|
const optimalClip = this.getOptimalClip(clipboardData);
|
||||||
if (
|
if (
|
||||||
optimalClip?.type ===
|
optimalClip?.type ===
|
||||||
OFFICE_CLIPBOARD_MIMETYPE.DOCS_DOCUMENT_SLICE_CLIP_WRAPPED
|
OFFICE_CLIPBOARD_MIMETYPE.DOCS_DOCUMENT_SLICE_CLIP_WRAPPED
|
||||||
) {
|
) {
|
||||||
return this._firePasteEditAction(optimalClip.data);
|
const clipInfo: InnerClipInfo = JSON.parse(optimalClip.data);
|
||||||
|
return clipInfo.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
const textClipData = escape(
|
const textClipData = escape(
|
||||||
clipboardData.getData(OFFICE_CLIPBOARD_MIMETYPE.TEXT)
|
clipboardData.getData(OFFICE_CLIPBOARD_MIMETYPE.TEXT)
|
||||||
);
|
);
|
||||||
|
|
||||||
const shouldConvertMarkdown =
|
const shouldConvertMarkdown =
|
||||||
this._supportMarkdownPaste &&
|
|
||||||
this._markdownParse.checkIfTextContainsMd(textClipData);
|
this._markdownParse.checkIfTextContainsMd(textClipData);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
optimalClip?.type === OFFICE_CLIPBOARD_MIMETYPE.HTML &&
|
optimalClip?.type === OFFICE_CLIPBOARD_MIMETYPE.HTML &&
|
||||||
!shouldConvertMarkdown
|
!shouldConvertMarkdown
|
||||||
) {
|
) {
|
||||||
return this._pasteHtml(optimalClip.data);
|
return this._utils.convertHTMLString2Blocks(optimalClip.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldConvertMarkdown) {
|
if (shouldConvertMarkdown) {
|
||||||
const md2html = marked.parse(textClipData);
|
const md2html = marked.parse(textClipData);
|
||||||
return this._pasteHtml(md2html);
|
return this._utils.convertHTMLString2Blocks(md2html);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._pasteText(textClipData);
|
return this._utils.textToBlock(textClipData);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _firePasteEditAction(clipboardData: string) {
|
private async _file2Blocks(clipboardData: any): Promise<ClipBlockInfo[]> {
|
||||||
const clipInfo: InnerClipInfo = JSON.parse(clipboardData);
|
|
||||||
clipInfo && this._insertBlocks(clipInfo.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _pasteFile(clipboardData: any) {
|
|
||||||
const file = Paste._getImageFile(clipboardData);
|
const file = Paste._getImageFile(clipboardData);
|
||||||
if (file) {
|
if (file) {
|
||||||
const result = await services.api.file.create({
|
const result = await services.api.file.create({
|
||||||
@@ -121,8 +120,9 @@ export class Paste {
|
|||||||
},
|
},
|
||||||
children: [] as ClipBlockInfo[],
|
children: [] as ClipBlockInfo[],
|
||||||
};
|
};
|
||||||
await this._insertBlocks([blockInfo]);
|
return [blockInfo];
|
||||||
}
|
}
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
private static _isPureFileInClipboard(clipboardData: DataTransfer) {
|
private static _isPureFileInClipboard(clipboardData: DataTransfer) {
|
||||||
const types = clipboardData.types;
|
const types = clipboardData.types;
|
||||||
@@ -423,16 +423,6 @@ export class Paste {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _pasteHtml(clipData: string) {
|
|
||||||
const block2 = await this._utils.convertHTMLString2Blocks(clipData);
|
|
||||||
await this._insertBlocks(block2);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _pasteText(clipData: string) {
|
|
||||||
const blocks = this._utils.textToBlock(clipData);
|
|
||||||
await this._insertBlocks(blocks);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static _getImageFile(clipboardData: any) {
|
private static _getImageFile(clipboardData: any) {
|
||||||
const files = clipboardData.files;
|
const files = clipboardData.files;
|
||||||
if (files && files[0] && files[0].type.indexOf('image') > -1) {
|
if (files && files[0] && files[0].type.indexOf('image') > -1) {
|
||||||
|
|||||||
Reference in New Issue
Block a user