refactor: refactor block2html in clipboard

This commit is contained in:
QiShaoXuan 2022-08-22 22:03:11 +08:00
parent 065f833564
commit 4b904ef762
27 changed files with 284 additions and 450 deletions

View File

@ -5,10 +5,7 @@ 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 { import { RecastBlockProvider } from '@toeverything/components/editor-core';
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';
@ -70,10 +67,10 @@ const AffineBoard = ({
set_app(app); set_app(app);
}, },
async onCopy(e, groupIds) { async onCopy(e, groupIds) {
const clip = await getClipDataOfBlocksById( const clip =
editor, await editor.clipboard.clipboardUtils.getClipDataOfBlocksById(
groupIds groupIds
); );
e.clipboardData?.setData( e.clipboardData?.setData(
clip.getMimeType(), clip.getMimeType(),

View File

@ -993,7 +993,7 @@ class SlateUtils {
textValue.children textValue.children
)}</a>`; )}</a>`;
} }
return `<span ${style}>${text}</span>>`; return `<span ${style}>${text}</span>`;
} }
public getStartSelection() { public getStartSelection() {

View File

@ -1,18 +1,10 @@
import { import { AsyncBlock, BaseView } from '@toeverything/framework/virgo';
AsyncBlock, import { Protocol } from '@toeverything/datasource/db-service';
BaseView,
CreateView,
SelectBlock,
getTextHtml,
} from '@toeverything/framework/virgo';
import {
Protocol,
DefaultColumnsValue,
} from '@toeverything/datasource/db-service';
// import { withTreeViewChildren } from '../../utils/with-tree-view-children';
import { defaultBulletProps, BulletView } from './BulletView'; import { defaultBulletProps, BulletView } from './BulletView';
import { IndentWrapper } from '../../components/IndentWrapper'; import {
Block2HtmlProps,
commonBlock2HtmlContent,
} from '../../utils/commonBlockClip';
export class BulletBlock extends BaseView { export class BulletBlock extends BaseView {
public type = Protocol.Block.Type.bullet; public type = Protocol.Block.Type.bullet;
@ -71,13 +63,7 @@ export class BulletBlock extends BaseView {
return null; return null;
} }
override async block2html( override async block2html(props: Block2HtmlProps) {
block: AsyncBlock, return `<ul><li>${await commonBlock2HtmlContent(props)}</li></ul>`;
children: SelectBlock[],
generateHtml: (el: any[]) => Promise<string>
): Promise<string> {
let content = getTextHtml(block);
content += await generateHtml(children);
return `<ul><li>${content}</li></ul>`;
} }
} }

View File

@ -1,16 +1,10 @@
import { import { BaseView, AsyncBlock } from '@toeverything/framework/virgo';
BaseView, import { Protocol } from '@toeverything/datasource/db-service';
AsyncBlock,
CreateView,
SelectBlock,
getTextHtml,
} from '@toeverything/framework/virgo';
import {
Protocol,
DefaultColumnsValue,
} from '@toeverything/datasource/db-service';
import { CodeView } from './CodeView'; import { CodeView } from './CodeView';
import { ComponentType } from 'react'; import {
Block2HtmlProps,
commonBlock2HtmlContent,
} from '../../utils/commonBlockClip';
export class CodeBlock extends BaseView { export class CodeBlock extends BaseView {
type = Protocol.Block.Type.code; type = Protocol.Block.Type.code;
@ -62,13 +56,7 @@ export class CodeBlock extends BaseView {
return null; return null;
} }
override async block2html( override async block2html(props: Block2HtmlProps) {
block: AsyncBlock, return `<code>${await commonBlock2HtmlContent(props)}<code/>`;
children: SelectBlock[],
generateHtml: (el: any[]) => Promise<string>
): Promise<string> {
let content = getTextHtml(block);
content += await generateHtml(children);
return `<code>${content}</code>`;
} }
} }

View File

@ -5,6 +5,7 @@ import {
} from '@toeverything/framework/virgo'; } from '@toeverything/framework/virgo';
import { Protocol } from '@toeverything/datasource/db-service'; import { Protocol } from '@toeverything/datasource/db-service';
import { DividerView } from './divider-view'; import { DividerView } from './divider-view';
import { Block2HtmlProps } from '../../utils/commonBlockClip';
export class DividerBlock extends BaseView { export class DividerBlock extends BaseView {
type = Protocol.Block.Type.divider; type = Protocol.Block.Type.divider;
@ -28,12 +29,7 @@ export class DividerBlock extends BaseView {
return null; return null;
} }
override async block2html(props: Block2HtmlProps) {
override async block2html( return `<hr/>`;
block: AsyncBlock,
children: SelectBlock[],
generateHtml: (el: any[]) => Promise<string>
): Promise<string> {
return `<hr>`;
} }
} }

