New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@blocksuite/editor

Package Overview
Dependencies
Maintainers
5
Versions
634
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@blocksuite/editor - npm Package Compare versions

Comparing version 0.3.1-20230104134918-4a6cec7 to 0.3.1-20230106002207-33202f0

10

dist/managers/clipboard/content-parser/index.d.ts
import { Signal } from '@blocksuite/store';
import type { OpenBlockInfo, EditorContainer, SelectedBlock } from '../../../index.js';
type ParseHtml2BlockFunc = (...args: any[]) => OpenBlockInfo[] | null;
import type { EditorContainer, OpenBlockInfo, SelectedBlock } from '../../../index.js';
type ParseHtml2BlockFunc = (...args: any[]) => Promise<OpenBlockInfo[] | null>;
export declare class ContentParser {

@@ -10,3 +10,3 @@ private _editor;

private _parsers;
private _parseHtml;
private _htmlParser;
constructor(editor: EditorContainer);

@@ -17,4 +17,4 @@ onExportHtml(): void;

block2Text(blocks: SelectedBlock[]): string;
htmlText2Block(html: string): OpenBlockInfo[];
markdown2Block(text: string): OpenBlockInfo[];
htmlText2Block(html: string): Promise<OpenBlockInfo[]>;
markdown2Block(text: string): Promise<OpenBlockInfo[]>;
registerParserHtmlText2Block(name: string, func: ParseHtml2BlockFunc): void;

@@ -21,0 +21,0 @@ getParserHtmlText2Block(name: string): ParseHtml2BlockFunc;

import { marked } from 'marked';
import { Signal } from '@blocksuite/store';
import { FileExporter } from '../../file-exporter/file-exporter.js';
import { ParserHtml } from './parse-html.js';
import { HtmlParser } from './parse-html.js';
export class ContentParser {

@@ -12,4 +12,4 @@ constructor(editor) {

this._editor = editor;
this._parseHtml = new ParserHtml(this);
this._parseHtml.registerParsers();
this._htmlParser = new HtmlParser(this, this._editor);
this._htmlParser.registerParsers();
}

@@ -43,3 +43,3 @@ onExportHtml() {

}
htmlText2Block(html) {
async htmlText2Block(html) {
const htmlEl = document.createElement('html');

@@ -51,3 +51,3 @@ htmlEl.innerHTML = html;

}
markdown2Block(text) {
async markdown2Block(text) {
const underline = {

@@ -76,3 +76,26 @@ name: 'underline',

};
marked.use({ extensions: [underline] });
const inlineCode = {
name: 'inlineCode',
level: 'inline',
start(src) {
return src.indexOf('`');
},
tokenizer(src) {
const rule = /^(?:`)(`{2,}?|[^`]+)(?:`)$/g;
const match = rule.exec(src);
if (match) {
return {
type: 'inlineCode',
raw: match[0],
text: match[1].trim(), // You can add additional properties to your tokens to pass along to the renderer
};
}
return;
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
renderer(token) {
return `<code>${token.text}</code>`;
},
};
marked.use({ extensions: [underline, inlineCode] });
const md2html = marked.parse(text);

@@ -130,6 +153,6 @@ return this.htmlText2Block(md2html);

}
_convertHtml2Blocks(element) {
return Array.from(element.children)
.map(childElement => {
const clipBlockInfos = this.getParserHtmlText2Block('nodeParser')?.(childElement) || [];
async _convertHtml2Blocks(element) {
const openBlockPromises = Array.from(element.children).map(async (childElement) => {
const clipBlockInfos = (await this.getParserHtmlText2Block('nodeParser')?.(childElement)) ||
[];
if (clipBlockInfos && clipBlockInfos.length) {

@@ -139,7 +162,10 @@ return clipBlockInfos;

return [];
})
.flat()
.filter(v => v);
});
const results = [];
for (const item of openBlockPromises) {
results.push(await item);
}
return results.flat().filter(v => v);
}
}
//# sourceMappingURL=index.js.map
import type { ContentParser } from './index.js';
export declare class ParserHtml {
import type { EditorContainer } from '../../../components/index.js';
export declare class HtmlParser {
private _contentParser;
constructor(contentParser: ContentParser);
private _editor;
constructor(contentParser: ContentParser, editor: EditorContainer);
registerParsers(): void;
private _nodePaser;
private _nodeParser;
private _commonParser;

@@ -12,3 +14,5 @@ private _commonHTML2Block;

private _blockQuoteParser;
private _codeBlockParser;
private _embedItemParser;
}
//# sourceMappingURL=parse-html.d.ts.map

@@ -0,1 +1,2 @@

import { assertExists } from '@blocksuite/blocks';
// There are these uncommon in-line tags that have not been added

@@ -22,103 +23,241 @@ // tt, acronym, dfn, kbd, samp, var, bdo, br, img, map, object, q, script, sub, sup, button, select, TEXTAREA

];
export class ParserHtml {
constructor(contentParser) {
this._contentParser = contentParser;
}
registerParsers() {
this._contentParser.registerParserHtmlText2Block('nodeParser', this._nodePaser.bind(this));
this._contentParser.registerParserHtmlText2Block('commonParser', this._commonParser.bind(this));
this._contentParser.registerParserHtmlText2Block('listItemParser', this._listItemParser.bind(this));
this._contentParser.registerParserHtmlText2Block('blockQuoteParser', this._blockQuoteParser.bind(this));
}
// TODO parse children block
_nodePaser(node) {
let result;
// custom parser
result =
this._contentParser.getParserHtmlText2Block('customNodeParser')?.(node);
if (result && result.length > 0) {
return result;
}
const tagName = node.tagName;
if (node instanceof Text || INLINE_TAGS.includes(tagName)) {
result = this._contentParser.getParserHtmlText2Block('commonParser')?.({
element: node,
flavour: 'affine:paragraph',
type: 'text',
});
}
else {
switch (tagName) {
case 'H1':
case 'H2':
case 'H3':
case 'H4':
case 'H5':
case 'H6':
result = this._contentParser.getParserHtmlText2Block('commonParser')?.({
element: node,
flavour: 'affine:paragraph',
type: tagName.toLowerCase(),
});
break;
case 'BLOCKQUOTE':
result =
this._contentParser.getParserHtmlText2Block('blockQuoteParser')?.(node);
break;
case 'P':
if (node.firstChild instanceof Text &&
(node.firstChild.textContent?.startsWith('[] ') ||
node.firstChild.textContent?.startsWith('[ ] ') ||
node.firstChild.textContent?.startsWith('[x] '))) {
result =
this._contentParser.getParserHtmlText2Block('listItemParser')?.(node);
}
else {
result = this._contentParser.getParserHtmlText2Block('commonParser')?.({
export class HtmlParser {
constructor(contentParser, editor) {
// TODO parse children block
this._nodeParser = async (node) => {
let result;
// custom parser
result = await this._contentParser.getParserHtmlText2Block('customNodeParser')?.(node);
if (result && result.length > 0) {
return result;
}
const tagName = node.tagName;
if (node instanceof Text || INLINE_TAGS.includes(tagName)) {
result = await this._contentParser.getParserHtmlText2Block('commonParser')?.({
element: node,
flavour: 'affine:paragraph',
type: 'text',
});
}
else {
switch (tagName) {
case 'H1':
case 'H2':
case 'H3':
case 'H4':
case 'H5':
case 'H6':
result = await this._contentParser.getParserHtmlText2Block('commonParser')?.({
element: node,
flavour: 'affine:paragraph',
type: tagName.toLowerCase(),
});
break;
case 'BLOCKQUOTE':
result = await this._contentParser.getParserHtmlText2Block('blockQuoteParser')?.(node);
break;
case 'P':
if (node.firstChild instanceof Text &&
(node.firstChild.textContent?.startsWith('[] ') ||
node.firstChild.textContent?.startsWith('[ ] ') ||
node.firstChild.textContent?.startsWith('[x] '))) {
result = await this._contentParser.getParserHtmlText2Block('listItemParser')?.(node);
}
else if (node.firstChild instanceof HTMLImageElement) {
result = await this._contentParser.getParserHtmlText2Block('embedItemParser')?.(node.firstChild);
}
else {
result = await this._contentParser.getParserHtmlText2Block('commonParser')?.({
element: node,
flavour: 'affine:paragraph',
type: 'text',
});
}
break;
case 'DIV':
result = await this._contentParser.getParserHtmlText2Block('commonParser')?.({
element: node,
flavour: 'affine:paragraph',
type: 'text',
});
break;
case 'LI':
result = await this._contentParser.getParserHtmlText2Block('listItemParser')?.(node);
break;
case 'HR':
result = await this._contentParser.getParserHtmlText2Block('commonParser')?.({
element: node,
flavour: 'affine:divider',
});
break;
case 'PRE':
result = await this._contentParser.getParserHtmlText2Block('codeBlockParser')?.(node);
break;
case 'IMG':
{
result = await this._contentParser.getParserHtmlText2Block('embedItemParser')?.(node);
}
break;
default:
break;
}
}
if (result && result.length > 0) {
return result;
}
const openBlockPromises = Array.from(node.children).map(async (childElement) => {
const clipBlockInfos = (await this._contentParser.getParserHtmlText2Block('nodeParser')?.(childElement)) || [];
if (clipBlockInfos && clipBlockInfos.length) {
return clipBlockInfos;
}
return [];
});
const results = [];
for (const item of openBlockPromises) {
results.push(await item);
}
return results.flat().filter(v => v);
};
this._commonParser = async ({ element, flavour, type, checked, ignoreEmptyElement = true, }) => {
const res = await this._commonHTML2Block(element, flavour, type, checked, ignoreEmptyElement);
return res ? [res] : null;
};
this._listItemParser = async (element) => {
const tagName = element.parentElement?.tagName;
let type = tagName === 'OL' ? 'numbered' : 'bulleted';
let checked;
let inputEl;
if ((inputEl = element.firstElementChild)?.tagName === 'INPUT' ||
(inputEl = element.firstElementChild?.firstElementChild)?.tagName ===
'INPUT') {
type = 'todo';
checked = inputEl?.getAttribute('checked') !== null;
}
if (element.firstChild instanceof Text) {
if (element.firstChild.textContent?.startsWith('[] ')) {
element.firstChild.textContent =
element.firstChild.textContent.slice(3);
type = 'todo';
checked = false;
}
else if (element.firstChild.textContent?.startsWith('[ ] ')) {
element.firstChild.textContent =
element.firstChild.textContent.slice(4);
type = 'todo';
checked = false;
}
else if (element.firstChild.textContent?.startsWith('[x] ')) {
element.firstChild.textContent =
element.firstChild.textContent.slice(4);
type = 'todo';
checked = true;
}
}
const result = this._contentParser.getParserHtmlText2Block('commonParser')?.({
element: element,
flavour: 'affine:list',
type: type,
checked: checked,
});
return result;
};
this._blockQuoteParser = async (element) => {
const getText = (list) => {
const result = [];
list.forEach(item => {
const texts = item.text.filter(textItem => textItem.insert);
if (result.length > 0 && texts.length > 0) {
result.push({ insert: '\n' });
}
break;
case 'DIV':
result = this._contentParser.getParserHtmlText2Block('commonParser')?.({
element: node,
flavour: 'affine:paragraph',
type: 'text',
});
break;
case 'LI':
result =
this._contentParser.getParserHtmlText2Block('listItemParser')?.(node);
break;
case 'HR':
result = this._contentParser.getParserHtmlText2Block('commonParser')?.({
element: node,
flavour: 'affine:divider',
});
break;
default:
break;
result.push(...texts);
const childTexts = getText(item.children);
if (result.length > 0 && childTexts.length > 0) {
result.push({ insert: '\n' });
}
result.push(...childTexts);
});
return result;
};
const commonResult = await this._contentParser.getParserHtmlText2Block('commonParser')?.({
element: element,
flavour: 'affine:paragraph',
type: 'text',
});
if (!commonResult) {
return null;
}
}
if (result && result.length > 0) {
return [
{
flavour: 'affine:paragraph',
type: 'quote',
text: getText(commonResult),
children: [],
},
];
};
this._codeBlockParser = async (element) => {
// code block doesn't parse other nested Markdown syntax, thus is always one layer deep, example:
// <pre><code class="language-typescript">code content</code></pre>
const content = element.firstChild?.textContent || '';
const language = element.children[0]?.getAttribute('class')?.split('-')[1] || 'JavaScript';
return [
{
flavour: 'affine:code',
type: 'code',
text: [
{
insert: content,
attributes: {
'code-block': true,
},
},
],
children: [],
language,
},
];
};
this._embedItemParser = async (element) => {
let result = [];
if (element instanceof HTMLImageElement) {
const imgUrl = element.src;
let resp;
try {
resp = await fetch(imgUrl);
}
catch (error) {
console.error(error);
return result;
}
const imgBlob = await resp.blob();
if (!imgBlob.type.startsWith('image/')) {
return result;
}
const storage = await this._editor.page.blobs;
assertExists(storage);
const id = await storage.set(imgBlob);
result = [
{
flavour: 'affine:embed',
type: 'image',
sourceId: id,
children: [],
text: [{ insert: '' }],
},
];
}
return result;
}
return Array.from(node.children)
.map(childElement => {
const clipBlockInfos = this._contentParser.getParserHtmlText2Block('nodeParser')?.(childElement) || [];
if (clipBlockInfos && clipBlockInfos.length) {
return clipBlockInfos;
}
return [];
})
.flat()
.filter(v => v);
};
this._contentParser = contentParser;
this._editor = editor;
}
_commonParser({ element, flavour, type, checked, ignoreEmptyElement = true, }) {
const res = this._commonHTML2Block(element, flavour, type, checked, ignoreEmptyElement);
return res ? [res] : null;
registerParsers() {
this._contentParser.registerParserHtmlText2Block('nodeParser', this._nodeParser);
this._contentParser.registerParserHtmlText2Block('commonParser', this._commonParser);
this._contentParser.registerParserHtmlText2Block('listItemParser', this._listItemParser);
this._contentParser.registerParserHtmlText2Block('blockQuoteParser', this._blockQuoteParser);
this._contentParser.registerParserHtmlText2Block('codeBlockParser', this._codeBlockParser);
this._contentParser.registerParserHtmlText2Block('embedItemParser', this._embedItemParser);
}
_commonHTML2Block(element, flavour, type, checked, ignoreEmptyElement = true) {
async _commonHTML2Block(element, flavour, type, checked, ignoreEmptyElement = true) {
const childNodes = element.childNodes;

@@ -144,3 +283,3 @@ let isChildNode = false;

if (node instanceof Element) {
const childNode = this._nodePaser(node);
const childNode = await this._nodeParser(node);
childNode && children.push(...childNode);

@@ -192,75 +331,2 @@ }

}
_listItemParser(element) {
const tagName = element.parentElement?.tagName;
let type = tagName === 'OL' ? 'numbered' : 'bulleted';
let checked;
let inputEl;
if ((inputEl = element.firstElementChild)?.tagName === 'INPUT' ||
(inputEl = element.firstElementChild?.firstElementChild)?.tagName ===
'INPUT') {
type = 'todo';
checked = inputEl?.getAttribute('checked') !== null;
}
if (element.firstChild instanceof Text) {
if (element.firstChild.textContent?.startsWith('[] ')) {
element.firstChild.textContent =
element.firstChild.textContent.slice(3);
type = 'todo';
checked = false;
}
else if (element.firstChild.textContent?.startsWith('[ ] ')) {
element.firstChild.textContent =
element.firstChild.textContent.slice(4);
type = 'todo';
checked = false;
}
else if (element.firstChild.textContent?.startsWith('[x] ')) {
element.firstChild.textContent =
element.firstChild.textContent.slice(4);
type = 'todo';
checked = true;
}
}
const result = this._contentParser.getParserHtmlText2Block('commonParser')?.({
element: element,
flavour: 'affine:list',
type: type,
checked: checked,
});
return result;
}
_blockQuoteParser(element) {
const getText = (list) => {
const result = [];
list.forEach(item => {
const texts = item.text.filter(textItem => textItem.insert);
if (result.length > 0 && texts.length > 0) {
result.push({ insert: '\n' });
}
result.push(...texts);
const childTexts = getText(item.children);
if (result.length > 0 && childTexts.length > 0) {
result.push({ insert: '\n' });
}
result.push(...childTexts);
});
return result;
};
const commonResult = this._contentParser.getParserHtmlText2Block('commonParser')?.({
element: element,
flavour: 'affine:paragraph',
type: 'text',
});
if (!commonResult) {
return null;
}
return [
{
flavour: 'affine:paragraph',
type: 'quote',
text: getText(commonResult),
children: [],
},
];
}
}

@@ -267,0 +333,0 @@ const getIsLink = (htmlElement) => {

@@ -13,5 +13,5 @@ import type { EditorContainer } from '../../components/index.js';

get clipboardTarget(): HTMLElement;
importMarkdown(text: string, insertPositionId: string): void;
importMarkdown(text: string, insertPositionId: string): Promise<void>;
dispose(): void;
}
//# sourceMappingURL=index.d.ts.map

@@ -25,4 +25,4 @@ import { ClipboardEventDispatcher } from './event-dispatcher.js';

}
importMarkdown(text, insertPositionId) {
const blocks = this._editor.contentParser.markdown2Block(text);
async importMarkdown(text, insertPositionId) {
const blocks = await this._editor.contentParser.markdown2Block(text);
this._paste.insertBlocks(blocks, {

@@ -29,0 +29,0 @@ type: 'Block',

@@ -83,3 +83,3 @@ import { MarkdownUtils } from './markdown-utils.js';

if (shouldConvertMarkdown) {
return this._editor.contentParser.markdown2Block(textClipData);
return await this._editor.contentParser.markdown2Block(textClipData);
}

@@ -157,3 +157,3 @@ return this._editor.contentParser.text2blocks(textClipData);

if (selectedBlock && !matchFlavours(selectedBlock, ['affine:page'])) {
const endIndex = lastBlock.endPos || selectedBlock?.text?.length || 0;
const endIndex = lastBlock.endPos ?? (selectedBlock?.text?.length || 0);
const insertTexts = blocks[0].text;

@@ -245,2 +245,3 @@ const insertLen = insertTexts.reduce((len, value) => {

height: block.height,
language: block.language,
};

@@ -247,0 +248,0 @@ const id = this._editor.page.addBlock(blockProps, parent, index + i);

@@ -36,3 +36,4 @@ export declare enum CLIPBOARD_MIMETYPE {

height?: number;
language?: string;
};
//# sourceMappingURL=types.d.ts.map
{
"name": "@blocksuite/editor",
"version": "0.3.1-20230104134918-4a6cec7",
"version": "0.3.1-20230106002207-33202f0",
"description": "Default BlockSuite-based editor built for AFFiNE.",

@@ -11,4 +11,4 @@ "main": "dist/index.js",

"dependencies": {
"@blocksuite/blocks": "0.3.1-20230104134918-4a6cec7",
"@blocksuite/store": "0.3.1-20230104134918-4a6cec7",
"@blocksuite/blocks": "0.3.1-20230106002207-33202f0",
"@blocksuite/store": "0.3.1-20230106002207-33202f0",
"lit": "^2.5.0",

@@ -15,0 +15,0 @@ "marked": "^4.2.5",

@@ -5,11 +5,11 @@ import { marked } from 'marked';

import type {
EditorContainer,
OpenBlockInfo,
EditorContainer,
SelectedBlock,
} from '../../../index.js';
import { FileExporter } from '../../file-exporter/file-exporter.js';
import { ParserHtml } from './parse-html.js';
import { HtmlParser } from './parse-html.js';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type ParseHtml2BlockFunc = (...args: any[]) => OpenBlockInfo[] | null;
type ParseHtml2BlockFunc = (...args: any[]) => Promise<OpenBlockInfo[] | null>;

@@ -22,7 +22,8 @@ export class ContentParser {

private _parsers: Record<string, ParseHtml2BlockFunc> = {};
private _parseHtml: ParserHtml;
private _htmlParser: HtmlParser;
constructor(editor: EditorContainer) {
this._editor = editor;
this._parseHtml = new ParserHtml(this);
this._parseHtml.registerParsers();
this._htmlParser = new HtmlParser(this, this._editor);
this._htmlParser.registerParsers();
}

@@ -71,3 +72,3 @@

public htmlText2Block(html: string): OpenBlockInfo[] {
public async htmlText2Block(html: string): Promise<OpenBlockInfo[]> {
const htmlEl = document.createElement('html');

@@ -80,3 +81,3 @@ htmlEl.innerHTML = html;

public markdown2Block(text: string): OpenBlockInfo[] {
public async markdown2Block(text: string): Promise<OpenBlockInfo[]> {
const underline = {

@@ -105,3 +106,26 @@ name: 'underline',

};
marked.use({ extensions: [underline] });
const inlineCode = {
name: 'inlineCode',
level: 'inline',
start(src: string) {
return src.indexOf('`');
},
tokenizer(src: string) {
const rule = /^(?:`)(`{2,}?|[^`]+)(?:`)$/g;
const match = rule.exec(src);
if (match) {
return {
type: 'inlineCode',
raw: match[0], // This is the text that you want your token to consume from the source
text: match[1].trim(), // You can add additional properties to your tokens to pass along to the renderer
};
}
return;
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
renderer(token: any) {
return `<code>${token.text}</code>`;
},
};
marked.use({ extensions: [underline, inlineCode] });
const md2html = marked.parse(text);

@@ -193,8 +217,10 @@ return this.htmlText2Block(md2html);

private _convertHtml2Blocks(element: Element): OpenBlockInfo[] {
return Array.from(element.children)
.map(childElement => {
private async _convertHtml2Blocks(
element: Element
): Promise<OpenBlockInfo[]> {
const openBlockPromises = Array.from(element.children).map(
async childElement => {
const clipBlockInfos =
this.getParserHtmlText2Block('nodeParser')?.(childElement) || [];
(await this.getParserHtmlText2Block('nodeParser')?.(childElement)) ||
[];
if (clipBlockInfos && clipBlockInfos.length) {

@@ -204,6 +230,12 @@ return clipBlockInfos;

return [];
})
.flat()
.filter(v => v);
}
);
const results: Array<OpenBlockInfo[]> = [];
for (const item of openBlockPromises) {
results.push(await item);
}
return results.flat().filter(v => v);
}
}
import type { ContentParser } from './index.js';
import type { OpenBlockInfo } from '../types.js';
import type { EditorContainer } from '../../../components/index.js';
import { assertExists } from '@blocksuite/blocks';

@@ -26,6 +28,9 @@ // There are these uncommon in-line tags that have not been added

export class ParserHtml {
export class HtmlParser {
private _contentParser: ContentParser;
constructor(contentParser: ContentParser) {
private _editor: EditorContainer;
constructor(contentParser: ContentParser, editor: EditorContainer) {
this._contentParser = contentParser;
this._editor = editor;
}

@@ -36,23 +41,35 @@

'nodeParser',
this._nodePaser.bind(this)
this._nodeParser
);
this._contentParser.registerParserHtmlText2Block(
'commonParser',
this._commonParser.bind(this)
this._commonParser
);
this._contentParser.registerParserHtmlText2Block(
'listItemParser',
this._listItemParser.bind(this)
this._listItemParser
);
this._contentParser.registerParserHtmlText2Block(
'blockQuoteParser',
this._blockQuoteParser.bind(this)
this._blockQuoteParser
);
this._contentParser.registerParserHtmlText2Block(
'codeBlockParser',
this._codeBlockParser
);
this._contentParser.registerParserHtmlText2Block(
'embedItemParser',
this._embedItemParser
);
}
// TODO parse children block
private _nodePaser(node: Element): OpenBlockInfo[] | null {
private _nodeParser = async (
node: Element
): Promise<OpenBlockInfo[] | null> => {
let result;
// custom parser
result =
this._contentParser.getParserHtmlText2Block('customNodeParser')?.(node);
result = await this._contentParser.getParserHtmlText2Block(
'customNodeParser'
)?.(node);
if (result && result.length > 0) {

@@ -64,3 +81,5 @@ return result;

if (node instanceof Text || INLINE_TAGS.includes(tagName)) {
result = this._contentParser.getParserHtmlText2Block('commonParser')?.({
result = await this._contentParser.getParserHtmlText2Block(
'commonParser'
)?.({
element: node,

@@ -78,3 +97,3 @@ flavour: 'affine:paragraph',

case 'H6':
result = this._contentParser.getParserHtmlText2Block(
result = await this._contentParser.getParserHtmlText2Block(
'commonParser'

@@ -88,6 +107,5 @@ )?.({

case 'BLOCKQUOTE':
result =
this._contentParser.getParserHtmlText2Block('blockQuoteParser')?.(
node
);
result = await this._contentParser.getParserHtmlText2Block(
'blockQuoteParser'
)?.(node);
break;

@@ -101,8 +119,11 @@ case 'P':

) {
result =
this._contentParser.getParserHtmlText2Block('listItemParser')?.(
node
);
result = await this._contentParser.getParserHtmlText2Block(
'listItemParser'
)?.(node);
} else if (node.firstChild instanceof HTMLImageElement) {
result = await this._contentParser.getParserHtmlText2Block(
'embedItemParser'
)?.(node.firstChild);
} else {
result = this._contentParser.getParserHtmlText2Block(
result = await this._contentParser.getParserHtmlText2Block(
'commonParser'

@@ -117,3 +138,3 @@ )?.({

case 'DIV':
result = this._contentParser.getParserHtmlText2Block(
result = await this._contentParser.getParserHtmlText2Block(
'commonParser'

@@ -127,9 +148,8 @@ )?.({

case 'LI':
result =
this._contentParser.getParserHtmlText2Block('listItemParser')?.(
node
);
result = await this._contentParser.getParserHtmlText2Block(
'listItemParser'
)?.(node);
break;
case 'HR':
result = this._contentParser.getParserHtmlText2Block(
result = await this._contentParser.getParserHtmlText2Block(
'commonParser'

@@ -141,2 +161,14 @@ )?.({

break;
case 'PRE':
result = await this._contentParser.getParserHtmlText2Block(
'codeBlockParser'
)?.(node);
break;
case 'IMG':
{
result = await this._contentParser.getParserHtmlText2Block(
'embedItemParser'
)?.(node);
}
break;
default:

@@ -150,8 +182,8 @@ break;

}
return Array.from(node.children)
.map(childElement => {
const openBlockPromises = Array.from(node.children).map(
async childElement => {
const clipBlockInfos =
this._contentParser.getParserHtmlText2Block('nodeParser')?.(
(await this._contentParser.getParserHtmlText2Block('nodeParser')?.(
childElement
) || [];
)) || [];

@@ -162,8 +194,13 @@ if (clipBlockInfos && clipBlockInfos.length) {

return [];
})
.flat()
.filter(v => v);
}
}
);
private _commonParser({
const results: Array<OpenBlockInfo[]> = [];
for (const item of openBlockPromises) {
results.push(await item);
}
return results.flat().filter(v => v);
};
private _commonParser = async ({
element,

@@ -180,4 +217,4 @@ flavour,

ignoreEmptyElement?: boolean;
}): OpenBlockInfo[] | null {
const res = this._commonHTML2Block(
}): Promise<OpenBlockInfo[] | null> => {
const res = await this._commonHTML2Block(
element,

@@ -190,5 +227,5 @@ flavour,

return res ? [res] : null;
}
};
private _commonHTML2Block(
private async _commonHTML2Block(
element: Element,

@@ -199,3 +236,3 @@ flavour: string,

ignoreEmptyElement = true
): OpenBlockInfo | null {
): Promise<OpenBlockInfo | null> {
const childNodes = element.childNodes;

@@ -224,3 +261,3 @@ let isChildNode = false;

if (node instanceof Element) {
const childNode = this._nodePaser(node);
const childNode = await this._nodeParser(node);
childNode && children.push(...childNode);

@@ -285,3 +322,5 @@ }

private _listItemParser(element: Element): OpenBlockInfo[] | null {
private _listItemParser = async (
element: Element
): Promise<OpenBlockInfo[] | null> => {
const tagName = element.parentElement?.tagName;

@@ -326,5 +365,7 @@ let type = tagName === 'OL' ? 'numbered' : 'bulleted';

return result;
}
};
private _blockQuoteParser(element: Element): OpenBlockInfo[] | null {
private _blockQuoteParser = async (
element: Element
): Promise<OpenBlockInfo[] | null> => {
const getText = (list: OpenBlockInfo[]): Record<string, unknown>[] => {

@@ -350,3 +391,3 @@ const result: Record<string, unknown>[] = [];

const commonResult = this._contentParser.getParserHtmlText2Block(
const commonResult = await this._contentParser.getParserHtmlText2Block(
'commonParser'

@@ -370,3 +411,63 @@ )?.({

];
}
};
private _codeBlockParser = async (
element: Element
): Promise<OpenBlockInfo[] | null> => {
// code block doesn't parse other nested Markdown syntax, thus is always one layer deep, example:
// <pre><code class="language-typescript">code content</code></pre>
const content = element.firstChild?.textContent || '';
const language =
element.children[0]?.getAttribute('class')?.split('-')[1] || 'JavaScript';
return [
{
flavour: 'affine:code',
type: 'code',
text: [
{
insert: content,
attributes: {
'code-block': true,
},
},
],
children: [],
language,
},
];
};
private _embedItemParser = async (
element: Element
): Promise<OpenBlockInfo[] | null> => {
let result: OpenBlockInfo[] | null = [];
if (element instanceof HTMLImageElement) {
const imgUrl = (element as HTMLImageElement).src;
let resp;
try {
resp = await fetch(imgUrl);
} catch (error) {
console.error(error);
return result;
}
const imgBlob = await resp.blob();
if (!imgBlob.type.startsWith('image/')) {
return result;
}
const storage = await this._editor.page.blobs;
assertExists(storage);
const id = await storage.set(imgBlob);
result = [
{
flavour: 'affine:embed',
type: 'image',
sourceId: id,
children: [],
text: [{ insert: '' }],
},
];
}
return result;
};
}

@@ -373,0 +474,0 @@

@@ -43,4 +43,4 @@ import type { EditorContainer } from '../../components/index.js';

public importMarkdown(text: string, insertPositionId: string) {
const blocks = this._editor.contentParser.markdown2Block(text);
public async importMarkdown(text: string, insertPositionId: string) {
const blocks = await this._editor.contentParser.markdown2Block(text);
this._paste.insertBlocks(blocks, {

@@ -47,0 +47,0 @@ type: 'Block',

@@ -121,3 +121,3 @@ import type { BaseBlockModel } from '@blocksuite/store';

if (shouldConvertMarkdown) {
return this._editor.contentParser.markdown2Block(textClipData);
return await this._editor.contentParser.markdown2Block(textClipData);
}

@@ -213,3 +213,3 @@

if (selectedBlock && !matchFlavours(selectedBlock, ['affine:page'])) {
const endIndex = lastBlock.endPos || selectedBlock?.text?.length || 0;
const endIndex = lastBlock.endPos ?? (selectedBlock?.text?.length || 0);
const insertTexts = blocks[0].text;

@@ -324,2 +324,3 @@ const insertLen = insertTexts.reduce(

height: block.height,
language: block.language,
};

@@ -326,0 +327,0 @@ const id = this._editor.page.addBlock(blockProps, parent, index + i);

@@ -39,2 +39,3 @@ export enum CLIPBOARD_MIMETYPE {

height?: number;
language?: string;
};

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc