1- import { DOMSerializer , Fragment , Node , Schema } from "prosemirror-model" ;
1+ import { DOMSerializer , Schema } from "prosemirror-model" ;
22
33import { PartialBlock } from "../../../blocks/defaultBlocks" ;
44import type { BlockNoteEditor } from "../../../editor/BlockNoteEditor" ;
5- import { BlockSchema , InlineContentSchema , StyleSchema } from "../../../schema" ;
5+ import {
6+ BlockSchema ,
7+ InlineContent ,
8+ InlineContentSchema ,
9+ StyleSchema ,
10+ } from "../../../schema" ;
611import { esmDependencies } from "../../../util/esmDependencies" ;
7- import { blockToNode } from "../../nodeConversions/nodeConversions" ;
812import {
9- serializeNodeInner ,
10- serializeProseMirrorFragment ,
13+ serializeBlocks ,
14+ serializeInlineContent ,
1115} from "./util/sharedHTMLConversion" ;
1216import { simplifyBlocks } from "./util/simplifyBlocksRehypePlugin" ;
1317
@@ -24,26 +28,6 @@ import { simplifyBlocks } from "./util/simplifyBlocksRehypePlugin";
2428// 3. While nesting for list items is preserved, other types of blocks nested
2529// inside a list are un-nested and a new list is created after them.
2630// 4. The HTML is wrapped in a single `div` element.
27- //
28- // The serializer has 2 main methods:
29- // `exportBlocks`: Exports an array of blocks to HTML.
30- // `exportFragment`: Exports a ProseMirror fragment to HTML. This is mostly
31- // useful if you want to export a selection which may not start/end at the
32- // start/end of a block.
33- export interface ExternalHTMLExporter <
34- BSchema extends BlockSchema ,
35- I extends InlineContentSchema ,
36- S extends StyleSchema
37- > {
38- exportBlocks : (
39- blocks : PartialBlock < BSchema , I , S > [ ] ,
40- options : { document ?: Document }
41- ) => string ;
42- exportProseMirrorFragment : (
43- fragment : Fragment ,
44- options : { document ?: Document ; simplifyBlocks ?: boolean }
45- ) => string ;
46- }
4731
4832// Needs to be sync because it's used in drag handler event (SideMenuPlugin)
4933// Ideally, call `await initializeESMDependencies()` before calling this function
@@ -54,7 +38,7 @@ export const createExternalHTMLExporter = <
5438> (
5539 schema : Schema ,
5640 editor : BlockNoteEditor < BSchema , I , S >
57- ) : ExternalHTMLExporter < BSchema , I , S > => {
41+ ) => {
5842 const deps = esmDependencies ;
5943
6044 if ( ! deps ) {
@@ -63,67 +47,63 @@ export const createExternalHTMLExporter = <
6347 ) ;
6448 }
6549
66- // TODO: maybe cache this serializer (default prosemirror serializer is cached)?
67- const serializer = new DOMSerializer (
68- DOMSerializer . nodesFromSchema ( schema ) ,
69- DOMSerializer . marksFromSchema ( schema )
70- ) as DOMSerializer & {
71- serializeNodeInner : (
72- node : Node ,
73- options : { document ?: Document }
74- ) => HTMLElement ;
75- exportProseMirrorFragment : (
76- fragment : Fragment ,
77- options : { document ?: Document ; simplifyBlocks ?: boolean }
78- ) => string ;
50+ const serializer = DOMSerializer . fromSchema ( schema ) ;
51+
52+ return {
7953 exportBlocks : (
8054 blocks : PartialBlock < BSchema , I , S > [ ] ,
8155 options : { document ?: Document }
82- ) => string ;
83- } ;
56+ ) => {
57+ const html = serializeBlocks (
58+ editor ,
59+ blocks ,
60+ serializer ,
61+ true ,
62+ options
63+ ) . outerHTML ;
8464
85- serializer . serializeNodeInner = (
86- node : Node ,
87- options : { document ?: Document }
88- ) => serializeNodeInner ( node , options , serializer , editor , true ) ;
65+ // Possible improvement: now, we first use the serializeBlocks function
66+ // which adds blockcontainer and blockgroup wrappers. We then pass the
67+ // result to simplifyBlocks, which then cleans the wrappers.
68+ //
69+ // It might be easier if we create a version of serializeBlocks that
70+ // doesn't add the wrappers in the first place, then we can get rid of
71+ // the more complex simplifyBlocks plugin.
72+ let externalHTML : any = deps . unified
73+ . unified ( )
74+ . use ( deps . rehypeParse . default , { fragment : true } ) ;
75+ if ( ( options as any ) . simplifyBlocks !== false ) {
76+ externalHTML = externalHTML . use ( simplifyBlocks , {
77+ orderedListItemBlockTypes : new Set < string > ( [ "numberedListItem" ] ) ,
78+ unorderedListItemBlockTypes : new Set < string > ( [
79+ "bulletListItem" ,
80+ "checkListItem" ,
81+ ] ) ,
82+ } ) ;
83+ }
84+ externalHTML = externalHTML
85+ . use ( deps . rehypeStringify . default )
86+ . processSync ( html ) ;
8987
90- // Like the `internalHTMLSerializer`, also uses `serializeProseMirrorFragment`
91- // but additionally runs it through the `simplifyBlocks` rehype plugin to
92- // convert the internal HTML to external.
93- serializer . exportProseMirrorFragment = ( fragment , options ) => {
94- let externalHTML : any = deps . unified
95- . unified ( )
96- . use ( deps . rehypeParse . default , { fragment : true } ) ;
97- if ( options . simplifyBlocks !== false ) {
98- externalHTML = externalHTML . use ( simplifyBlocks , {
99- orderedListItemBlockTypes : new Set < string > ( [ "numberedListItem" ] ) ,
100- unorderedListItemBlockTypes : new Set < string > ( [
101- "bulletListItem" ,
102- "checkListItem" ,
103- ] ) ,
104- } ) ;
105- }
106- externalHTML = externalHTML
107- . use ( deps . rehypeStringify . default )
108- . processSync ( serializeProseMirrorFragment ( fragment , serializer , options ) ) ;
88+ return externalHTML . value as string ;
89+ } ,
10990
110- return externalHTML . value as string ;
111- } ;
91+ exportInlineContent : (
92+ inlineContent : InlineContent < I , S > [ ] ,
93+ options : { simplifyBlocks : boolean ; document ?: Document }
94+ ) => {
95+ const domFragment = serializeInlineContent (
96+ editor ,
97+ inlineContent as any ,
98+ serializer ,
99+ true ,
100+ options
101+ ) ;
112102
113- serializer . exportBlocks = (
114- blocks : PartialBlock < BSchema , I , S > [ ] ,
115- options
116- ) => {
117- const nodes = blocks . map ( ( block ) =>
118- blockToNode ( block , schema , editor . schema . styleSchema )
119- ) ;
120- const blockGroup = schema . nodes [ "blockGroup" ] . create ( null , nodes ) ;
103+ const parent = document . createElement ( "div" ) ;
104+ parent . append ( domFragment . cloneNode ( true ) ) ;
121105
122- return serializer . exportProseMirrorFragment (
123- Fragment . from ( blockGroup ) ,
124- options
125- ) ;
106+ return parent . innerHTML ;
107+ } ,
126108 } ;
127-
128- return serializer ;
129109} ;
0 commit comments