View File

@ -5,6 +5,7 @@ import {
} from '@toeverything/framework/virgo'; } from '@toeverything/framework/virgo';
import { Protocol } from '@toeverything/datasource/db-service'; import { Protocol } from '@toeverything/datasource/db-service';
import { EmbedLinkView } from './EmbedLinkView'; import { EmbedLinkView } from './EmbedLinkView';
import { Block2HtmlProps } from '../../utils/commonBlockClip';
export class EmbedLinkBlock extends BaseView { export class EmbedLinkBlock extends BaseView {
public override selectable = true; public override selectable = true;
@ -35,13 +36,8 @@ export class EmbedLinkBlock extends BaseView {
return null; return null;
} }
override async block2html({ block }: Block2HtmlProps) {
override async block2html( const url = block.getProperty('embedLink')?.value;
block: AsyncBlock, return `<p><a href="${url}">${url}</a></p>`;
children: SelectBlock[],
generateHtml: (el: any[]) => Promise<string>
): Promise<string> {
const figma_url = block.getProperty('embedLink')?.value;
return `<p><a src=${figma_url}>${figma_url}</p>`;
} }
} }

View File

@ -5,6 +5,7 @@ import {
SelectBlock, SelectBlock,
} from '@toeverything/framework/virgo'; } from '@toeverything/framework/virgo';
import { FigmaView } from './FigmaView'; import { FigmaView } from './FigmaView';
import { Block2HtmlProps } from '../../utils/commonBlockClip';
export class FigmaBlock extends BaseView { export class FigmaBlock extends BaseView {
public override selectable = true; public override selectable = true;
@ -41,13 +42,8 @@ export class FigmaBlock extends BaseView {
return null; return null;
} }
override async block2html({ block }: Block2HtmlProps) {
override async block2html( const figmaUrl = block.getProperty('embedLink')?.value;
block: AsyncBlock, return `<p><a href="${figmaUrl}">${figmaUrl}</a></p>`;
children: SelectBlock[],
generateHtml: (el: any[]) => Promise<string>
): Promise<string> {
const figma_url = block.getProperty('embedLink')?.value;
return `<p><a src=${figma_url}>${figma_url}</p>`;
} }
} }

View File

@ -9,25 +9,22 @@ import {
services, services,
} from '@toeverything/datasource/db-service'; } from '@toeverything/datasource/db-service';
import { FileView } from './FileView'; import { FileView } from './FileView';
import { Block2HtmlProps } from '../../utils/commonBlockClip';
export class FileBlock extends BaseView { export class FileBlock extends BaseView {
public override selectable = true; public override selectable = true;
public override activatable = false; public override activatable = false;
type = Protocol.Block.Type.file; type = Protocol.Block.Type.file;
View = FileView; View = FileView;
override async block2html({ block }: Block2HtmlProps) {
const fileProperty = block.getProperty('file');
const fileId = fileProperty?.value;
const fileInfo = fileId
? await services.api.file.get(fileId, block.workspace)
: null;
override async block2html( return fileInfo
block: AsyncBlock, ? `<p><a href=${fileInfo?.url}>${fileProperty?.name}</a></p>`
children: SelectBlock[], : '';
generateHtml: (el: any[]) => Promise<string>
): Promise<string> {
const file_property =
block.getProperty('file') || ({} as FileColumnValue);
const file_id = file_property.value;
let file_info = null;
if (file_id) {
file_info = await services.api.file.get(file_id, block.workspace);
}
return `<p><a src=${file_info?.url}>${file_property?.name}</p>`;
} }
} }

View File

@ -6,6 +6,10 @@ import {
SelectBlock, SelectBlock,
} from '@toeverything/framework/virgo'; } from '@toeverything/framework/virgo';
import { GroupView } from './GroupView'; import { GroupView } from './GroupView';
import {
Block2HtmlProps,
commonBlock2HtmlContent,
} from '../../utils/commonBlockClip';
export class Group extends BaseView { export class Group extends BaseView {
public override selectable = true; public override selectable = true;
@ -25,13 +29,12 @@ export class Group extends BaseView {
override async onCreate(block: AsyncBlock): Promise<AsyncBlock> { override async onCreate(block: AsyncBlock): Promise<AsyncBlock> {
return block; return block;
} }
override async block2html({ editor, selectInfo, block }: Block2HtmlProps) {
override async block2html( const childrenHtml =
block: AsyncBlock, await editor.clipboard.clipboardUtils.convertBlock2HtmlBySelectInfos(
children: SelectBlock[], block,
generateHtml: (el: any[]) => Promise<string> selectInfo?.children
): Promise<string> { );
const content = await generateHtml(children); return `<div>${childrenHtml}<code/>`;
return `<div>${content}<div>`;
} }
} }

View File

@ -5,6 +5,7 @@ import {
} from '@toeverything/framework/virgo'; } from '@toeverything/framework/virgo';
import { Protocol } from '@toeverything/datasource/db-service'; import { Protocol } from '@toeverything/datasource/db-service';
import { GroupDividerView } from './groupDividerView'; import { GroupDividerView } from './groupDividerView';
import { Block2HtmlProps } from '../../utils/commonBlockClip';
export class GroupDividerBlock extends BaseView { export class GroupDividerBlock extends BaseView {
type = Protocol.Block.Type.groupDivider; type = Protocol.Block.Type.groupDivider;
@ -28,12 +29,7 @@ export class GroupDividerBlock extends BaseView {
return null; return null;
} }
override async block2html(props: Block2HtmlProps) {
override async block2html( return `<hr/>`;
block: AsyncBlock,
children: SelectBlock[],
generateHtml: (el: any[]) => Promise<string>
): Promise<string> {
return `<hr>`;
} }
} }

View File

@ -1,10 +1,7 @@
import { import { BaseView } from '@toeverything/framework/virgo';
AsyncBlock,
BaseView,
SelectBlock,
} from '@toeverything/framework/virgo';
import { Protocol } from '@toeverything/datasource/db-service'; import { Protocol } from '@toeverything/datasource/db-service';
import { ImageView } from './ImageView'; import { ImageView } from './ImageView';
import { Block2HtmlProps } from '../../utils/commonBlockClip';
export class ImageBlock extends BaseView { export class ImageBlock extends BaseView {
public override selectable = true; public override selectable = true;
@ -37,18 +34,13 @@ export class ImageBlock extends BaseView {
return null; return null;
} }
// TODO: override async block2html({ block, editor }: Block2HtmlProps) {
override async block2html( const textValue = block.getProperty('text');
block: AsyncBlock,
children: SelectBlock[],
generateHtml: (el: any[]) => Promise<string>
): Promise<string> {
const text = block.getProperty('text');
const content = ''; const content = '';
if (text) { // TODO: text.value should export with style??
text.value.map(text => `<span>${text}</span>`).join(''); const figcaption = (textValue?.value ?? [])
} .map(({ text }) => `<span>${text}</span>`)
// TODO: child .join('');
return `<p><img src=${content}></p>`; return `<figure><img src="${content}" alt="${figcaption}"/><figcaption>${figcaption}<figcaption/></figure>`;
} }
} }

View File

@ -1,16 +1,10 @@
import { import { AsyncBlock, BaseView } from '@toeverything/framework/virgo';
AsyncBlock, import { Protocol } from '@toeverything/datasource/db-service';
BaseView,
SelectBlock,
getTextHtml,
} from '@toeverything/framework/virgo';
import {
Protocol,
DefaultColumnsValue,
} from '@toeverything/datasource/db-service';
// import { withTreeViewChildren } from '../../utils/with-tree-view-children';
import { defaultTodoProps, NumberedView } from './NumberedView'; import { defaultTodoProps, NumberedView } from './NumberedView';
import { IndentWrapper } from '../../components/IndentWrapper'; import {
Block2HtmlProps,
commonBlock2HtmlContent,
} from '../../utils/commonBlockClip';
export class NumberedBlock extends BaseView { export class NumberedBlock extends BaseView {
public type = Protocol.Block.Type.numbered; public type = Protocol.Block.Type.numbered;
@ -77,14 +71,7 @@ export class NumberedBlock extends BaseView {
return null; return null;
} }
override async block2html(props: Block2HtmlProps) {
override async block2html( return `<ol><li>${await commonBlock2HtmlContent(props)}</li></ol>`;
block: AsyncBlock,
children: SelectBlock[],
generateHtml: (el: any[]) => Promise<string>
): Promise<string> {
let content = getTextHtml(block);
content += await generateHtml(children);
return `<ol><li>${content}</li></ol>`;
} }
} }

View File

