mirror of
https://github.com/toeverything/AFFiNE.git
synced 2025-01-03 21:35:19 +03:00
refactor: refactor clipboard
This commit is contained in:
parent
66a36481e1
commit
17e454b1e6
@ -24,6 +24,7 @@ import {
|
||||
MARKDOWN_STYLE_MAP,
|
||||
MatchRes,
|
||||
} from './utils';
|
||||
import { AsyncBlock, SelectBlock } from '@toeverything/components/editor-core';
|
||||
|
||||
function isInlineAndVoid(editor: Editor, el: any) {
|
||||
return editor.isInline(el) && editor.isVoid(el);
|
||||
@ -958,7 +959,41 @@ class SlateUtils {
|
||||
}
|
||||
|
||||
public getNodeByPath(path: Path) {
|
||||
Editor.node(this.editor, path);
|
||||
return Editor.node(this.editor, path);
|
||||
}
|
||||
|
||||
public getNodeByRange(range: Range) {
|
||||
return Editor.node(this.editor, range);
|
||||
}
|
||||
|
||||
// This may should write with logic of render slate
|
||||
public convertLeaf2Html(textValue: any) {
|
||||
const { text, fontColor, fontBgColor } = textValue;
|
||||
|
||||
const style = `style="${fontColor ? `color: ${fontColor};` : ''}${
|
||||
fontBgColor ? `backgroundColor: ${fontBgColor};` : ''
|
||||
}"`;
|
||||
if (textValue.bold) {
|
||||
return `<strong ${style}>${text}</strong>`;
|
||||
}
|
||||
if (textValue.italic) {
|
||||
return `<em ${style}>${text}</em>`;
|
||||
}
|
||||
if (textValue.underline) {
|
||||
return `<u ${style}>${text}</u>`;
|
||||
}
|
||||
if (textValue.inlinecode) {
|
||||
return `<code ${style}>${text}</code>`;
|
||||
}
|
||||
if (textValue.strikethrough) {
|
||||
return `<s ${style}>${text}</s>`;
|
||||
}
|
||||
if (textValue.type === 'link') {
|
||||
return `<a href='${textValue.url}' ${style}>${this.convertLeaf2Html(
|
||||
textValue.children
|
||||
)}</a>`;
|
||||
}
|
||||
return `<span ${style}>${text}</span>>`;
|
||||
}
|
||||
|
||||
public getStartSelection() {
|
||||
|
@ -2,7 +2,6 @@ import {
|
||||
AsyncBlock,
|
||||
BaseView,
|
||||
CreateView,
|
||||
getTextProperties,
|
||||
SelectBlock,
|
||||
getTextHtml,
|
||||
} from '@toeverything/framework/virgo';
|
||||
@ -28,14 +27,6 @@ export class BulletBlock extends BaseView {
|
||||
return block;
|
||||
}
|
||||
|
||||
override getSelProperties(
|
||||
block: AsyncBlock,
|
||||
selectInfo: any
|
||||
): DefaultColumnsValue {
|
||||
const properties = super.getSelProperties(block, selectInfo);
|
||||
return getTextProperties(properties, selectInfo);
|
||||
}
|
||||
|
||||
override html2block(
|
||||
el: Element,
|
||||
parseEl: (el: Element) => any[]
|
||||
|
@ -1,7 +1,6 @@
|
||||
import {
|
||||
BaseView,
|
||||
AsyncBlock,
|
||||
getTextProperties,
|
||||
CreateView,
|
||||
SelectBlock,
|
||||
getTextHtml,
|
||||
@ -28,14 +27,6 @@ export class CodeBlock extends BaseView {
|
||||
return block;
|
||||
}
|
||||
|
||||
override getSelProperties(
|
||||
block: AsyncBlock,
|
||||
selectInfo: any
|
||||
): DefaultColumnsValue {
|
||||
const properties = super.getSelProperties(block, selectInfo);
|
||||
return getTextProperties(properties, selectInfo);
|
||||
}
|
||||
|
||||
// TODO: internal format not implemented yet
|
||||
override html2block(
|
||||
el: Element,
|
||||
|
@ -1,7 +1,6 @@
|
||||
import {
|
||||
AsyncBlock,
|
||||
BaseView,
|
||||
getTextProperties,
|
||||
SelectBlock,
|
||||
getTextHtml,
|
||||
} from '@toeverything/framework/virgo';
|
||||
@ -29,14 +28,6 @@ export class NumberedBlock extends BaseView {
|
||||
return block;
|
||||
}
|
||||
|
||||
override getSelProperties(
|
||||
block: AsyncBlock,
|
||||
selectInfo: any
|
||||
): DefaultColumnsValue {
|
||||
const properties = super.getSelProperties(block, selectInfo);
|
||||
return getTextProperties(properties, selectInfo);
|
||||
}
|
||||
|
||||
override html2block(
|
||||
el: Element,
|
||||
parseEl: (el: Element) => any[]
|
||||
|
@ -8,7 +8,6 @@ import {
|
||||
BaseView,
|
||||
ChildrenView,
|
||||
getTextHtml,
|
||||
getTextProperties,
|
||||
SelectBlock,
|
||||
} from '@toeverything/framework/virgo';
|
||||
|
||||
@ -35,14 +34,6 @@ export class PageBlock extends BaseView {
|
||||
return this.get_decoration<any>(content, 'text')?.value?.[0].text;
|
||||
}
|
||||
|
||||
override getSelProperties(
|
||||
block: AsyncBlock,
|
||||
selectInfo: any
|
||||
): DefaultColumnsValue {
|
||||
const properties = super.getSelProperties(block, selectInfo);
|
||||
return getTextProperties(properties, selectInfo);
|
||||
}
|
||||
|
||||
override async block2html(
|
||||
block: AsyncBlock,
|
||||
children: SelectBlock[],
|
||||
|
@ -7,7 +7,6 @@ import {
|
||||
BaseView,
|
||||
CreateView,
|
||||
getTextHtml,
|
||||
getTextProperties,
|
||||
SelectBlock,
|
||||
} from '@toeverything/framework/virgo';
|
||||
|
||||
@ -29,14 +28,6 @@ export class QuoteBlock extends BaseView {
|
||||
return block;
|
||||
}
|
||||
|
||||
override getSelProperties(
|
||||
block: AsyncBlock,
|
||||
selectInfo: any
|
||||
): DefaultColumnsValue {
|
||||
const properties = super.getSelProperties(block, selectInfo);
|
||||
return getTextProperties(properties, selectInfo);
|
||||
}
|
||||
|
||||
override html2block(
|
||||
el: Element,
|
||||
parseEl: (el: Element) => any[]
|
||||
@ -96,14 +87,6 @@ export class CalloutBlock extends BaseView {
|
||||
return block;
|
||||
}
|
||||
|
||||
override getSelProperties(
|
||||
block: AsyncBlock,
|
||||
selectInfo: any
|
||||
): DefaultColumnsValue {
|
||||
const properties = super.getSelProperties(block, selectInfo);
|
||||
return getTextProperties(properties, selectInfo);
|
||||
}
|
||||
|
||||
override html2block(
|
||||
el: Element,
|
||||
parseEl: (el: Element) => any[]
|
||||
|
@ -2,7 +2,6 @@ import {
|
||||
BaseView,
|
||||
CreateView,
|
||||
AsyncBlock,
|
||||
getTextProperties,
|
||||
SelectBlock,
|
||||
getTextHtml,
|
||||
} from '@toeverything/framework/virgo';
|
||||
@ -28,14 +27,6 @@ export class TextBlock extends BaseView {
|
||||
return block;
|
||||
}
|
||||
|
||||
override getSelProperties(
|
||||
block: AsyncBlock,
|
||||
selectInfo: any
|
||||
): DefaultColumnsValue {
|
||||
const properties = super.getSelProperties(block, selectInfo);
|
||||
return getTextProperties(properties, selectInfo);
|
||||
}
|
||||
|
||||
override html2block(
|
||||
el: Element,
|
||||
parseEl: (el: Element) => any[]
|
||||
@ -145,14 +136,6 @@ export class Heading1Block extends BaseView {
|
||||
return block;
|
||||
}
|
||||
|
||||
override getSelProperties(
|
||||
block: AsyncBlock,
|
||||
selectInfo: any
|
||||
): DefaultColumnsValue {
|
||||
const properties = super.getSelProperties(block, selectInfo);
|
||||
return getTextProperties(properties, selectInfo);
|
||||
}
|
||||
|
||||
override html2block(
|
||||
el: Element,
|
||||
parseEl: (el: Element) => any[]
|
||||
@ -210,14 +193,6 @@ export class Heading2Block extends BaseView {
|
||||
return block;
|
||||
}
|
||||
|
||||
override getSelProperties(
|
||||
block: AsyncBlock,
|
||||
selectInfo: any
|
||||
): DefaultColumnsValue {
|
||||
const properties = super.getSelProperties(block, selectInfo);
|
||||
return getTextProperties(properties, selectInfo);
|
||||
}
|
||||
|
||||
override html2block(
|
||||
el: Element,
|
||||
parseEl: (el: Element) => any[]
|
||||
@ -275,14 +250,6 @@ export class Heading3Block extends BaseView {
|
||||
return block;
|
||||
}
|
||||
|
||||
override getSelProperties(
|
||||
block: AsyncBlock,
|
||||
selectInfo: any
|
||||
): DefaultColumnsValue {
|
||||
const properties = super.getSelProperties(block, selectInfo);
|
||||
return getTextProperties(properties, selectInfo);
|
||||
}
|
||||
|
||||
override html2block(
|
||||
el: Element,
|
||||
parseEl: (el: Element) => any[]
|
||||
|
@ -1,6 +1,5 @@
|
||||
import {
|
||||
BaseView,
|
||||
getTextProperties,
|
||||
AsyncBlock,
|
||||
SelectBlock,
|
||||
getTextHtml,
|
||||
@ -29,14 +28,6 @@ export class TodoBlock extends BaseView {
|
||||
return block;
|
||||
}
|
||||
|
||||
override getSelProperties(
|
||||
block: TodoAsyncBlock,
|
||||
selectInfo: any
|
||||
): DefaultColumnsValue {
|
||||
const properties = super.getSelProperties(block, selectInfo);
|
||||
return getTextProperties(properties, selectInfo);
|
||||
}
|
||||
|
||||
override html2block(
|
||||
el: Element,
|
||||
parseEl: (el: Element) => any[]
|
||||
|
@ -41,7 +41,9 @@ export class YoutubeBlock extends BaseView {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
override async block2Text(block: AsyncBlock, selectInfo: SelectBlock) {
|
||||
return block.getProperty('embedLink')?.value ?? '';
|
||||
}
|
||||
override async block2html(
|
||||
block: AsyncBlock,
|
||||
children: SelectBlock[],
|
||||
|
@ -11,6 +11,11 @@ import {
|
||||
Selection as SlateSelection,
|
||||
} from 'slate';
|
||||
import { Editor } from '../editor';
|
||||
import {
|
||||
AsyncBlock,
|
||||
SelectBlock,
|
||||
SelectInfo,
|
||||
} from '@toeverything/components/editor-core';
|
||||
|
||||
type TextUtilsFunctions =
|
||||
| 'getString'
|
||||
@ -37,7 +42,9 @@ type TextUtilsFunctions =
|
||||
| 'blur'
|
||||
| 'setSelection'
|
||||
| 'insertNodes'
|
||||
| 'getNodeByPath';
|
||||
| 'getNodeByPath'
|
||||
| 'getNodeByRange'
|
||||
| 'convertLeaf2Html';
|
||||
|
||||
type ExtendedTextUtils = SlateUtils & {
|
||||
setLinkModalVisible: (visible: boolean) => void;
|
||||
@ -98,15 +105,116 @@ export class BlockHelper {
|
||||
return '';
|
||||
}
|
||||
|
||||
public getBlockTextBetweenSelection(blockId: string) {
|
||||
public async isBlockEditable(blockOrBlockId: AsyncBlock | string) {
|
||||
const block =
|
||||
typeof blockOrBlockId === 'string'
|
||||
? await this._editor.getBlockById(blockOrBlockId)
|
||||
: blockOrBlockId;
|
||||
const blockView = this._editor.getView(block.type);
|
||||
|
||||
return blockView.activatable;
|
||||
}
|
||||
|
||||
public async getFlatBlocksUnderParent(
|
||||
parentBlockId: string,
|
||||
includeParent: boolean = false
|
||||
): Promise<AsyncBlock[]> {
|
||||
const blocks = [];
|
||||
const block = await this._editor.getBlockById(parentBlockId);
|
||||
if (includeParent) {
|
||||
blocks.push(block);
|
||||
}
|
||||
const children = await block.children();
|
||||
(
|
||||
await Promise.all(
|
||||
children.map(child => {
|
||||
return this.getFlatBlocksUnderParent(child.id, true);
|
||||
})
|
||||
)
|
||||
).forEach(editableChildren => {
|
||||
blocks.push(...editableChildren);
|
||||
});
|
||||
return blocks;
|
||||
}
|
||||
|
||||
public getBlockTextBetweenSelection(
|
||||
blockId: string,
|
||||
shouldUsePreviousSelection = true
|
||||
) {
|
||||
const text_utils = this._blockTextUtilsMap[blockId];
|
||||
if (text_utils) {
|
||||
return text_utils.getStringBetweenSelection(true);
|
||||
return text_utils.getStringBetweenSelection(
|
||||
shouldUsePreviousSelection
|
||||
);
|
||||
}
|
||||
console.warn('Could find the block text utils');
|
||||
return '';
|
||||
}
|
||||
|
||||
public async getEditableBlockPropertiesBySelectInfo(
|
||||
block: AsyncBlock,
|
||||
selectInfo: SelectBlock
|
||||
) {
|
||||
const properties = block.getProperties();
|
||||
if (properties.text.value.length === 0) {
|
||||
return properties;
|
||||
}
|
||||
let text_value = properties.text.value;
|
||||
|
||||
const {
|
||||
text: { value: originTextValue, ...otherTextProperties },
|
||||
...otherProperties
|
||||
} = properties;
|
||||
|
||||
// Use deepClone method will throw incomprehensible error
|
||||
let textValue = JSON.parse(JSON.stringify(originTextValue));
|
||||
|
||||
if (selectInfo.endInfo) {
|
||||
textValue = textValue.slice(0, selectInfo.endInfo.arrayIndex + 1);
|
||||
textValue[textValue.length - 1].text = text_value[
|
||||
textValue.length - 1
|
||||
].text.substring(0, selectInfo.endInfo.offset);
|
||||
}
|
||||
if (selectInfo.startInfo) {
|
||||
textValue = textValue.slice(selectInfo.startInfo.arrayIndex);
|
||||
textValue[0].text = textValue[0].text.substring(
|
||||
selectInfo.startInfo.offset
|
||||
);
|
||||
}
|
||||
return {
|
||||
...otherProperties,
|
||||
text: {
|
||||
...otherTextProperties,
|
||||
value: textValue,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// For editable blocks, the properties containing the selected text will be returned with the selection information
|
||||
public async getBlockPropertiesBySelectInfo(selectBlockInfo: SelectBlock) {
|
||||
const block = await this._editor.getBlockById(selectBlockInfo.blockId);
|
||||
const blockView = this._editor.getView(block.type);
|
||||
if (blockView.activatable) {
|
||||
return this.getEditableBlockPropertiesBySelectInfo(
|
||||
block,
|
||||
selectBlockInfo
|
||||
);
|
||||
} else {
|
||||
return block?.getProperties();
|
||||
}
|
||||
}
|
||||
|
||||
public convertTextValue2Html(blockId: string, textValue: any) {
|
||||
const text_utils = this._blockTextUtilsMap[blockId];
|
||||
if (!text_utils) {
|
||||
return '';
|
||||
}
|
||||
return textValue.reduce((html: string, textValueItem: any) => {
|
||||
const fragment = text_utils.convertLeaf2Html(textValueItem);
|
||||
return `${html}${fragment}`;
|
||||
}, '');
|
||||
}
|
||||
|
||||
public setBlockBlur(blockId: string) {
|
||||
const text_utils = this._blockTextUtilsMap[blockId];
|
||||
if (text_utils) {
|
||||
|
@ -1,128 +0,0 @@
|
||||
import { HooksRunner } from '../types';
|
||||
import { Editor } from '../editor';
|
||||
import ClipboardParse from './clipboard-parse';
|
||||
import { MarkdownParser } from './markdown-parse';
|
||||
import { shouldHandlerContinue } from './utils';
|
||||
import { Paste } from './paste';
|
||||
// todo needs to be a switch
|
||||
|
||||
enum ClipboardAction {
|
||||
COPY = 'copy',
|
||||
CUT = 'cut',
|
||||
PASTE = 'paste',
|
||||
}
|
||||
|
||||
//TODO: need to consider the cursor position after inserting the children
|
||||
class BrowserClipboard {
|
||||
private _eventTarget: Element;
|
||||
private _hooks: HooksRunner;
|
||||
private _editor: Editor;
|
||||
private _clipboardParse: ClipboardParse;
|
||||
private _markdownParse: MarkdownParser;
|
||||
private _paste: Paste;
|
||||
|
||||
constructor(eventTarget: Element, hooks: HooksRunner, editor: Editor) {
|
||||
this._eventTarget = eventTarget;
|
||||
this._hooks = hooks;
|
||||
this._editor = editor;
|
||||
this._clipboardParse = new ClipboardParse(editor);
|
||||
this._markdownParse = new MarkdownParser();
|
||||
this._paste = new Paste(
|
||||
editor,
|
||||
this._clipboardParse,
|
||||
this._markdownParse
|
||||
);
|
||||
this._initialize();
|
||||
}
|
||||
|
||||
public getClipboardParse() {
|
||||
return this._clipboardParse;
|
||||
}
|
||||
|
||||
private _initialize() {
|
||||
this._handleCopy = this._handleCopy.bind(this);
|
||||
this._handleCut = this._handleCut.bind(this);
|
||||
|
||||
document.addEventListener(ClipboardAction.COPY, this._handleCopy);
|
||||
document.addEventListener(ClipboardAction.CUT, this._handleCut);
|
||||
document.addEventListener(
|
||||
ClipboardAction.PASTE,
|
||||
this._paste.handlePaste
|
||||
);
|
||||
this._eventTarget.addEventListener(
|
||||
ClipboardAction.COPY,
|
||||
this._handleCopy
|
||||
);
|
||||
this._eventTarget.addEventListener(
|
||||
ClipboardAction.CUT,
|
||||
this._handleCut
|
||||
);
|
||||
this._eventTarget.addEventListener(
|
||||
ClipboardAction.PASTE,
|
||||
this._paste.handlePaste
|
||||
);
|
||||
}
|
||||
|
||||
private _handleCopy(e: Event) {
|
||||
if (!shouldHandlerContinue(e, this._editor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._dispatchClipboardEvent(ClipboardAction.COPY, e as ClipboardEvent);
|
||||
}
|
||||
|
||||
private _handleCut(e: Event) {
|
||||
if (!shouldHandlerContinue(e, this._editor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._dispatchClipboardEvent(ClipboardAction.CUT, e as ClipboardEvent);
|
||||
}
|
||||
|
||||
private _preCopyCut(action: ClipboardAction, e: ClipboardEvent) {
|
||||
switch (action) {
|
||||
case ClipboardAction.COPY:
|
||||
this._hooks.beforeCopy(e);
|
||||
break;
|
||||
|
||||
case ClipboardAction.CUT:
|
||||
this._hooks.beforeCut(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private _dispatchClipboardEvent(
|
||||
action: ClipboardAction,
|
||||
e: ClipboardEvent
|
||||
) {
|
||||
this._preCopyCut(action, e);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
document.removeEventListener(ClipboardAction.COPY, this._handleCopy);
|
||||
document.removeEventListener(ClipboardAction.CUT, this._handleCut);
|
||||
document.removeEventListener(
|
||||
ClipboardAction.PASTE,
|
||||
this._paste.handlePaste
|
||||
);
|
||||
this._eventTarget.removeEventListener(
|
||||
ClipboardAction.COPY,
|
||||
this._handleCopy
|
||||
);
|
||||
this._eventTarget.removeEventListener(
|
||||
ClipboardAction.CUT,
|
||||
this._handleCut
|
||||
);
|
||||
this._eventTarget.removeEventListener(
|
||||
ClipboardAction.PASTE,
|
||||
this._paste.handlePaste
|
||||
);
|
||||
this._clipboardParse.dispose();
|
||||
this._clipboardParse = null;
|
||||
this._eventTarget = null;
|
||||
this._hooks = null;
|
||||
this._editor = null;
|
||||
}
|
||||
}
|
||||
|
||||
export { BrowserClipboard };
|
@ -1,38 +0,0 @@
|
||||
import { Editor } from '../editor';
|
||||
import { SelectionManager } from '../selection';
|
||||
import { HookType, PluginHooks } from '../types';
|
||||
import ClipboardParse from './clipboard-parse';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { Copy } from './copy';
|
||||
class ClipboardPopulator {
|
||||
private _editor: Editor;
|
||||
private _hooks: PluginHooks;
|
||||
private _selectionManager: SelectionManager;
|
||||
private _clipboardParse: ClipboardParse;
|
||||
private _sub = new Subscription();
|
||||
private _copy: Copy;
|
||||
constructor(
|
||||
editor: Editor,
|
||||
hooks: PluginHooks,
|
||||
selectionManager: SelectionManager
|
||||
) {
|
||||
this._editor = editor;
|
||||
this._hooks = hooks;
|
||||
this._selectionManager = selectionManager;
|
||||
this._clipboardParse = new ClipboardParse(editor);
|
||||
this._copy = new Copy(editor);
|
||||
this._sub.add(
|
||||
hooks.get(HookType.BEFORE_COPY).subscribe(this._copy.handleCopy)
|
||||
);
|
||||
this._sub.add(
|
||||
hooks.get(HookType.BEFORE_CUT).subscribe(this._copy.handleCopy)
|
||||
);
|
||||
}
|
||||
|
||||
disposeInternal() {
|
||||
this._sub.unsubscribe();
|
||||
this._hooks = null;
|
||||
}
|
||||
}
|
||||
|
||||
export { ClipboardPopulator };
|
@ -0,0 +1,47 @@
|
||||
import { ClipboardEventDispatcher } from './clipboardEventDispatcher';
|
||||
import { HookType } from '@toeverything/components/editor-core';
|
||||
import { Editor } from '../editor';
|
||||
import { Copy } from './copy';
|
||||
import { Paste } from './paste';
|
||||
import ClipboardParse from './clipboard-parse';
|
||||
import { MarkdownParser } from './markdown-parse';
|
||||
|
||||
export class Clipboard {
|
||||
private _clipboardEventDispatcher: ClipboardEventDispatcher;
|
||||
private _copy: Copy;
|
||||
private _paste: Paste;
|
||||
private _clipboardParse: ClipboardParse;
|
||||
private _markdownParse: MarkdownParser;
|
||||
|
||||
constructor(editor: Editor, clipboardTarget: HTMLElement) {
|
||||
this._clipboardEventDispatcher = new ClipboardEventDispatcher(
|
||||
editor,
|
||||
clipboardTarget
|
||||
);
|
||||
this._clipboardParse = new ClipboardParse(editor);
|
||||
this._markdownParse = new MarkdownParser();
|
||||
this._copy = new Copy(editor);
|
||||
|
||||
this._paste = new Paste(
|
||||
editor,
|
||||
this._clipboardParse,
|
||||
this._markdownParse
|
||||
);
|
||||
|
||||
editor
|
||||
.getHooks()
|
||||
.get(HookType.ON_COPY)
|
||||
.subscribe(this._copy.handleCopy);
|
||||
|
||||
editor.getHooks().get(HookType.ON_CUT).subscribe(this._copy.handleCopy);
|
||||
|
||||
editor
|
||||
.getHooks()
|
||||
.get(HookType.ON_PASTE)
|
||||
.subscribe(this._paste.handlePaste);
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
this._clipboardEventDispatcher.dispose();
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
import { Editor } from '../editor';
|
||||
import { shouldHandlerContinue } from './utils';
|
||||
|
||||
enum ClipboardAction {
|
||||
copy = 'copy',
|
||||
cut = 'cut',
|
||||
paste = 'paste',
|
||||
}
|
||||
|
||||
//TODO: need to consider the cursor position after inserting the children
|
||||
export class ClipboardEventDispatcher {
|
||||
private _editor: Editor;
|
||||
private _clipboardTarget: HTMLElement;
|
||||
|
||||
constructor(editor: Editor, clipboardTarget: HTMLElement) {
|
||||
this._editor = editor;
|
||||
this._clipboardTarget = clipboardTarget;
|
||||
this._initialize();
|
||||
}
|
||||
|
||||
private _initialize() {
|
||||
this._copyHandler = this._copyHandler.bind(this);
|
||||
this._cutHandler = this._cutHandler.bind(this);
|
||||
this._pasteHandler = this._pasteHandler.bind(this);
|
||||
|
||||
document.addEventListener(ClipboardAction.copy, this._copyHandler);
|
||||
document.addEventListener(ClipboardAction.cut, this._cutHandler);
|
||||
document.addEventListener(ClipboardAction.paste, this._pasteHandler);
|
||||
this._clipboardTarget.addEventListener(
|
||||
ClipboardAction.copy,
|
||||
this._copyHandler
|
||||
);
|
||||
this._clipboardTarget.addEventListener(
|
||||
ClipboardAction.cut,
|
||||
this._cutHandler
|
||||
);
|
||||
this._clipboardTarget.addEventListener(
|
||||
ClipboardAction.paste,
|
||||
this._pasteHandler
|
||||
);
|
||||
}
|
||||
|
||||
private _copyHandler(e: ClipboardEvent) {
|
||||
if (!shouldHandlerContinue(e, this._editor)) {
|
||||
return;
|
||||
}
|
||||
this._editor.getHooks().onCopy(e);
|
||||
}
|
||||
|
||||
private _cutHandler(e: ClipboardEvent) {
|
||||
if (!shouldHandlerContinue(e, this._editor)) {
|
||||
return;
|
||||
}
|
||||
this._editor.getHooks().onCut(e);
|
||||
}
|
||||
private _pasteHandler(e: ClipboardEvent) {
|
||||
if (!shouldHandlerContinue(e, this._editor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._editor.getHooks().onPaste(e);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
document.removeEventListener(ClipboardAction.copy, this._copyHandler);
|
||||
document.removeEventListener(ClipboardAction.cut, this._cutHandler);
|
||||
document.removeEventListener(ClipboardAction.paste, this._pasteHandler);
|
||||
this._clipboardTarget.removeEventListener(
|
||||
ClipboardAction.copy,
|
||||
this._copyHandler
|
||||
);
|
||||
this._clipboardTarget.removeEventListener(
|
||||
ClipboardAction.cut,
|
||||
this._cutHandler
|
||||
);
|
||||
this._clipboardTarget.removeEventListener(
|
||||
ClipboardAction.paste,
|
||||
this._pasteHandler
|
||||
);
|
||||
this._editor = null;
|
||||
}
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
import { Editor } from '../editor';
|
||||
import {
|
||||
AsyncBlock,
|
||||
SelectBlock,
|
||||
SelectInfo,
|
||||
} from '@toeverything/components/editor-core';
|
||||
import { ClipBlockInfo, OFFICE_CLIPBOARD_MIMETYPE } from './types';
|
||||
import { getClipInfoOfBlockById } from './utils';
|
||||
import { Clip } from './clip';
|
||||
|
||||
export class ClipboardUtils {
|
||||
private _editor: Editor;
|
||||
constructor(editor: Editor) {
|
||||
this._editor = editor;
|
||||
}
|
||||
|
||||
async isBlockEditable(blockOrBlockId: AsyncBlock | string) {
|
||||
const block =
|
||||
typeof blockOrBlockId === 'string'
|
||||
? await this._editor.getBlockById(blockOrBlockId)
|
||||
: blockOrBlockId;
|
||||
const blockView = this._editor.getView(block.type);
|
||||
|
||||
return blockView.activatable;
|
||||
}
|
||||
|
||||
async getClipInfoOfBlockById(blockId: string) {
|
||||
const block = await this._editor.getBlockById(blockId);
|
||||
const blockInfo: ClipBlockInfo = {
|
||||
type: block.type,
|
||||
properties: block?.getProperties(),
|
||||
children: [] as ClipBlockInfo[],
|
||||
};
|
||||
const children = (await block?.children()) ?? [];
|
||||
|
||||
await Promise.all(
|
||||
children.map(async childBlock => {
|
||||
const childInfo = await this.getClipInfoOfBlockById(
|
||||
childBlock.id
|
||||
);
|
||||
blockInfo.children.push(childInfo);
|
||||
})
|
||||
);
|
||||
|
||||
return blockInfo;
|
||||
}
|
||||
|
||||
async getClipDataOfBlocksById(blockIds: string[]) {
|
||||
const clipInfos = await Promise.all(
|
||||
blockIds.map(blockId => this.getClipInfoOfBlockById(blockId))
|
||||
);
|
||||
|
||||
return new Clip(
|
||||
OFFICE_CLIPBOARD_MIMETYPE.DOCS_DOCUMENT_SLICE_CLIP_WRAPPED,
|
||||
JSON.stringify({
|
||||
data: clipInfos,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
async getClipInfoOfBlockBySelectInfo(selectBlockInfo: SelectBlock) {
|
||||
const block = await this._editor.getBlockById(selectBlockInfo.blockId);
|
||||
const blockInfo: ClipBlockInfo = {
|
||||
type: block?.type,
|
||||
properties:
|
||||
await this._editor.blockHelper.getBlockPropertiesBySelectInfo(
|
||||
selectBlockInfo
|
||||
),
|
||||
// Editable has no children
|
||||
children: [],
|
||||
};
|
||||
return blockInfo;
|
||||
}
|
||||
|
||||
async getClipDataOfBlocksBySelectInfo(selectInfo: SelectInfo) {
|
||||
const clipInfos = await Promise.all(
|
||||
selectInfo.blocks.map(selectBlockInfo =>
|
||||
this.getClipInfoOfBlockBySelectInfo(selectBlockInfo)
|
||||
)
|
||||
);
|
||||
return new Clip(
|
||||
OFFICE_CLIPBOARD_MIMETYPE.DOCS_DOCUMENT_SLICE_CLIP_WRAPPED,
|
||||
JSON.stringify({
|
||||
data: clipInfos,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
async convertEditableBlockToHtml(block: AsyncBlock) {
|
||||
const generate = (textList: any[]) => {
|
||||
let content = '';
|
||||
textList.forEach(text_obj => {
|
||||
let text = text_obj.text || '';
|
||||
if (text_obj.bold) {
|
||||
text = `<strong>${text}</strong>`;
|
||||
}
|
||||
if (text_obj.italic) {
|
||||
text = `<em>${text}</em>`;
|
||||
}
|
||||
if (text_obj.underline) {
|
||||
text = `<u>${text}</u>`;
|
||||
}
|
||||
if (text_obj.inlinecode) {
|
||||
text = `<code>${text}</code>`;
|
||||
}
|
||||
if (text_obj.strikethrough) {
|
||||
text = `<s>${text}</s>`;
|
||||
}
|
||||
if (text_obj.type === 'link') {
|
||||
text = `<a href='${text_obj.url}'>${generate(
|
||||
text_obj.children
|
||||
)}</a>`;
|
||||
}
|
||||
content += text;
|
||||
});
|
||||
return content;
|
||||
};
|
||||
const text_list: any[] = block.getProperty('text').value;
|
||||
return generate(text_list);
|
||||
}
|
||||
}
|
@ -4,15 +4,15 @@ import { OFFICE_CLIPBOARD_MIMETYPE } from './types';
|
||||
import { Clip } from './clip';
|
||||
import ClipboardParse from './clipboard-parse';
|
||||
import { getClipDataOfBlocksById } from './utils';
|
||||
import { copyToClipboard } from '@toeverything/utils';
|
||||
import { ClipboardUtils } from './clipboardUtils';
|
||||
class Copy {
|
||||
private _editor: Editor;
|
||||
private _clipboardParse: ClipboardParse;
|
||||
|
||||
private _utils: ClipboardUtils;
|
||||
constructor(editor: Editor) {
|
||||
this._editor = editor;
|
||||
this._clipboardParse = new ClipboardParse(editor);
|
||||
|
||||
this._utils = new ClipboardUtils(editor);
|
||||
this.handleCopy = this.handleCopy.bind(this);
|
||||
}
|
||||
public async handleCopy(e: ClipboardEvent) {
|
||||
@ -22,7 +22,6 @@ class Copy {
|
||||
if (!clips.length) {
|
||||
return;
|
||||
}
|
||||
// TODO: is not compatible with safari
|
||||
const success = this._copyToClipboardFromPc(clips);
|
||||
if (!success) {
|
||||
// This way, not compatible with firefox
|
||||
@ -49,7 +48,11 @@ class Copy {
|
||||
const affineClip = await this._getAffineClip();
|
||||
clips.push(affineClip);
|
||||
|
||||
// get common html clip
|
||||
const textClip = await this._getTextClip();
|
||||
clips.push(textClip);
|
||||
|
||||
// const htmlClip = await this._getHtmlClip();
|
||||
// clips.push(htmlClip);
|
||||
const htmlClip = await this._clipboardParse.generateHtml();
|
||||
htmlClip &&
|
||||
clips.push(new Clip(OFFICE_CLIPBOARD_MIMETYPE.HTML, htmlClip));
|
||||
@ -57,16 +60,128 @@ class Copy {
|
||||
return clips;
|
||||
}
|
||||
|
||||
// private async _getHtmlClip(): Promise<Clip> {
|
||||
// const selectInfo: SelectInfo =
|
||||
// await this._editor.selectionManager.getSelectInfo();
|
||||
//
|
||||
// if (selectInfo.type === 'Range') {
|
||||
// const html = (
|
||||
// await Promise.all(
|
||||
// selectInfo.blocks.map(async selectBlockInfo => {
|
||||
// const block = await this._editor.getBlockById(
|
||||
// selectBlockInfo.blockId
|
||||
// );
|
||||
// const blockView = this._editor.getView(block.type);
|
||||
// const block2html = await blockView.block2html({
|
||||
// editor: this._editor,
|
||||
// block,
|
||||
// selectInfo: selectBlockInfo,
|
||||
// });
|
||||
//
|
||||
// if (
|
||||
// await this._editor.blockHelper.isBlockEditable(
|
||||
// block
|
||||
// )
|
||||
// ) {
|
||||
// const selectedProperties =
|
||||
// await this._editor.blockHelper.getEditableBlockPropertiesBySelectInfo(
|
||||
// block,
|
||||
// selectBlockInfo
|
||||
// );
|
||||
//
|
||||
// return (
|
||||
// block2html ||
|
||||
// this._editor.blockHelper.convertTextValue2Html(
|
||||
// block.id,
|
||||
// selectedProperties.text.value
|
||||
// )
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// return block2html;
|
||||
// })
|
||||
// )
|
||||
// ).join('');
|
||||
// console.log('html', html);
|
||||
// }
|
||||
//
|
||||
// return new Clip(OFFICE_CLIPBOARD_MIMETYPE.HTML, 'blockText');
|
||||
// }
|
||||
|
||||
private async _getAffineClip(): Promise<Clip> {
|
||||
const selectInfo: SelectInfo =
|
||||
await this._editor.selectionManager.getSelectInfo();
|
||||
|
||||
return getClipDataOfBlocksById(
|
||||
this._editor,
|
||||
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(): Promise<Clip> {
|
||||
const selectInfo: SelectInfo =
|
||||
await this._editor.selectionManager.getSelectInfo();
|
||||
|
||||
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');
|
||||
|
@ -42,13 +42,13 @@ export class Paste {
|
||||
OFFICE_CLIPBOARD_MIMETYPE.HTML,
|
||||
OFFICE_CLIPBOARD_MIMETYPE.TEXT,
|
||||
];
|
||||
public handlePaste(e: Event) {
|
||||
public handlePaste(e: ClipboardEvent) {
|
||||
if (!shouldHandlerContinue(e, this._editor)) {
|
||||
return;
|
||||
}
|
||||
e.stopPropagation();
|
||||
|
||||
const clipboardData = (e as ClipboardEvent).clipboardData;
|
||||
const clipboardData = e.clipboardData;
|
||||
|
||||
const isPureFile = Paste._isPureFileInClipboard(clipboardData);
|
||||
if (isPureFile) {
|
||||
|
@ -2,7 +2,10 @@ 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: ClipboardEvent,
|
||||
editor: Editor
|
||||
) => {
|
||||
const filterNodes = ['INPUT', 'SELECT', 'TEXTAREA'];
|
||||
|
||||
if (event.defaultPrevented) {
|
||||
@ -20,10 +23,9 @@ export const getClipInfoOfBlockById = async (
|
||||
blockId: string
|
||||
) => {
|
||||
const block = await editor.getBlockById(blockId);
|
||||
const blockView = editor.getView(block.type);
|
||||
const blockInfo: ClipBlockInfo = {
|
||||
type: block.type,
|
||||
properties: blockView.getSelProperties(block, {}),
|
||||
properties: block?.getProperties(),
|
||||
children: [] as ClipBlockInfo[],
|
||||
};
|
||||
const children = (await block?.children()) ?? [];
|
||||
|
@ -15,8 +15,7 @@ import assert from 'assert';
|
||||
import type { WorkspaceAndBlockId } from './block';
|
||||
import { AsyncBlock } from './block';
|
||||
import { BlockHelper } from './block/block-helper';
|
||||
import { BrowserClipboard } from './clipboard/browser-clipboard';
|
||||
import { ClipboardPopulator } from './clipboard/clipboard-populator';
|
||||
import { Clipboard } from './clipboard/clipboard';
|
||||
import { EditorCommands } from './commands';
|
||||
import { EditorConfig } from './config';
|
||||
import { DragDropManager } from './drag-drop';
|
||||
@ -65,8 +64,9 @@ export class Editor implements Virgo {
|
||||
readonly = false;
|
||||
private _rootBlockId: string;
|
||||
private storage_manager?: StorageManager;
|
||||
private clipboard?: BrowserClipboard;
|
||||
private clipboard_populator?: ClipboardPopulator;
|
||||
private _clipboard: Clipboard;
|
||||
// private clipboardActionDispacher?: ClipboardEventDispatcher;
|
||||
// private clipboard_populator?: ClipboardPopulator;
|
||||
public reactRenderRoot: {
|
||||
render: PatchNode;
|
||||
has: (key: string) => boolean;
|
||||
@ -138,7 +138,7 @@ export class Editor implements Virgo {
|
||||
|
||||
public set container(v: HTMLDivElement) {
|
||||
this.ui_container = v;
|
||||
this._initClipboard();
|
||||
this._clipboard = new Clipboard(this, this.ui_container);
|
||||
}
|
||||
|
||||
public get container() {
|
||||
@ -191,26 +191,26 @@ export class Editor implements Virgo {
|
||||
};
|
||||
}
|
||||
|
||||
private _disposeClipboard() {
|
||||
this.clipboard?.dispose();
|
||||
this.clipboard_populator?.disposeInternal();
|
||||
}
|
||||
// private _disposeClipboard() {
|
||||
// this.clipboard?.dispose();
|
||||
// this.clipboard_populator?.disposeInternal();
|
||||
// }
|
||||
|
||||
private _initClipboard() {
|
||||
this._disposeClipboard();
|
||||
if (this.ui_container && !this._isDisposed) {
|
||||
this.clipboard = new BrowserClipboard(
|
||||
this.ui_container,
|
||||
this.hooks,
|
||||
this
|
||||
);
|
||||
this.clipboard_populator = new ClipboardPopulator(
|
||||
this,
|
||||
this.hooks,
|
||||
this.selectionManager
|
||||
);
|
||||
}
|
||||
}
|
||||
// private _initClipboard() {
|
||||
// this._disposeClipboard();
|
||||
// if (this.ui_container && !this._isDisposed) {
|
||||
// this.clipboardActionDispacher = new ClipboardEventDispatcher({
|
||||
// clipboardTarget: this.ui_container,
|
||||
// hooks: this.hooks,
|
||||
// editor: this,
|
||||
// });
|
||||
// this.clipboard_populator = new ClipboardPopulator(
|
||||
// this,
|
||||
// this.hooks,
|
||||
// this.selectionManager
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
/** Root Block Id */
|
||||
getRootBlockId() {
|
||||
@ -498,12 +498,13 @@ export class Editor implements Virgo {
|
||||
}
|
||||
|
||||
public async page2html(): Promise<string> {
|
||||
const parse = this.clipboard?.getClipboardParse();
|
||||
if (!parse) {
|
||||
return '';
|
||||
}
|
||||
const html_str = await parse.page2html();
|
||||
return html_str;
|
||||
// const parse = this.clipboard?.getClipboardParse();
|
||||
// if (!parse) {
|
||||
// return '';
|
||||
// }
|
||||
// const html_str = await parse.page2html();
|
||||
// return html_str;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
@ -519,6 +520,6 @@ export class Editor implements Virgo {
|
||||
this.plugin_manager.dispose();
|
||||
this.selectionManager.dispose();
|
||||
this.dragDropManager.dispose();
|
||||
this._disposeClipboard();
|
||||
this._clipboard?.dispose();
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,6 @@ export { Editor as BlockEditor } from './editor';
|
||||
export * from './selection';
|
||||
export { BlockDropPlacement, HookType, GroupDirection } from './types';
|
||||
export type { Plugin, PluginCreator, PluginHooks, Virgo } from './types';
|
||||
export { BaseView, getTextHtml, getTextProperties } from './views/base-view';
|
||||
export { BaseView, getTextHtml } from './views/base-view';
|
||||
export type { ChildrenView, CreateView } from './views/base-view';
|
||||
export { getClipDataOfBlocksById } from './clipboard/utils';
|
||||
|
@ -116,12 +116,15 @@ export class Hooks implements HooksRunner, PluginHooks {
|
||||
this._runHook(HookType.ON_SEARCH);
|
||||
}
|
||||
|
||||
public beforeCopy(e: ClipboardEvent): void {
|
||||
this._runHook(HookType.BEFORE_COPY, e);
|
||||
public onCopy(e: ClipboardEvent): void {
|
||||
this._runHook(HookType.ON_COPY, e);
|
||||
}
|
||||
|
||||
public beforeCut(e: ClipboardEvent): void {
|
||||
this._runHook(HookType.BEFORE_CUT, e);
|
||||
public onCut(e: ClipboardEvent): void {
|
||||
this._runHook(HookType.ON_CUT, e);
|
||||
}
|
||||
public onPaste(e: ClipboardEvent): void {
|
||||
this._runHook(HookType.ON_PASTE, e);
|
||||
}
|
||||
|
||||
public onRootNodeScroll(e: React.UIEvent): void {
|
||||
|
@ -174,8 +174,9 @@ export enum HookType {
|
||||
ON_ROOTNODE_DRAG_END = 'onRootNodeDragEnd',
|
||||
ON_ROOTNODE_DRAG_OVER_CAPTURE = 'onRootNodeDragOverCapture',
|
||||
ON_ROOTNODE_DROP = 'onRootNodeDrop',
|
||||
BEFORE_COPY = 'beforeCopy',
|
||||
BEFORE_CUT = 'beforeCut',
|
||||
ON_COPY = 'onCopy',
|
||||
ON_CUT = 'onCut',
|
||||
ON_PASTE = 'onPaste',
|
||||
ON_ROOTNODE_SCROLL = 'onRootNodeScroll',
|
||||
}
|
||||
|
||||
@ -207,8 +208,9 @@ export interface HooksRunner {
|
||||
onRootNodeDragEnd: (e: React.DragEvent<Element>) => void;
|
||||
onRootNodeDragLeave: (e: React.DragEvent<Element>) => void;
|
||||
onRootNodeDrop: (e: React.DragEvent<Element>) => void;
|
||||
beforeCopy: (e: ClipboardEvent) => void;
|
||||
beforeCut: (e: ClipboardEvent) => void;
|
||||
onCopy: (e: ClipboardEvent) => void;
|
||||
onCut: (e: ClipboardEvent) => void;
|
||||
onPaste: (e: ClipboardEvent) => void;
|
||||
onRootNodeScroll: (e: React.UIEvent) => void;
|
||||
}
|
||||
|
||||
|
@ -131,10 +131,6 @@ export abstract class BaseView {
|
||||
return result;
|
||||
}
|
||||
|
||||
getSelProperties(block: AsyncBlock, selectInfo: any): DefaultColumnsValue {
|
||||
return cloneDeep(block.getProperties());
|
||||
}
|
||||
|
||||
html2block(el: Element, parseEl: (el: Element) => any[]): any[] | null {
|
||||
return null;
|
||||
}
|
||||
@ -146,31 +142,24 @@ export abstract class BaseView {
|
||||
): Promise<string> {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
async block2Text(
|
||||
block: AsyncBlock,
|
||||
// The selectInfo parameter is not passed when the block is selected in ful, the selectInfo.type is Range
|
||||
selectInfo?: SelectBlock
|
||||
): Promise<string> {
|
||||
return '';
|
||||
}
|
||||
|
||||
export const getTextProperties = (
|
||||
properties: DefaultColumnsValue,
|
||||
selectInfo: any
|
||||
) => {
|
||||
let text_value = properties.text.value;
|
||||
if (text_value.length === 0) {
|
||||
return properties;
|
||||
}
|
||||
if (selectInfo.endInfo) {
|
||||
text_value = text_value.slice(0, selectInfo.endInfo.arrayIndex + 1);
|
||||
text_value[text_value.length - 1].text = text_value[
|
||||
text_value.length - 1
|
||||
].text.substring(0, selectInfo.endInfo.offset);
|
||||
}
|
||||
if (selectInfo.startInfo) {
|
||||
text_value = text_value.slice(selectInfo.startInfo.arrayIndex);
|
||||
text_value[0].text = text_value[0].text.substring(
|
||||
selectInfo.startInfo.offset
|
||||
);
|
||||
}
|
||||
properties.text.value = text_value;
|
||||
return properties;
|
||||
};
|
||||
// TODO: Try using new methods
|
||||
// async block2html2(props: {
|
||||
// editor: Editor;
|
||||
// block: AsyncBlock;
|
||||
// // The selectInfo parameter is not passed when the block is selected in ful, the selectInfo.type is Range
|
||||
// selectInfo?: SelectBlock;
|
||||
// }) {
|
||||
// return '';
|
||||
// }
|
||||
}
|
||||
|
||||
export const getTextHtml = (block: AsyncBlock) => {
|
||||
const generate = (textList: any[]) => {
|
||||
|
Loading…
Reference in New Issue
Block a user