fix: shortcut for cut

This commit is contained in:
alt0
2022-10-11 17:10:38 +08:00
parent db44f619f2
commit c74b03da9a
4 changed files with 228 additions and 5 deletions
@@ -1138,6 +1138,15 @@ class SlateUtils {
});
}
public removeBetweenPoints(startPoint: Point, endPoint: Point) {
const at = {
anchor: startPoint,
focus: endPoint,
};
Transforms.select(this.editor, at);
this.editor.deleteFragment();
}
public setDoubleLinkSearchSlash(point: Point) {
const str = Editor.string(this.editor, {
anchor: this.getStart(),
@@ -13,7 +13,7 @@ import {
} from 'slate';
import { AsyncBlock } from '../block';
import { Editor } from '../editor';
import { SelectBlock } from '../selection';
import { SelectBlock, type SelectInfo } from '../selection';
type TextUtilsFunctions =
| 'getString'
@@ -40,6 +40,7 @@ type TextUtilsFunctions =
| 'getCommentsIdsBySelection'
| 'getCurrentSelection'
| 'removeSelection'
| 'removeBetweenPoints'
| 'isCollapsed'
| 'blur'
| 'setSelection'
@@ -528,4 +529,32 @@ export class BlockHelper {
console.warn('Could find the block text utils');
return undefined;
}
public removeSelection(selection: SelectInfo) {
if (selection.type === 'Range') {
selection.blocks.forEach(async selectBlockInfo => {
const text_utils =
this._blockTextUtilsMap[selectBlockInfo.blockId];
text_utils.removeBetweenPoints(
{
path: [0, selectBlockInfo.startInfo.arrayIndex],
offset: selectBlockInfo.startInfo.offset,
},
{
path: [0, selectBlockInfo.endInfo.arrayIndex],
offset: selectBlockInfo.endInfo.offset,
}
);
});
} else if (selection.type === 'Block') {
selection.blocks.forEach(async selectBlockInfo => {
(
await this._editor.getBlock({
workspace: this._editor.workspace,
id: selectBlockInfo.blockId,
})
).remove();
});
}
}
}
@@ -1,7 +1,8 @@
import { ClipboardEventDispatcher } from './clipboardEventDispatcher';
import { HookType } from '../types';
import { Editor } from '../editor';
import { HookType } from '../types';
import { ClipboardEventDispatcher } from './clipboardEventDispatcher';
import { Copy } from './copy';
import { Cut } from './cut';
import { Paste } from './paste';
import { ClipboardUtils } from './clipboardUtils';
@@ -9,6 +10,7 @@ import { ClipboardUtils } from './clipboardUtils';
export class Clipboard {
private _clipboardEventDispatcher: ClipboardEventDispatcher;
private _copy: Copy;
private _cut: Cut;
private _paste: Paste;
public clipboardUtils: ClipboardUtils;
private _clipboardTarget: HTMLElement;
@@ -17,7 +19,7 @@ export class Clipboard {
this.clipboardUtils = new ClipboardUtils(editor);
this._clipboardTarget = clipboardTarget;
this._copy = new Copy(editor);
this._cut = new Cut(editor);
this._paste = new Paste(editor);
this._clipboardEventDispatcher = new ClipboardEventDispatcher(
@@ -30,7 +32,7 @@ export class Clipboard {
.get(HookType.ON_COPY)
.subscribe(this._copy.handleCopy);
editor.getHooks().get(HookType.ON_CUT).subscribe(this._copy.handleCopy);
editor.getHooks().get(HookType.ON_CUT).subscribe(this._cut.handleCut);
editor
.getHooks()
@@ -0,0 +1,183 @@
import { Editor } from '../editor';
import { SelectInfo } from '../selection';
import { Clip } from './clip';
import { ClipboardUtils } from './clipboardUtils';
import { OFFICE_CLIPBOARD_MIMETYPE } from './types';
class Cut {
private _editor: Editor;
private _utils: ClipboardUtils;
constructor(editor: Editor) {
this._editor = editor;
this._utils = new ClipboardUtils(editor);
this.handleCut = this.handleCut.bind(this);
}
public async handleCut(e: ClipboardEvent) {
e.preventDefault();
e.stopPropagation();
const selectInfo: SelectInfo =
await this._editor.selectionManager.getSelectInfo();
const clips = await this.getClips(selectInfo);
if (!clips.length) {
return;
}
const success = this._copyToClipboardFromPc(clips);
if (!success) {
// This way, not compatible with firefox
const clipboardData = e.clipboardData;
if (clipboardData) {
try {
clips.forEach(clip => {
clipboardData.setData(
clip.getMimeType(),
clip.getData()
);
});
} catch (e) {
// TODO handle exception
}
}
}
this._editor.blockHelper.removeSelection(selectInfo);
}
async getClips(selectInfo: SelectInfo) {
const clips: Clip[] = [];
// get custom clip
const affineClip = await this._getAffineClip(selectInfo);
clips.push(affineClip);
const textClip = await this._getTextClip(selectInfo);
clips.push(textClip);
const htmlClip = await this._getHtmlClip(selectInfo);
clips.push(htmlClip);
return clips;
}
private async _getHtmlClip(selectInfo: SelectInfo): Promise<Clip> {
const htmlStr = (
await Promise.all(
selectInfo.blocks.map(async selectBlockInfo => {
const block = await this._editor.getBlockById(
selectBlockInfo.blockId
);
const blockView = this._editor.getView(block.type);
return await blockView.block2html({
editor: this._editor,
block,
selectInfo: selectBlockInfo,
});
})
)
).join('');
return new Clip(OFFICE_CLIPBOARD_MIMETYPE.HTML, htmlStr);
}
private async _getAffineClip(selectInfo: SelectInfo): Promise<Clip> {
if (selectInfo.type === 'Range') {
return this._utils.getClipDataOfBlocksBySelectInfo(selectInfo);
}
// The only remaining case is that selectInfo.type === 'Block'
return this._utils.getClipDataOfBlocksById(
selectInfo.blocks.map(block => block.blockId)
);
}
private async _getTextClip(selectInfo: SelectInfo): Promise<Clip> {
if (selectInfo.type === 'Range') {
const text = (
await Promise.all(
selectInfo.blocks.map(async selectBlockInfo => {
const block = await this._editor.getBlockById(
selectBlockInfo.blockId
);
const blockView = this._editor.getView(block.type);
const block2Text = await blockView.block2Text(
block,
selectBlockInfo
);
return (
block2Text ||
this._editor.blockHelper.getBlockTextBetweenSelection(
selectBlockInfo.blockId,
false
)
);
})
)
).join('\n');
return new Clip(OFFICE_CLIPBOARD_MIMETYPE.TEXT, text);
}
// The only remaining case is that selectInfo.type === 'Block'
const selectedBlocks = (
await Promise.all(
selectInfo.blocks.map(selectBlockInfo =>
this._editor.blockHelper.getFlatBlocksUnderParent(
selectBlockInfo.blockId,
true
)
)
)
).flat();
const blockText = (
await Promise.all(
selectedBlocks.map(async block => {
const blockView = this._editor.getView(block.type);
const block2Text = await blockView.block2Text(block);
return (
block2Text ||
this._editor.blockHelper.getBlockText(block.id)
);
})
)
).join('\n');
return new Clip(OFFICE_CLIPBOARD_MIMETYPE.TEXT, blockText);
}
// TODO: Optimization
// TODO: is not compatible with safari
private _copyToClipboardFromPc(clips: any[]) {
let success = false;
const tempElem = document.createElement('textarea');
tempElem.value = 'temp';
document.body.appendChild(tempElem);
tempElem.select();
tempElem.setSelectionRange(0, tempElem.value.length);
const listener = function (e: any) {
const clipboardData = e.clipboardData;
if (clipboardData) {
clips.forEach(clip => {
clipboardData.setData(clip.getMimeType(), clip.getData());
});
}
e.preventDefault();
e.stopPropagation();
tempElem.removeEventListener('copy', listener);
} as any;
tempElem.addEventListener('copy', listener);
try {
success = document.execCommand('copy');
} finally {
tempElem.removeEventListener('copy', listener);
document.body.removeChild(tempElem);
}
return success;
}
}
export { Cut };