@ -1,20 +1,9 @@
import { withRecastBlock } from '@toeverything/components/editor-core'; import { withRecastBlock } from '@toeverything/components/editor-core';
import { import { Protocol } from '@toeverything/datasource/db-service';
Protocol, import { AsyncBlock, BaseView } from '@toeverything/framework/virgo';
DefaultColumnsValue,
} from '@toeverything/datasource/db-service';
import {
AsyncBlock,
BaseView,
ChildrenView,
getTextHtml,
SelectBlock,
} from '@toeverything/framework/virgo';
import { PageView } from './PageView'; import { PageView } from './PageView';
import { Block2HtmlProps } from '../../utils/commonBlockClip';
export const PageChildrenView: (prop: ChildrenView) => JSX.Element = props =>
props.children;
export class PageBlock extends BaseView { export class PageBlock extends BaseView {
type = Protocol.Block.Type.page; type = Protocol.Block.Type.page;
@ -34,13 +23,17 @@ export class PageBlock extends BaseView {
return this.get_decoration<any>(content, 'text')?.value?.[0].text; return this.get_decoration<any>(content, 'text')?.value?.[0].text;
} }
override async block2html( override async block2html({ block, editor, selectInfo }: Block2HtmlProps) {
block: AsyncBlock, const header =
children: SelectBlock[], await editor.clipboard.clipboardUtils.convertTextValue2HtmlBySelectInfo(
generateHtml: (el: any[]) => Promise<string> block,
): Promise<string> { selectInfo
const content = getTextHtml(block); );
const childrenContent = await generateHtml(children); const childrenHtml =
return `<h1>${content}</h1> ${childrenContent}`; await editor.clipboard.clipboardUtils.convertBlock2HtmlBySelectInfos(
block,
selectInfo?.children
);
return `<h1>${header}</h1>${childrenHtml}`;
} }
} }

View File

@ -1,14 +1,13 @@
import { import { Protocol } from '@toeverything/datasource/db-service';
DefaultColumnsValue,
Protocol,
} from '@toeverything/datasource/db-service';
import { import {
AsyncBlock, AsyncBlock,
BaseView, BaseView,
CreateView, CreateView,
getTextHtml,
SelectBlock,
} from '@toeverything/framework/virgo'; } from '@toeverything/framework/virgo';
import {
Block2HtmlProps,
commonBlock2HtmlContent,
} from '../../utils/commonBlockClip';
import { TextView } from './TextView'; import { TextView } from './TextView';
@ -60,14 +59,10 @@ export class QuoteBlock extends BaseView {
return null; return null;
} }
override async block2html( override async block2html(props: Block2HtmlProps) {
block: AsyncBlock, return `<blockquote>${await commonBlock2HtmlContent(
children: SelectBlock[], props
generateHtml: (el: any[]) => Promise<string> )}</blockquote>`;
): Promise<string> {
let content = getTextHtml(block);
content += await generateHtml(children);
return `<blockquote>${content}</blockquote>`;
} }
} }
@ -135,13 +130,7 @@ export class CalloutBlock extends BaseView {
return null; return null;
} }
override async block2html( override async block2html(props: Block2HtmlProps) {
block: AsyncBlock, return `<aside>${await commonBlock2HtmlContent(props)}</aside>`;
children: SelectBlock[],
generateHtml: (el: any[]) => Promise<string>
): Promise<string> {
let content = getTextHtml(block);
content += await generateHtml(children);
return `<aside>${content}</aside>`;
} }
} }

View File

@ -2,16 +2,15 @@ import {
BaseView, BaseView,
CreateView, CreateView,
AsyncBlock, AsyncBlock,
SelectBlock,
getTextHtml,
} from '@toeverything/framework/virgo'; } from '@toeverything/framework/virgo';
import { import { Protocol } from '@toeverything/datasource/db-service';
DefaultColumnsValue,
Protocol,
} from '@toeverything/datasource/db-service';
import { TextView } from './TextView'; import { TextView } from './TextView';
import { getRandomString } from '@toeverything/components/common'; import { getRandomString } from '@toeverything/components/common';
import {
Block2HtmlProps,
commonBlock2HtmlContent,
} from '../../utils/commonBlockClip';
export class TextBlock extends BaseView { export class TextBlock extends BaseView {
type = Protocol.Block.Type.text; type = Protocol.Block.Type.text;
@ -111,14 +110,8 @@ export class TextBlock extends BaseView {
: null; : null;
} }
override async block2html( override async block2html(props: Block2HtmlProps) {
block: AsyncBlock, return `<p>${await commonBlock2HtmlContent(props)}</p>`;
children: SelectBlock[],
generateHtml: (el: any[]) => Promise<string>
): Promise<string> {
let content = getTextHtml(block);
content += await generateHtml(children);
return `<p>${content}</p>`;
} }
} }
@ -168,14 +161,8 @@ export class Heading1Block extends BaseView {
return null; return null;
} }
override async block2html( override async block2html(props: Block2HtmlProps) {
block: AsyncBlock, return `<h1>${await commonBlock2HtmlContent(props)}</h1>`;
children: SelectBlock[],
generateHtml: (el: any[]) => Promise<string>
): Promise<string> {
let content = getTextHtml(block);
content += await generateHtml(children);
return `<h1>${content}</h1>`;
} }
} }
@ -225,14 +212,8 @@ export class Heading2Block extends BaseView {
return null; return null;
} }
override async block2html( override async block2html(props: Block2HtmlProps) {
block: AsyncBlock, return `<h2>${await commonBlock2HtmlContent(props)}</h2>`;
children: SelectBlock[],
generateHtml: (el: any[]) => Promise<string>
): Promise<string> {
let content = getTextHtml(block);
content += await generateHtml(children);
return `<h2>${content}</h2>`;
} }
} }
@ -282,13 +263,7 @@ export class Heading3Block extends BaseView {
return null; return null;
} }
override async block2html( override async block2html(props: Block2HtmlProps) {
block: AsyncBlock, return `<h3>${await commonBlock2HtmlContent(props)}</h3>`;
children: SelectBlock[],
generateHtml: (el: any[]) => Promise<string>
): Promise<string> {
let content = getTextHtml(block);
content += await generateHtml(children);
return `<h3>${content}</h3>`;
} }
} }

