@blocksuite/editor
Advanced tools
Comparing version 0.2.4 to 0.2.5
@@ -105,2 +105,4 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
height: 100%; | ||
overflow-y: scroll; | ||
position: relative; | ||
} | ||
@@ -107,0 +109,0 @@ </style> |
@@ -89,6 +89,2 @@ import { Slot } from '@blocksuite/store'; | ||
} | ||
// TODO Handling different block by extension | ||
let text = model?.text?.toString() || ''; | ||
const end = selectedBlock.endPos ? selectedBlock.endPos : text.length; | ||
text = text.slice(selectedBlock.startPos || 0, end); | ||
const children = []; | ||
@@ -99,3 +95,4 @@ selectedBlock.children.forEach(child => { | ||
}); | ||
return `${text}${children.join('')}`; | ||
const text = model.block2Text(children.join(''), selectedBlock.startPos, selectedBlock.endPos); | ||
return text; | ||
} | ||
@@ -102,0 +99,0 @@ _convertHtml2Blocks(element) { |
@@ -8,6 +8,6 @@ import { ContentParser } from '.'; | ||
private _commonParser; | ||
private _textPaser; | ||
private _commonHTML2Block; | ||
private _commonHTML2Text; | ||
private _listItemParser; | ||
} | ||
//# sourceMappingURL=parse-html.d.ts.map |
@@ -7,8 +7,13 @@ export class ParserHtml { | ||
this._contentParser.registerParserHtmlText2Block('nodeParser', this._nodePaser.bind(this)); | ||
this._contentParser.registerParserHtmlText2Block('textParser', this._textPaser.bind(this)); | ||
this._contentParser.registerParserHtmlText2Block('commonParser', this._commonParser.bind(this)); | ||
this._contentParser.registerParserHtmlText2Block('listItemParser', this._listItemParser.bind(this)); | ||
} | ||
// TODO parse children block | ||
_nodePaser(node) { | ||
if (node.nodeType === 3) { | ||
return this._contentParser.getParserHtmlText2Block('textParser')(node); | ||
return this._contentParser.getParserHtmlText2Block('commonParser')?.({ | ||
element: node, | ||
flavour: 'paragraph', | ||
type: 'text', | ||
}); | ||
} | ||
@@ -20,4 +25,35 @@ if (node.nodeType !== 1) { | ||
let result; | ||
if (['DIV', 'P', 'B', 'A', 'EM', 'U', 'S', 'DEL'].includes(tagName)) { | ||
result = this._contentParser.getParserHtmlText2Block('textParser')(node); | ||
switch (tagName) { | ||
case 'H1': | ||
case 'H2': | ||
case 'H3': | ||
case 'H4': | ||
case 'H5': | ||
case 'H6': | ||
result = this._contentParser.getParserHtmlText2Block('commonParser')?.({ | ||
element: node, | ||
flavour: 'paragraph', | ||
type: tagName.toLowerCase(), | ||
}); | ||
break; | ||
case 'DIV': | ||
case 'P': | ||
case 'B': | ||
case 'A': | ||
case 'EM': | ||
case 'U': | ||
case 'S': | ||
case 'DEL': | ||
result = this._contentParser.getParserHtmlText2Block('commonParser')?.({ | ||
element: node, | ||
flavour: 'paragraph', | ||
type: 'text', | ||
}); | ||
break; | ||
case 'LI': | ||
result = | ||
this._contentParser.getParserHtmlText2Block('listItemParser')?.(node); | ||
break; | ||
default: | ||
break; | ||
} | ||
@@ -27,3 +63,3 @@ if (result && result.length > 0) { | ||
} | ||
return Array.from(node.childNodes) | ||
return Array.from(node.children) | ||
.map(childElement => { | ||
@@ -39,19 +75,7 @@ const clipBlockInfos = this._contentParser.getParserHtmlText2Block('nodeParser')?.(childElement) || []; | ||
} | ||
_commonParser({ element, tagName, flavour, type, ignoreEmptyElement = true, }) { | ||
const tagNames = typeof tagName === 'string' ? [tagName] : tagName; | ||
if (tagNames.includes(element.tagName)) { | ||
const res = this._commonHTML2Block(element, flavour, type, ignoreEmptyElement); | ||
return res ? [res] : null; | ||
} | ||
return null; | ||
_commonParser({ element, flavour, type, checked, ignoreEmptyElement = true, }) { | ||
const res = this._commonHTML2Block(element, flavour, type, checked, ignoreEmptyElement); | ||
return res ? [res] : null; | ||
} | ||
_textPaser(element) { | ||
return this._contentParser.getParserHtmlText2Block('commonParser')?.({ | ||
element, | ||
flavour: 'paragraph', | ||
type: 'text', | ||
tagName: ['DIV', 'P', 'B', 'A', 'EM', 'U', 'S', 'DEL'], | ||
}); | ||
} | ||
_commonHTML2Block(element, flavour, type, ignoreEmptyElement = true) { | ||
_commonHTML2Block(element, flavour, type, checked, ignoreEmptyElement = true) { | ||
const textValue = this._commonHTML2Text(element, {}, ignoreEmptyElement); | ||
@@ -64,2 +88,3 @@ if (!textValue.length && ignoreEmptyElement) { | ||
type: type, | ||
checked: checked, | ||
text: textValue, | ||
@@ -129,2 +154,21 @@ children: [], | ||
} | ||
_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; | ||
} | ||
const result = this._contentParser.getParserHtmlText2Block('commonParser')?.({ | ||
element: element, | ||
flavour: 'list', | ||
type: type, | ||
checked: checked, | ||
}); | ||
return result; | ||
} | ||
} | ||
@@ -176,3 +220,3 @@ const getIsLink = (htmlElement) => { | ||
style['text-decoration'].indexOf('line-through') !== -1)) { | ||
textStyle['strikethrough'] = true; | ||
textStyle['strike'] = true; | ||
} | ||
@@ -179,0 +223,0 @@ return textStyle; |
import { CLIPBOARD_MIMETYPE } from './types'; | ||
import { ClipItem } from './clip-item'; | ||
import { ListBlockModel } from '@blocksuite/blocks'; | ||
export class CopyCutManager { | ||
@@ -85,4 +86,17 @@ constructor(editor) { | ||
} | ||
// TODO Handling different block by extension | ||
const delta = model?.text?.sliceToDelta(selectedBlock?.startPos || 0, selectedBlock?.endPos); | ||
let { flavour, type } = model; | ||
let delta = []; | ||
if (model.flavour === 'page') { | ||
flavour = 'paragraph'; | ||
type = 'text'; | ||
const text = model.block2Text('', selectedBlock?.startPos, selectedBlock?.endPos); | ||
delta = [ | ||
{ | ||
insert: text, | ||
}, | ||
]; | ||
} | ||
else { | ||
delta = model?.text?.sliceToDelta(selectedBlock?.startPos || 0, selectedBlock?.endPos); | ||
} | ||
const children = []; | ||
@@ -94,5 +108,6 @@ selectedBlock.children.forEach(child => { | ||
return { | ||
flavour: model.flavour, | ||
type: model.type, | ||
flavour: flavour, | ||
type: type, | ||
text: delta, | ||
checked: model instanceof ListBlockModel ? model.checked : undefined, | ||
children: children, | ||
@@ -99,0 +114,0 @@ }; |
@@ -58,3 +58,3 @@ import { marked } from 'marked'; | ||
} | ||
const textClipData = escape(clipboardData.getData(CLIPBOARD_MIMETYPE.TEXT)); | ||
const textClipData = clipboardData.getData(CLIPBOARD_MIMETYPE.TEXT); | ||
const shouldConvertMarkdown = MarkdownUtils.checkIfTextContainsMd(textClipData); | ||
@@ -66,2 +66,3 @@ if (optimalClip?.type === CLIPBOARD_MIMETYPE.HTML && | ||
if (shouldConvertMarkdown) { | ||
// TODO the method of parse need deal underline | ||
const md2html = marked.parse(textClipData); | ||
@@ -108,3 +109,3 @@ return this._editor.contentParser.htmlText2Block(md2html); | ||
parent = this._editor.store.getParent(selectedBlock); | ||
index = (parent?.children.indexOf(selectedBlock) || -1) + 1; | ||
index = (parent?.children.indexOf(selectedBlock) || 0) + 1; | ||
} | ||
@@ -121,3 +122,3 @@ const addBlockIds = []; | ||
parent = this._editor.store.getParent(selectedBlock); | ||
index = (parent?.children.indexOf(selectedBlock) || -1) + 1; | ||
index = (parent?.children.indexOf(selectedBlock) || 0) + 1; | ||
} | ||
@@ -135,2 +136,3 @@ const addBlockIds = []; | ||
type: block.type, | ||
checked: block.checked, | ||
}; | ||
@@ -137,0 +139,0 @@ const id = this._editor.store.addBlock(blockProps, parent, index + i); |
@@ -22,4 +22,5 @@ export declare enum CLIPBOARD_MIMETYPE { | ||
text: unknown; | ||
checked?: boolean; | ||
children: OpenBlockInfo[]; | ||
}; | ||
//# sourceMappingURL=types.d.ts.map |
@@ -34,2 +34,10 @@ import TurndownService from 'turndown'; | ||
const turndownService = new TurndownService(); | ||
turndownService.addRule('input', { | ||
filter: ['input'], | ||
replacement: function (content, node) { | ||
return node.getAttribute('checked') === null | ||
? '[ ] ' | ||
: '[x] '; | ||
}, | ||
}); | ||
const markdown = turndownService.turndown(htmlContent); | ||
@@ -36,0 +44,0 @@ FileExporter.exportFile((pageTitle || 'Undefined') + '.md', markdown, 'text/plain'); |
{ | ||
"name": "@blocksuite/editor", | ||
"version": "0.2.4", | ||
"version": "0.2.5", | ||
"type": "module", | ||
@@ -11,5 +11,5 @@ "description": "", | ||
"dependencies": { | ||
"@blocksuite/blocks": "0.2.4", | ||
"@blocksuite/shared": "0.2.4", | ||
"@blocksuite/store": "0.2.4", | ||
"@blocksuite/blocks": "0.2.5", | ||
"@blocksuite/shared": "0.2.5", | ||
"@blocksuite/store": "0.2.5", | ||
"lit": "^2.3.1", | ||
@@ -16,0 +16,0 @@ "marked": "^4.1.0", |
@@ -139,2 +139,4 @@ import { LitElement, html } from 'lit'; | ||
height: 100%; | ||
overflow-y: scroll; | ||
position: relative; | ||
} | ||
@@ -141,0 +143,0 @@ </style> |
@@ -137,7 +137,2 @@ import { PageBlockModel } from '@blocksuite/blocks'; | ||
// TODO Handling different block by extension | ||
let text = model?.text?.toString() || ''; | ||
const end = selectedBlock.endPos ? selectedBlock.endPos : text.length; | ||
text = text.slice(selectedBlock.startPos || 0, end); | ||
const children: string[] = []; | ||
@@ -149,3 +144,9 @@ selectedBlock.children.forEach(child => { | ||
return `${text}${children.join('')}`; | ||
const text = model.block2Text( | ||
children.join(''), | ||
selectedBlock.startPos, | ||
selectedBlock.endPos | ||
); | ||
return text; | ||
} | ||
@@ -152,0 +153,0 @@ |
@@ -16,14 +16,18 @@ import { ContentParser } from '.'; | ||
this._contentParser.registerParserHtmlText2Block( | ||
'textParser', | ||
this._textPaser.bind(this) | ||
); | ||
this._contentParser.registerParserHtmlText2Block( | ||
'commonParser', | ||
this._commonParser.bind(this) | ||
); | ||
this._contentParser.registerParserHtmlText2Block( | ||
'listItemParser', | ||
this._listItemParser.bind(this) | ||
); | ||
} | ||
// TODO parse children block | ||
private _nodePaser(node: Element): OpenBlockInfo[] | null { | ||
if (node.nodeType === 3) { | ||
return this._contentParser.getParserHtmlText2Block('textParser')(node); | ||
return this._contentParser.getParserHtmlText2Block('commonParser')?.({ | ||
element: node, | ||
flavour: 'paragraph', | ||
type: 'text', | ||
}); | ||
} | ||
@@ -35,4 +39,35 @@ if (node.nodeType !== 1) { | ||
let result; | ||
if (['DIV', 'P', 'B', 'A', 'EM', 'U', 'S', 'DEL'].includes(tagName)) { | ||
result = this._contentParser.getParserHtmlText2Block('textParser')(node); | ||
switch (tagName) { | ||
case 'H1': | ||
case 'H2': | ||
case 'H3': | ||
case 'H4': | ||
case 'H5': | ||
case 'H6': | ||
result = this._contentParser.getParserHtmlText2Block('commonParser')?.({ | ||
element: node, | ||
flavour: 'paragraph', | ||
type: tagName.toLowerCase(), | ||
}); | ||
break; | ||
case 'DIV': | ||
case 'P': | ||
case 'B': | ||
case 'A': | ||
case 'EM': | ||
case 'U': | ||
case 'S': | ||
case 'DEL': | ||
result = this._contentParser.getParserHtmlText2Block('commonParser')?.({ | ||
element: node, | ||
flavour: 'paragraph', | ||
type: 'text', | ||
}); | ||
break; | ||
case 'LI': | ||
result = | ||
this._contentParser.getParserHtmlText2Block('listItemParser')?.(node); | ||
break; | ||
default: | ||
break; | ||
} | ||
@@ -42,3 +77,3 @@ if (result && result.length > 0) { | ||
} | ||
return Array.from(node.childNodes) | ||
return Array.from(node.children) | ||
.map(childElement => { | ||
@@ -61,33 +96,21 @@ const clipBlockInfos = | ||
element, | ||
tagName, | ||
flavour, | ||
type, | ||
checked, | ||
ignoreEmptyElement = true, | ||
}: { | ||
element: Element; | ||
tagName: string | string[]; | ||
flavour: string; | ||
type: string; | ||
checked?: boolean; | ||
ignoreEmptyElement?: boolean; | ||
}): OpenBlockInfo[] | null { | ||
const tagNames = typeof tagName === 'string' ? [tagName] : tagName; | ||
if (tagNames.includes(element.tagName)) { | ||
const res = this._commonHTML2Block( | ||
element, | ||
flavour, | ||
type, | ||
ignoreEmptyElement | ||
); | ||
return res ? [res] : null; | ||
} | ||
return null; | ||
} | ||
private _textPaser(element: Element): OpenBlockInfo[] | null { | ||
return this._contentParser.getParserHtmlText2Block('commonParser')?.({ | ||
const res = this._commonHTML2Block( | ||
element, | ||
flavour: 'paragraph', | ||
type: 'text', | ||
tagName: ['DIV', 'P', 'B', 'A', 'EM', 'U', 'S', 'DEL'], | ||
}); | ||
flavour, | ||
type, | ||
checked, | ||
ignoreEmptyElement | ||
); | ||
return res ? [res] : null; | ||
} | ||
@@ -99,2 +122,3 @@ | ||
type: string, | ||
checked?: boolean, | ||
ignoreEmptyElement = true | ||
@@ -109,2 +133,3 @@ ): OpenBlockInfo | null { | ||
type: type, | ||
checked: checked, | ||
text: textValue, | ||
@@ -187,2 +212,26 @@ children: [], | ||
} | ||
private _listItemParser(element: HTMLElement): OpenBlockInfo[] | null { | ||
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; | ||
} | ||
const result = this._contentParser.getParserHtmlText2Block( | ||
'commonParser' | ||
)?.({ | ||
element: element, | ||
flavour: 'list', | ||
type: type, | ||
checked: checked, | ||
}); | ||
return result; | ||
} | ||
} | ||
@@ -247,3 +296,3 @@ | ||
) { | ||
textStyle['strikethrough'] = true; | ||
textStyle['strike'] = true; | ||
} | ||
@@ -250,0 +299,0 @@ |
@@ -5,3 +5,3 @@ import { CLIPBOARD_MIMETYPE, OpenBlockInfo } from './types'; | ||
import { SelectedBlock } from '@blocksuite/shared'; | ||
import type { DefaultPageBlockComponent } from '@blocksuite/blocks'; | ||
import { DefaultPageBlockComponent, ListBlockModel } from '@blocksuite/blocks'; | ||
@@ -120,8 +120,25 @@ export class CopyCutManager { | ||
} | ||
// TODO Handling different block by extension | ||
const delta = model?.text?.sliceToDelta( | ||
selectedBlock?.startPos || 0, | ||
selectedBlock?.endPos | ||
); | ||
let { flavour, type } = model; | ||
let delta = []; | ||
if (model.flavour === 'page') { | ||
flavour = 'paragraph'; | ||
type = 'text'; | ||
const text = model.block2Text( | ||
'', | ||
selectedBlock?.startPos, | ||
selectedBlock?.endPos | ||
); | ||
delta = [ | ||
{ | ||
insert: text, | ||
}, | ||
]; | ||
} else { | ||
delta = model?.text?.sliceToDelta( | ||
selectedBlock?.startPos || 0, | ||
selectedBlock?.endPos | ||
); | ||
} | ||
const children: OpenBlockInfo[] = []; | ||
@@ -134,5 +151,6 @@ selectedBlock.children.forEach(child => { | ||
return { | ||
flavour: model.flavour, | ||
type: model.type, | ||
flavour: flavour, | ||
type: type, | ||
text: delta, | ||
checked: model instanceof ListBlockModel ? model.checked : undefined, | ||
children: children, | ||
@@ -139,0 +157,0 @@ }; |
@@ -75,3 +75,3 @@ import type { DefaultPageBlockComponent } from '@blocksuite/blocks'; | ||
const textClipData = escape(clipboardData.getData(CLIPBOARD_MIMETYPE.TEXT)); | ||
const textClipData = clipboardData.getData(CLIPBOARD_MIMETYPE.TEXT); | ||
@@ -88,2 +88,3 @@ const shouldConvertMarkdown = | ||
if (shouldConvertMarkdown) { | ||
// TODO the method of parse need deal underline | ||
const md2html = marked.parse(textClipData); | ||
@@ -144,3 +145,3 @@ return this._editor.contentParser.htmlText2Block(md2html); | ||
parent = this._editor.store.getParent(selectedBlock); | ||
index = (parent?.children.indexOf(selectedBlock) || -1) + 1; | ||
index = (parent?.children.indexOf(selectedBlock) || 0) + 1; | ||
} | ||
@@ -159,3 +160,3 @@ const addBlockIds: string[] = []; | ||
parent = this._editor.store.getParent(selectedBlock); | ||
index = (parent?.children.indexOf(selectedBlock) || -1) + 1; | ||
index = (parent?.children.indexOf(selectedBlock) || 0) + 1; | ||
} | ||
@@ -179,2 +180,3 @@ const addBlockIds: string[] = []; | ||
type: block.type as string, | ||
checked: block.checked, | ||
}; | ||
@@ -181,0 +183,0 @@ const id = this._editor.store.addBlock(blockProps, parent, index + i); |
@@ -24,3 +24,4 @@ export enum CLIPBOARD_MIMETYPE { | ||
text: unknown; | ||
checked?: boolean; | ||
children: OpenBlockInfo[]; | ||
}; |
@@ -46,2 +46,10 @@ import TurndownService from 'turndown'; | ||
const turndownService = new TurndownService(); | ||
turndownService.addRule('input', { | ||
filter: ['input'], | ||
replacement: function (content, node) { | ||
return (node as HTMLElement).getAttribute('checked') === null | ||
? '[ ] ' | ||
: '[x] '; | ||
}, | ||
}); | ||
const markdown = turndownService.turndown(htmlContent); | ||
@@ -48,0 +56,0 @@ FileExporter.exportFile( |
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
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
136145
2359
+ Added@blocksuite/blocks@0.2.5(transitive)
+ Added@blocksuite/shared@0.2.5(transitive)
+ Added@blocksuite/store@0.2.5(transitive)
- Removed@blocksuite/blocks@0.2.4(transitive)
- Removed@blocksuite/shared@0.2.4(transitive)
- Removed@blocksuite/store@0.2.4(transitive)
Updated@blocksuite/blocks@0.2.5
Updated@blocksuite/shared@0.2.5
Updated@blocksuite/store@0.2.5