View File

@ -1,18 +1,12 @@
import { import { BaseView } from '@toeverything/framework/virgo';
BaseView, import { Protocol } from '@toeverything/datasource/db-service';
AsyncBlock,
SelectBlock,
getTextHtml,
} from '@toeverything/framework/virgo';
// import type { CreateView } from '@toeverything/framework/virgo';
import {
Protocol,
DefaultColumnsValue,
} from '@toeverything/datasource/db-service';
// import { withTreeViewChildren } from '../../utils/with-tree-view-children';
import { withTreeViewChildren } from '../../utils/WithTreeViewChildren'; import { withTreeViewChildren } from '../../utils/WithTreeViewChildren';
import { TodoView, defaultTodoProps } from './TodoView'; import { TodoView, defaultTodoProps } from './TodoView';
import type { TodoAsyncBlock } from './types'; import type { TodoAsyncBlock } from './types';
import {
Block2HtmlProps,
commonBlock2HtmlContent,
} from '../../utils/commonBlockClip';
export class TodoBlock extends BaseView { export class TodoBlock extends BaseView {
type = Protocol.Block.Type.todo; type = Protocol.Block.Type.todo;
@ -78,13 +72,7 @@ export class TodoBlock extends BaseView {
return null; return null;
} }
override async block2html( override async block2html(props: Block2HtmlProps) {
block: AsyncBlock, return `<ul><li>[ ] ${await commonBlock2HtmlContent(props)}</li></ul>`;
children: SelectBlock[],
generateHtml: (el: any[]) => Promise<string>
): Promise<string> {
let content = getTextHtml(block);
content += await generateHtml(children);
return `<ul><li>[ ] ${content}</li></ul>`;
} }
} }

View File

@ -5,6 +5,10 @@ import {
SelectBlock, SelectBlock,
} from '@toeverything/framework/virgo'; } from '@toeverything/framework/virgo';
import { YoutubeView } from './YoutubeView'; import { YoutubeView } from './YoutubeView';
import {
Block2HtmlProps,
commonBlock2HtmlContent,
} from '../../utils/commonBlockClip';
export class YoutubeBlock extends BaseView { export class YoutubeBlock extends BaseView {
public override selectable = true; public override selectable = true;
@ -44,12 +48,8 @@ export class YoutubeBlock extends BaseView {
override async block2Text(block: AsyncBlock, selectInfo: SelectBlock) { override async block2Text(block: AsyncBlock, selectInfo: SelectBlock) {
return block.getProperty('embedLink')?.value ?? ''; return block.getProperty('embedLink')?.value ?? '';
} }
override async block2html( override async block2html({ block }: Block2HtmlProps) {
block: AsyncBlock,
children: SelectBlock[],
generateHtml: (el: any[]) => Promise<string>
): Promise<string> {
const url = block.getProperty('embedLink')?.value; const url = block.getProperty('embedLink')?.value;
return `<p><a src=${url}>${url}</p>`; return `<p><a href="${url}">${url}</a></p>`;
} }
} }

View File

@ -0,0 +1,30 @@
import {
AsyncBlock,
BlockEditor,
SelectBlock,
} from '@toeverything/components/editor-core';
export type Block2HtmlProps = {
editor: BlockEditor;
block: AsyncBlock;
// The selectInfo parameter is not passed when the block is selected in ful, the selectInfo.type is Range
selectInfo?: SelectBlock;
};
export const commonBlock2HtmlContent = async ({
editor,
block,
selectInfo,
}: Block2HtmlProps) => {
const html =
await editor.clipboard.clipboardUtils.convertTextValue2HtmlBySelectInfo(
block,
selectInfo
);
const childrenHtml =
await editor.clipboard.clipboardUtils.convertBlock2HtmlBySelectInfos(
block,
selectInfo?.children
);
return `${html}${childrenHtml}`;
};

View File

@ -153,7 +153,7 @@ export class BlockHelper {
public async getEditableBlockPropertiesBySelectInfo( public async getEditableBlockPropertiesBySelectInfo(
block: AsyncBlock, block: AsyncBlock,
selectInfo: SelectBlock selectInfo?: SelectBlock
) { ) {
const properties = block.getProperties(); const properties = block.getProperties();
if (properties.text.value.length === 0) { if (properties.text.value.length === 0) {
@ -169,13 +169,13 @@ export class BlockHelper {
// Use deepClone method will throw incomprehensible error // Use deepClone method will throw incomprehensible error
let textValue = JSON.parse(JSON.stringify(originTextValue)); let textValue = JSON.parse(JSON.stringify(originTextValue));
if (selectInfo.endInfo) { if (selectInfo?.endInfo) {
textValue = textValue.slice(0, selectInfo.endInfo.arrayIndex + 1); textValue = textValue.slice(0, selectInfo.endInfo.arrayIndex + 1);
textValue[textValue.length - 1].text = text_value[ textValue[textValue.length - 1].text = text_value[
textValue.length - 1 textValue.length - 1
].text.substring(0, selectInfo.endInfo.offset); ].text.substring(0, selectInfo.endInfo.offset);
} }
if (selectInfo.startInfo) { if (selectInfo?.startInfo) {
textValue = textValue.slice(selectInfo.startInfo.arrayIndex); textValue = textValue.slice(selectInfo.startInfo.arrayIndex);
textValue[0].text = textValue[0].text.substring( textValue[0].text = textValue[0].text.substring(
selectInfo.startInfo.offset selectInfo.startInfo.offset

View File

@ -1,31 +1,7 @@
import { Protocol, BlockFlavorKeys } from '@toeverything/datasource/db-service'; import { Protocol, BlockFlavorKeys } from '@toeverything/datasource/db-service';
import { escape } from '@toeverything/utils';
import { Editor } from '../editor'; import { Editor } from '../editor';
import { SelectBlock } from '../selection';
import { ClipBlockInfo } from './types'; import { ClipBlockInfo } from './types';
class DefaultBlockParse {
public static html2block(el: Element): ClipBlockInfo[] | undefined | null {
const tag_name = el.tagName;
if (tag_name === 'DIV' || el instanceof Text) {
return el.textContent?.split('\n').map(str => {
const data = {
text: escape(str),
};
return {
type: 'text',
properties: {
text: { value: [data] },
},
children: [],
};
});
}
return null;
}
}
export default class ClipboardParse { export default class ClipboardParse {
private editor: Editor; private editor: Editor;
private static block_types: BlockFlavorKeys[] = [ private static block_types: BlockFlavorKeys[] = [
@ -82,7 +58,7 @@ export default class ClipboardParse {
constructor(editor: Editor) { constructor(editor: Editor) {
this.editor = editor; this.editor = editor;
this.generate_html = this.generate_html.bind(this); // this.generate_html = this.generate_html.bind(this);
this.parse_dom = this.parse_dom.bind(this); this.parse_dom = this.parse_dom.bind(this);
} }
// TODO: escape // TODO: escape
@ -152,55 +128,6 @@ export default class ClipboardParse {
return blocks; return blocks;
} }
public async generateHtml(): Promise<string> {
const select_info = await this.editor.selectionManager.getSelectInfo();
return await this.generate_html(select_info.blocks);
}
public async page2html(): Promise<string> {
const root_block_id = this.editor.getRootBlockId();
if (!root_block_id) {
return '';
}
const block_info = await this.get_select_info(root_block_id);
return await this.generate_html([block_info]);
}
private async get_select_info(blockId: string) {
const block = await this.editor.getBlockById(blockId);
if (!block) return null;
const block_info: SelectBlock = {
blockId: block.id,
children: [],
};
const children_ids = block.childrenIds;
for (let i = 0; i < children_ids.length; i++) {
block_info.children.push(
await this.get_select_info(children_ids[i])
);
}
return block_info;
}
private async generate_html(selectBlocks: SelectBlock[]): Promise<string> {
let result = '';
for (let i = 0; i < selectBlocks.length; i++) {
const sel_block = selectBlocks[i];
if (!sel_block || !sel_block.blockId) continue;
const block = await this.editor.getBlockById(sel_block.blockId);
if (!block) continue;
const block_utils = this.editor.getView(block.type);
const html = await block_utils.block2html(
block,
sel_block.children,
this.generate_html
);
result += html;
}
return result;
}
public dispose() { public dispose() {
this.editor = null; this.editor = null;
} }

View File

@ -1,5 +1,9 @@
import { Editor } from '../editor'; import { Editor } from '../editor';
import { SelectBlock, SelectInfo } from '@toeverything/components/editor-core'; import {
AsyncBlock,
SelectBlock,
SelectInfo,
} from '@toeverything/components/editor-core';
import { ClipBlockInfo, OFFICE_CLIPBOARD_MIMETYPE } from './types'; import { ClipBlockInfo, OFFICE_CLIPBOARD_MIMETYPE } from './types';
import { Clip } from './clip'; import { Clip } from './clip';
@ -83,4 +87,76 @@ export class ClipboardUtils {
}) })
); );
} }
async convertTextValue2HtmlBySelectInfo(
blockOrBlockId: AsyncBlock | string,
selectBlockInfo?: SelectBlock
) {
const block =
typeof blockOrBlockId === 'string'
? await this._editor.getBlockById(blockOrBlockId)
: blockOrBlockId;
const selectedProperties =
await this._editor.blockHelper.getEditableBlockPropertiesBySelectInfo(
block,
selectBlockInfo
);
return this._editor.blockHelper.convertTextValue2Html(
block.id,
selectedProperties.text.value
);
}
async convertBlock2HtmlBySelectInfos(
blockOrBlockId: AsyncBlock | string,
selectBlockInfos?: SelectBlock[]
) {
if (!selectBlockInfos) {
const block =
typeof blockOrBlockId === 'string'
? await this._editor.getBlockById(blockOrBlockId)
: blockOrBlockId;
const children = await block?.children();
return (
await Promise.all(
children.map(async childBlock => {
const blockView = this._editor.getView(childBlock.type);
return await blockView.block2html({
editor: this._editor,
block: childBlock,
});
})
)
).join('');
}
return (
await Promise.all(
selectBlockInfos.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('');
}
async page2html() {
const rootBlockId = this._editor.getRootBlockId();
if (!rootBlockId) {
return '';
}
const rootBlock = await this._editor.getBlockById(rootBlockId);
const blockView = this._editor.getView(rootBlock.type);
return await blockView.block2html({
editor: this._editor,
block: rootBlock,
});
}
} }

View File

@ -50,62 +50,38 @@ class Copy {
const textClip = await this._getTextClip(); const textClip = await this._getTextClip();
clips.push(textClip); clips.push(textClip);
// const htmlClip = await this._getHtmlClip(); const htmlClip = await this._getHtmlClip();
// clips.push(htmlClip);
const htmlClip = await this._clipboardParse.generateHtml(); clips.push(htmlClip);
htmlClip && // const htmlClip = await this._clipboardParse.generateHtml();
clips.push(new Clip(OFFICE_CLIPBOARD_MIMETYPE.HTML, htmlClip)); // htmlClip &&
// clips.push(new Clip(OFFICE_CLIPBOARD_MIMETYPE.HTML, htmlClip));
return clips; return clips;
} }
// private async _getHtmlClip(): Promise<Clip> { private async _getHtmlClip(): Promise<Clip> {
// const selectInfo: SelectInfo = const selectInfo: SelectInfo =
// await this._editor.selectionManager.getSelectInfo(); await this._editor.selectionManager.getSelectInfo();
//
// if (selectInfo.type === 'Range') { const htmlStr = (
// const html = ( await Promise.all(
// await Promise.all( selectInfo.blocks.map(async selectBlockInfo => {
// selectInfo.blocks.map(async selectBlockInfo => { const block = await this._editor.getBlockById(
// const block = await this._editor.getBlockById( selectBlockInfo.blockId
// selectBlockInfo.blockId );
// ); const blockView = this._editor.getView(block.type);
// const blockView = this._editor.getView(block.type); return await blockView.block2html({
// const block2html = await blockView.block2html({ editor: this._editor,
// editor: this._editor, block,
// block, selectInfo: selectBlockInfo,
// selectInfo: selectBlockInfo, });
// }); })
// )
// if ( ).join('');
// await this._editor.blockHelper.isBlockEditable(
// block return new Clip(OFFICE_CLIPBOARD_MIMETYPE.HTML, htmlStr);
// ) }
// ) {
// 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> { private async _getAffineClip(): Promise<Clip> {
const selectInfo: SelectInfo = const selectInfo: SelectInfo =

View File

@ -502,13 +502,7 @@ export class Editor implements Virgo {
} }
public async page2html(): Promise<string> { public async page2html(): Promise<string> {
return ''; return this.clipboard?.clipboardUtils?.page2html?.();
// const parse = this.clipboard?.getClipboardParse();
// if (!parse) {
// return '';
// }
// const html_str = await parse.page2html();
// return html_str;
} }
dispose() { dispose() {

View File

@ -8,5 +8,5 @@ export { Editor as BlockEditor } from './editor';
export * from './selection'; export * from './selection';
export { BlockDropPlacement, HookType, GroupDirection } from './types'; 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 } from './views/base-view'; export { BaseView } from './views/base-view';
export type { ChildrenView, CreateView } from './views/base-view'; export type { ChildrenView, CreateView } from './views/base-view';

View File

@ -135,13 +135,6 @@ export abstract class BaseView {
return null; return null;
} }
async block2html(
block: AsyncBlock,
children: SelectBlock[],
generateHtml: (el: any[]) => Promise<string>
): Promise<string> {
return '';
}
async block2Text( async block2Text(
block: AsyncBlock, block: AsyncBlock,
// The selectInfo parameter is not passed when the block is selected in ful, the selectInfo.type is Range // The selectInfo parameter is not passed when the block is selected in ful, the selectInfo.type is Range
@ -151,45 +144,12 @@ export abstract class BaseView {
} }
// TODO: Try using new methods // TODO: Try using new methods
// async block2html2(props: { async block2html(props: {
// editor: Editor; editor: Editor;
// block: AsyncBlock; block: AsyncBlock;
// // The selectInfo parameter is not passed when the block is selected in ful, the selectInfo.type is Range // The selectInfo parameter is not passed when the block is selected in ful, the selectInfo.type is Range
// selectInfo?: SelectBlock; selectInfo?: SelectBlock;
// }) { }) {
// return ''; return '';
// } }
} }
export const getTextHtml = (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);
};

View File

@ -153,9 +153,7 @@ function PageSettingPortal() {
const handleExportHtml = async () => { const handleExportHtml = async () => {
//@ts-ignore //@ts-ignore
const htmlContent = await virgo.clipboard const htmlContent = await virgo.clipboard.clipboardUtils.page2html();
.getClipboardParse()
.page2html();
const htmlTitle = pageBlock.title; const htmlTitle = pageBlock.title;
FileExporter.exportHtml(htmlTitle, htmlContent); FileExporter.exportHtml(htmlTitle, htmlContent);
@ -163,9 +161,7 @@ function PageSettingPortal() {
const handleExportMarkdown = async () => { const handleExportMarkdown = async () => {
//@ts-ignore //@ts-ignore
const htmlContent = await virgo.clipboard const htmlContent = await virgo.clipboard.clipboardUtils.page2html();
.getClipboardParse()
.page2html();
const htmlTitle = pageBlock.title; const htmlTitle = pageBlock.title;
FileExporter.exportMarkdown(htmlTitle, htmlContent); FileExporter.exportMarkdown(htmlTitle, htmlContent);
}; };

View File

@ -1,5 +1,4 @@
import { createEditor } from '@toeverything/components/affine-editor'; import { createEditor } from '@toeverything/components/affine-editor';
import { ClipboardParse } from '@toeverything/components/editor-core';
import { fileExporter } from './file-exporter'; import { fileExporter } from './file-exporter';
interface CreateClipboardParseProps { interface CreateClipboardParseProps {
@ -7,13 +6,12 @@ interface CreateClipboardParseProps {
rootBlockId: string; rootBlockId: string;
} }
const createClipboardParse = ({ const createClipboardUtils = ({
workspaceId, workspaceId,
rootBlockId, rootBlockId,
}: CreateClipboardParseProps) => { }: CreateClipboardParseProps) => {
const editor = createEditor(workspaceId, rootBlockId); const editor = createEditor(workspaceId, rootBlockId);
return editor.clipboard.clipboardUtils;
return new ClipboardParse(editor);
}; };
interface ExportHandlerProps extends CreateClipboardParseProps { interface ExportHandlerProps extends CreateClipboardParseProps {
@ -25,9 +23,8 @@ export const exportHtml = async ({
rootBlockId, rootBlockId,
title, title,
}: ExportHandlerProps) => { }: ExportHandlerProps) => {
const clipboardParse = createClipboardParse({ workspaceId, rootBlockId }); const clipboardUtils = createClipboardUtils({ workspaceId, rootBlockId });
const htmlContent = await clipboardParse.page2html(); fileExporter.exportHtml(title, await clipboardUtils.page2html());
fileExporter.exportHtml(title, htmlContent);
}; };
export const exportMarkdown = async ({ export const exportMarkdown = async ({
@ -35,7 +32,6 @@ export const exportMarkdown = async ({
rootBlockId, rootBlockId,
title, title,
}: ExportHandlerProps) => { }: ExportHandlerProps) => {
const clipboardParse = createClipboardParse({ workspaceId, rootBlockId }); const clipboardUtils = createClipboardUtils({ workspaceId, rootBlockId });
const htmlContent = await clipboardParse.page2html(); fileExporter.exportMarkdown(title, await clipboardUtils.page2html());
fileExporter.exportMarkdown(title, htmlContent);
}; };