@kerebron/extension-odt 0.5.2 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/esm/ExtensionOdt.d.ts.map +1 -1
- package/esm/ExtensionOdt.js +16 -70
- package/esm/ExtensionOdt.js.map +1 -1
- package/esm/OdtParser.d.ts +5 -5
- package/esm/OdtParser.d.ts.map +1 -1
- package/esm/OdtParser.js +20 -13
- package/esm/OdtParser.js.map +1 -1
- package/esm/lists.d.ts +9 -9
- package/esm/lists.d.ts.map +1 -1
- package/esm/lists.js +21 -7
- package/esm/lists.js.map +1 -1
- package/esm/node_handlers/basic_node_handlers.d.ts.map +1 -1
- package/esm/node_handlers/basic_node_handlers.js +1 -3
- package/esm/node_handlers/basic_node_handlers.js.map +1 -1
- package/esm/node_handlers/list_node_handlers.d.ts.map +1 -1
- package/esm/node_handlers/list_node_handlers.js +50 -64
- package/esm/node_handlers/list_node_handlers.js.map +1 -1
- package/esm/postprocess/convertCodeParagraphsToCodeBlocks.d.ts.map +1 -1
- package/esm/postprocess/convertCodeParagraphsToCodeBlocks.js +30 -67
- package/esm/postprocess/convertCodeParagraphsToCodeBlocks.js.map +1 -1
- package/esm/postprocess/convertMathMl.d.ts.map +1 -1
- package/esm/postprocess/convertMathMl.js.map +1 -1
- package/esm/postprocess/fixContinuedLists.d.ts.map +1 -1
- package/esm/postprocess/fixContinuedLists.js +80 -67
- package/esm/postprocess/fixContinuedLists.js.map +1 -1
- package/esm/postprocess/mergeCodeBlocks.d.ts +3 -0
- package/esm/postprocess/mergeCodeBlocks.d.ts.map +1 -0
- package/esm/postprocess/mergeCodeBlocks.js +72 -0
- package/esm/postprocess/mergeCodeBlocks.js.map +1 -0
- package/esm/postprocess/postProcess.d.ts.map +1 -1
- package/esm/postprocess/postProcess.js +3 -1
- package/esm/postprocess/postProcess.js.map +1 -1
- package/esm/postprocess/removeUnusedBookmarks.d.ts +1 -1
- package/esm/postprocess/removeUnusedBookmarks.d.ts.map +1 -1
- package/esm/postprocess/removeUnusedBookmarks.js +17 -19
- package/esm/postprocess/removeUnusedBookmarks.js.map +1 -1
- package/esm/postprocess/urlRewrite.d.ts +4 -0
- package/esm/postprocess/urlRewrite.d.ts.map +1 -0
- package/esm/postprocess/urlRewrite.js +60 -0
- package/esm/postprocess/urlRewrite.js.map +1 -0
- package/package.json +3 -3
- package/src/ExtensionOdt.ts +17 -102
- package/src/OdtParser.ts +15 -8
- package/src/lists.ts +24 -10
- package/src/node_handlers/basic_node_handlers.ts +2 -4
- package/src/node_handlers/list_node_handlers.ts +64 -87
- package/src/postprocess/convertCodeParagraphsToCodeBlocks.ts +33 -88
- package/src/postprocess/convertMathMl.ts +0 -1
- package/src/postprocess/fixContinuedLists.ts +95 -78
- package/src/postprocess/mergeCodeBlocks.ts +98 -0
- package/src/postprocess/postProcess.ts +3 -1
- package/src/postprocess/removeUnusedBookmarks.ts +34 -21
- package/src/postprocess/urlRewrite.ts +95 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kerebron/extension-odt",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"module": "./esm/ExtensionOdt.js",
|
|
6
6
|
"exports": {
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
"src"
|
|
15
15
|
],
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@kerebron/editor": "0.5.
|
|
18
|
-
"@kerebron/odt-wasm": "0.5.
|
|
17
|
+
"@kerebron/editor": "0.5.3",
|
|
18
|
+
"@kerebron/odt-wasm": "0.5.3",
|
|
19
19
|
"prosemirror-model": "1.25.3",
|
|
20
20
|
"prosemirror-state": "1.4.3"
|
|
21
21
|
},
|
package/src/ExtensionOdt.ts
CHANGED
|
@@ -16,7 +16,8 @@ import {
|
|
|
16
16
|
import { OdtParser, OdtParserConfig } from './OdtParser.js';
|
|
17
17
|
import { getDefaultsPostProcessFilters } from './postprocess/postProcess.js';
|
|
18
18
|
import { Command } from '@kerebron/editor/commands';
|
|
19
|
-
import {
|
|
19
|
+
import { EditorState, Transaction } from 'prosemirror-state';
|
|
20
|
+
import { urlRewrite } from './postprocess/urlRewrite.js';
|
|
20
21
|
|
|
21
22
|
export interface OdtConfig extends OdtParserConfig {
|
|
22
23
|
debug?: boolean;
|
|
@@ -37,8 +38,6 @@ export class ExtensionOdt extends Extension {
|
|
|
37
38
|
editor: CoreEditor,
|
|
38
39
|
schema: Schema,
|
|
39
40
|
): Record<string, Converter> {
|
|
40
|
-
const config = this.config;
|
|
41
|
-
|
|
42
41
|
const odtConverter = {
|
|
43
42
|
fromDoc: async (document: Node): Promise<Uint8Array> => {
|
|
44
43
|
throw new Error('Not implemented');
|
|
@@ -53,118 +52,34 @@ export class ExtensionOdt extends Extension {
|
|
|
53
52
|
this.config.postProcessCommands || [],
|
|
54
53
|
);
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
// plugin.props.
|
|
61
|
-
}
|
|
55
|
+
let state = EditorState.create({ doc });
|
|
56
|
+
const dispatch = (tr: Transaction) => {
|
|
57
|
+
state = state.apply(tr);
|
|
58
|
+
};
|
|
62
59
|
|
|
63
|
-
const subEditor = editor.clone();
|
|
64
|
-
subEditor.setDocument(doc.toJSON());
|
|
65
|
-
|
|
66
|
-
let modified = false;
|
|
67
60
|
if (this.urlFromRewriter) {
|
|
68
|
-
|
|
69
|
-
subEditor.getDocument().descendants((node, pos) => {
|
|
70
|
-
if (node.type.name === 'image') {
|
|
71
|
-
imageNodes.push({ node, pos });
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
const linkNodes: Array<{ node: Node; pos: number }> = [];
|
|
76
|
-
subEditor.getDocument().descendants((node, pos) => {
|
|
77
|
-
if (node.marks.find((mark) => mark.type.name === 'link')) {
|
|
78
|
-
linkNodes.push({ node, pos });
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
const tr = subEditor.state.tr;
|
|
83
|
-
|
|
84
|
-
for (const { node, pos } of linkNodes) {
|
|
85
|
-
const linkMark = node.marks.find((mark) =>
|
|
86
|
-
mark.type.name === 'link'
|
|
87
|
-
);
|
|
88
|
-
if (!linkMark) {
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
let href = linkMark.attrs.href || '';
|
|
92
|
-
href = await this.urlFromRewriter(href, {
|
|
93
|
-
type: 'A',
|
|
94
|
-
dest: 'kerebron',
|
|
95
|
-
});
|
|
96
|
-
if (href !== linkMark.attrs.href) {
|
|
97
|
-
const newMarks = node.marks.map((mark) => {
|
|
98
|
-
if (mark.type.name === 'link') {
|
|
99
|
-
const markType = this.editor.schema.marks['link'];
|
|
100
|
-
return markType.create({ ...mark.attrs, href });
|
|
101
|
-
}
|
|
102
|
-
return mark;
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
const nodeType = this.editor.schema.nodes[node.type.name];
|
|
106
|
-
let replaceNode;
|
|
107
|
-
if (nodeType.isText) {
|
|
108
|
-
replaceNode = this.editor.schema.text(
|
|
109
|
-
node.text || '',
|
|
110
|
-
newMarks,
|
|
111
|
-
);
|
|
112
|
-
} else {
|
|
113
|
-
replaceNode = nodeType.create(
|
|
114
|
-
node.attrs,
|
|
115
|
-
node.content,
|
|
116
|
-
newMarks,
|
|
117
|
-
);
|
|
118
|
-
}
|
|
119
|
-
tr.replaceWith(
|
|
120
|
-
tr.mapping.map(pos),
|
|
121
|
-
tr.mapping.map(pos + node.nodeSize),
|
|
122
|
-
replaceNode,
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
for (const { node, pos } of imageNodes) {
|
|
128
|
-
let src = node.attrs.src || '';
|
|
129
|
-
|
|
130
|
-
src = await this.urlFromRewriter(src, {
|
|
131
|
-
type: 'IMG',
|
|
132
|
-
dest: 'kerebron',
|
|
133
|
-
filesMap,
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
if (src !== node.attrs.src) {
|
|
137
|
-
const nodeType = this.editor.schema.nodes[node.type.name];
|
|
138
|
-
const replaceNode = nodeType.create(
|
|
139
|
-
{ ...node.attrs, src },
|
|
140
|
-
node.content,
|
|
141
|
-
node.marks,
|
|
142
|
-
);
|
|
143
|
-
tr.replaceWith(
|
|
144
|
-
tr.mapping.map(pos),
|
|
145
|
-
tr.mapping.map(pos + node.nodeSize),
|
|
146
|
-
replaceNode,
|
|
147
|
-
);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
subEditor.dispatchTransaction(tr), modified = true;
|
|
61
|
+
await urlRewrite(this.urlFromRewriter, filesMap, state, dispatch);
|
|
151
62
|
}
|
|
152
63
|
|
|
153
64
|
if (filterCommands.length > 0) {
|
|
154
65
|
for (const filter of filterCommands) {
|
|
155
66
|
filter(
|
|
156
|
-
|
|
157
|
-
(tr) =>
|
|
67
|
+
state,
|
|
68
|
+
(tr) => dispatch(tr),
|
|
158
69
|
);
|
|
159
70
|
}
|
|
160
|
-
modified = true;
|
|
161
71
|
}
|
|
162
72
|
|
|
163
|
-
if (
|
|
164
|
-
|
|
73
|
+
if (this.config.debug) {
|
|
74
|
+
const event = new CustomEvent('odt:pmdoc:filtered', {
|
|
75
|
+
detail: {
|
|
76
|
+
doc: state.doc,
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
this.editor.dispatchEvent(event);
|
|
165
80
|
}
|
|
166
81
|
|
|
167
|
-
return doc;
|
|
82
|
+
return state.doc;
|
|
168
83
|
},
|
|
169
84
|
odtToJson: (buffer: Uint8Array) => {
|
|
170
85
|
const files = unzip(buffer);
|
package/src/OdtParser.ts
CHANGED
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
import { getListNodesHandlers } from './node_handlers/list_node_handlers.js';
|
|
7
7
|
import { getTableNodesHandlers } from './node_handlers/table_node_handlers.js';
|
|
8
8
|
import { ListTracker } from './lists.js';
|
|
9
|
-
import { type UrlRewriter } from '@kerebron/editor';
|
|
10
9
|
|
|
11
10
|
const COURIER_FONTS = ['Courier New', 'Courier', 'Roboto Mono'];
|
|
12
11
|
|
|
@@ -16,24 +15,24 @@ export interface OdtElement {
|
|
|
16
15
|
|
|
17
16
|
export type NodeHandler = (ctx: OdtStashContext, value: any) => void;
|
|
18
17
|
|
|
19
|
-
interface ListStyle {
|
|
18
|
+
export interface ListStyle {
|
|
20
19
|
'@name': string;
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
interface Style {
|
|
22
|
+
export interface Style {
|
|
24
23
|
'@name': string;
|
|
25
24
|
'@parent-style-name'?: string;
|
|
26
25
|
styles: string[];
|
|
27
26
|
}
|
|
28
27
|
|
|
29
|
-
interface StylesTree {
|
|
28
|
+
export interface StylesTree {
|
|
30
29
|
styles: {
|
|
31
30
|
'list-style': Array<ListStyle>;
|
|
32
31
|
'style': Array<Style>;
|
|
33
32
|
};
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
interface AutomaticStyles {
|
|
35
|
+
export interface AutomaticStyles {
|
|
37
36
|
'style': Array<Style>;
|
|
38
37
|
}
|
|
39
38
|
|
|
@@ -42,7 +41,7 @@ export function resolveStyle(
|
|
|
42
41
|
automaticStyles: AutomaticStyles,
|
|
43
42
|
name: string,
|
|
44
43
|
): Style {
|
|
45
|
-
let style: Style;
|
|
44
|
+
let style: Style | undefined;
|
|
46
45
|
|
|
47
46
|
if (!style) {
|
|
48
47
|
style = stylesTree.styles['list-style'].find((item) =>
|
|
@@ -59,6 +58,7 @@ export function resolveStyle(
|
|
|
59
58
|
if (!style) {
|
|
60
59
|
style = {
|
|
61
60
|
'@name': name,
|
|
61
|
+
styles: [],
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
64
|
|
|
@@ -198,6 +198,10 @@ export class OdtStashContext {
|
|
|
198
198
|
this.current.content = [];
|
|
199
199
|
}
|
|
200
200
|
|
|
201
|
+
public dropNode() {
|
|
202
|
+
this.unstash();
|
|
203
|
+
}
|
|
204
|
+
|
|
201
205
|
public closeNode(type: string, attrs = {}, marks = Mark.none) {
|
|
202
206
|
const node = this.createNode(type, attrs, marks);
|
|
203
207
|
this.unstash();
|
|
@@ -292,7 +296,7 @@ export class OdtParser {
|
|
|
292
296
|
...getListNodesHandlers(),
|
|
293
297
|
...getTableNodesHandlers(),
|
|
294
298
|
|
|
295
|
-
'change-start': {
|
|
299
|
+
'change-start': () => {
|
|
296
300
|
// custom(state) {
|
|
297
301
|
// state.textMarks.add({
|
|
298
302
|
// markName: 'change',
|
|
@@ -300,13 +304,16 @@ export class OdtParser {
|
|
|
300
304
|
// });
|
|
301
305
|
// },
|
|
302
306
|
},
|
|
303
|
-
'change-end': {
|
|
307
|
+
'change-end': () => {
|
|
304
308
|
// custom(state) {
|
|
305
309
|
// state.textMarks.forEach((x) =>
|
|
306
310
|
// x.markName === 'change' ? state.textMarks.delete(x) : x
|
|
307
311
|
// );
|
|
308
312
|
// },
|
|
309
313
|
},
|
|
314
|
+
'g': () => { // Test is: embedded-diagram-example.odt
|
|
315
|
+
// DrawG draw:g
|
|
316
|
+
},
|
|
310
317
|
'frame': (ctx: OdtStashContext, odtElement: any) => {
|
|
311
318
|
if (odtElement.object && odtElement.object['@href']) {
|
|
312
319
|
const fullPath = odtElement.object['@href'].replace(/^\.\//, '') +
|
package/src/lists.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import { OdtElement } from './OdtParser.js';
|
|
2
|
-
|
|
3
1
|
export class ListNumbering {
|
|
4
2
|
levels: { [level: number]: number } = {};
|
|
5
|
-
|
|
3
|
+
forceStart: { [level: number]: boolean } = {};
|
|
6
4
|
|
|
7
|
-
constructor() {
|
|
5
|
+
constructor(public readonly id: string) {
|
|
8
6
|
for (let i = 0; i < 20; i++) {
|
|
9
7
|
this.levels[i] = 1;
|
|
10
8
|
}
|
|
@@ -16,20 +14,36 @@ export class ListNumbering {
|
|
|
16
14
|
}
|
|
17
15
|
}
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
clone(id: string): ListNumbering {
|
|
18
|
+
const retVal = new ListNumbering(id);
|
|
19
|
+
|
|
20
|
+
retVal.levels = structuredClone(retVal.levels);
|
|
21
|
+
retVal.forceStart = structuredClone(retVal.forceStart);
|
|
22
|
+
|
|
23
|
+
return retVal;
|
|
21
24
|
}
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
export interface List {
|
|
25
28
|
level: number;
|
|
26
|
-
|
|
29
|
+
id?: string;
|
|
30
|
+
styleName: string;
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
export class ListTracker {
|
|
30
34
|
listStack: List[] = [];
|
|
31
35
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
36
|
+
pushList(id?: string, styleName = ''): List {
|
|
37
|
+
const list: List = {
|
|
38
|
+
id,
|
|
39
|
+
styleName,
|
|
40
|
+
level: this.listStack.length + 1,
|
|
41
|
+
};
|
|
42
|
+
this.listStack.push(list);
|
|
43
|
+
return list;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
getCurrentList(): List {
|
|
47
|
+
return this.listStack[this.listStack.length - 1];
|
|
48
|
+
}
|
|
35
49
|
}
|
|
@@ -33,13 +33,11 @@ export function getInlineNodesHandlers(): Record<string, NodeHandler> {
|
|
|
33
33
|
ctx.closeNode('br');
|
|
34
34
|
},
|
|
35
35
|
'soft-page-break': (ctx: OdtStashContext, odtElement: any) => {
|
|
36
|
-
ctx.openNode();
|
|
37
|
-
ctx.closeNode('br');
|
|
38
36
|
},
|
|
39
37
|
|
|
40
38
|
'bookmark': (ctx: OdtStashContext, element: any) => { // bookmark for parent para
|
|
41
39
|
ctx.openNode();
|
|
42
|
-
ctx.closeNode('
|
|
40
|
+
ctx.closeNode('node_bookmark', {
|
|
43
41
|
id: element['@name'],
|
|
44
42
|
});
|
|
45
43
|
},
|
|
@@ -74,7 +72,7 @@ export function getBasicNodesHandlers(): Record<string, NodeHandler> {
|
|
|
74
72
|
);
|
|
75
73
|
},
|
|
76
74
|
'p': (ctx: OdtStashContext, value: any) => {
|
|
77
|
-
const attrs = {};
|
|
75
|
+
const attrs: Record<string, any> = {};
|
|
78
76
|
|
|
79
77
|
const style = ctx.getElementStyle(value);
|
|
80
78
|
const heading = style.styles.find((item) =>
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { ListNumbering } from '../lists.js';
|
|
2
1
|
import {
|
|
3
2
|
iterateChildren,
|
|
4
3
|
NodeHandler,
|
|
@@ -6,91 +5,73 @@ import {
|
|
|
6
5
|
resolveStyle,
|
|
7
6
|
} from '../OdtParser.js';
|
|
8
7
|
|
|
8
|
+
// https://docs.oasis-open.org/office/OpenDocument/v1.4/OpenDocument-v1.4-part3-schema.html#a_19_880_22__text_list_
|
|
9
|
+
// The text:style-name attribute specifies the name of a list style that is applied to a list.
|
|
10
|
+
// If this attribute is not included and therefore no list style is specified, one of the following actions is taken:
|
|
11
|
+
// •If a list is contained within another list, the list style defaults to the style of the surrounding list.
|
|
12
|
+
// •If there is no list style specified for the surrounding list, but the list's list items contain paragraphs that have paragraph styles attached specifying a list style, that list style is used.
|
|
13
|
+
// •An implementation-dependent default list style is used.
|
|
14
|
+
// To determine which formatting properties are applied to a list, the list level and list style name are taken into account.
|
|
15
|
+
function processListStyle(ctx: OdtStashContext, level: number) {
|
|
16
|
+
const listTracker = ctx.listTracker;
|
|
17
|
+
const attrs: Record<string, string> = {};
|
|
18
|
+
|
|
19
|
+
let style = {};
|
|
20
|
+
for (let i = listTracker.listStack.length - 1; i >= 0; i--) {
|
|
21
|
+
const list = listTracker.listStack[i];
|
|
22
|
+
if (!style['@style-name']) {
|
|
23
|
+
style = (list.styleName)
|
|
24
|
+
? resolveStyle(
|
|
25
|
+
ctx.stylesTree,
|
|
26
|
+
ctx.automaticStyles,
|
|
27
|
+
list.styleName,
|
|
28
|
+
)
|
|
29
|
+
: {};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let nodeTypeName = 'bullet_list';
|
|
34
|
+
if (style) {
|
|
35
|
+
const numLevelStyle = style['list-level-style-number'].find(
|
|
36
|
+
(levelStyle) => parseInt(levelStyle['@level']) === level,
|
|
37
|
+
);
|
|
38
|
+
if (numLevelStyle) {
|
|
39
|
+
attrs['type'] = numLevelStyle['@num-format'] || '1';
|
|
40
|
+
if (numLevelStyle['@start-value']) {
|
|
41
|
+
attrs['start'] = numLevelStyle['@start-value'];
|
|
42
|
+
}
|
|
43
|
+
nodeTypeName = 'ordered_list';
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
attrs,
|
|
49
|
+
nodeTypeName,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// https://docs.oasis-open.org/office/OpenDocument/v1.4/OpenDocument-v1.4-part3-schema.html#element-text_list
|
|
9
54
|
export function getListNodesHandlers(): Record<string, NodeHandler> {
|
|
10
55
|
return {
|
|
11
56
|
'list': (ctx: OdtStashContext, odtElement: any) => {
|
|
12
57
|
const listTracker = ctx.listTracker;
|
|
13
|
-
|
|
14
|
-
level: listTracker.listStack.length + 1,
|
|
15
|
-
odtElement,
|
|
16
|
-
};
|
|
17
|
-
listTracker.listStack.push(list);
|
|
58
|
+
listTracker.pushList(odtElement['@id'], odtElement['@style-name']);
|
|
18
59
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (!listId) {
|
|
24
|
-
if (element['@id']) {
|
|
25
|
-
listId = element['@id'];
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
if (!style['@style-name']) {
|
|
29
|
-
style = ('object' === typeof element && element['@style-name'])
|
|
30
|
-
? resolveStyle(
|
|
31
|
-
ctx.stylesTree,
|
|
32
|
-
ctx.automaticStyles,
|
|
33
|
-
element['@style-name'],
|
|
34
|
-
)
|
|
35
|
-
: {};
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
let nodeTypeName = 'bullet_list';
|
|
40
|
-
const attrs = {};
|
|
41
|
-
if (style) {
|
|
42
|
-
const numLevelStyle = style['list-level-style-number'].find(
|
|
43
|
-
(levelStyle) => parseInt(levelStyle['@level']) === list.level,
|
|
44
|
-
);
|
|
45
|
-
if (numLevelStyle) {
|
|
46
|
-
attrs['type'] = numLevelStyle['@num-format'] || '1';
|
|
47
|
-
nodeTypeName = 'ordered_list';
|
|
48
|
-
}
|
|
49
|
-
}
|
|
60
|
+
const { nodeTypeName, attrs } = processListStyle(
|
|
61
|
+
ctx,
|
|
62
|
+
listTracker.getCurrentList().level,
|
|
63
|
+
);
|
|
50
64
|
|
|
51
65
|
ctx.current.meta['list_type'] = nodeTypeName;
|
|
52
66
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if (listId && listTracker.listNumberings.has(listId)) {
|
|
56
|
-
listNumbering = listTracker.listNumberings.get(listId);
|
|
67
|
+
if (odtElement['@id']) {
|
|
68
|
+
attrs['id'] = odtElement['@id'];
|
|
57
69
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (
|
|
61
|
-
odtElement['@continue-list'] &&
|
|
62
|
-
listTracker.listNumberings.has(odtElement['@continue-list'])
|
|
63
|
-
) {
|
|
64
|
-
listNumbering = listTracker.listNumberings.get(
|
|
65
|
-
odtElement['@continue-list'],
|
|
66
|
-
);
|
|
67
|
-
isContinue = true;
|
|
70
|
+
if (odtElement['@continue-list']) {
|
|
71
|
+
attrs['continue'] = odtElement['@continue-list'];
|
|
68
72
|
}
|
|
69
73
|
if (odtElement['@continue-numbering']) {
|
|
70
|
-
|
|
71
|
-
isContinue = true;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (!listNumbering) {
|
|
75
|
-
listNumbering = new ListNumbering();
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (isContinue) {
|
|
79
|
-
listTracker.preserveMinLevel = 999;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (listId) {
|
|
83
|
-
listTracker.listNumberings.set(listId, listNumbering);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
listTracker.lastNumbering = listNumbering;
|
|
87
|
-
|
|
88
|
-
if (listTracker.preserveMinLevel <= list.level) {
|
|
89
|
-
listNumbering.clearAbove(list.level - 1);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (nodeTypeName === 'ordered_list') {
|
|
93
|
-
attrs['start'] = listNumbering.levels[list.level] || 1;
|
|
74
|
+
attrs['continue'] = '_last';
|
|
94
75
|
}
|
|
95
76
|
|
|
96
77
|
ctx.openNode();
|
|
@@ -99,18 +80,14 @@ export function getListNodesHandlers(): Record<string, NodeHandler> {
|
|
|
99
80
|
'list-item': item,
|
|
100
81
|
}));
|
|
101
82
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
listNumbering.levels[list.level] += children.length;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
ctx.closeNode(nodeTypeName, attrs);
|
|
83
|
+
iterateChildren(children, (child) => {
|
|
84
|
+
ctx.handle(child.tag, child.value);
|
|
85
|
+
});
|
|
111
86
|
|
|
112
|
-
if (
|
|
113
|
-
|
|
87
|
+
if (ctx.current.content.length === 0) {
|
|
88
|
+
ctx.dropNode();
|
|
89
|
+
} else {
|
|
90
|
+
ctx.closeNode(nodeTypeName, attrs);
|
|
114
91
|
}
|
|
115
92
|
|
|
116
93
|
listTracker.listStack.pop();
|
|
@@ -122,7 +99,7 @@ export function getListNodesHandlers(): Record<string, NodeHandler> {
|
|
|
122
99
|
(child) => ctx.handle(child.tag, child.value),
|
|
123
100
|
);
|
|
124
101
|
|
|
125
|
-
const attrs = {};
|
|
102
|
+
const attrs: Record<string, string> = {};
|
|
126
103
|
attrs.markup = '* ';
|
|
127
104
|
|
|
128
105
|
ctx.closeNode('list_item', attrs);
|
|
@@ -1,36 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Node } from 'prosemirror-model';
|
|
2
2
|
import { Transaction } from 'prosemirror-state';
|
|
3
3
|
|
|
4
4
|
import type { Command } from '@kerebron/editor/commands';
|
|
5
5
|
|
|
6
|
-
function onlyHasCodeMarkedText(
|
|
7
|
-
paragraph: Node,
|
|
8
|
-
codeMarkType: MarkType,
|
|
9
|
-
): boolean {
|
|
10
|
-
if (paragraph.content.size === 0) {
|
|
11
|
-
return paragraph.marks.some((mark) => mark.type.name === codeMarkType.name);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
let allAreCodeMarked = true;
|
|
15
|
-
|
|
16
|
-
paragraph.content.forEach((child) => {
|
|
17
|
-
if (
|
|
18
|
-
!child.isText ||
|
|
19
|
-
!child.marks.some((mark) => mark.type.name === codeMarkType.name)
|
|
20
|
-
) {
|
|
21
|
-
allAreCodeMarked = false;
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
return allAreCodeMarked;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
interface ParagraphsToMerge {
|
|
29
|
-
startPos: number;
|
|
30
|
-
endPos: number;
|
|
31
|
-
innerText: string;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
6
|
export const convertCodeParagraphsToCodeBlocks: Command = (
|
|
35
7
|
state,
|
|
36
8
|
dispatch,
|
|
@@ -39,80 +11,53 @@ export const convertCodeParagraphsToCodeBlocks: Command = (
|
|
|
39
11
|
const schema = state.schema;
|
|
40
12
|
let tr: Transaction = state.tr;
|
|
41
13
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
function flushCodeBlock() {
|
|
45
|
-
if (paragraphsToMerge === null) {
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const textNode = schema.text(paragraphsToMerge.innerText);
|
|
50
|
-
const codeBlock = schema.nodes.code_block.createAndFill(null, [textNode]);
|
|
51
|
-
|
|
52
|
-
const startPos = tr.mapping.map(paragraphsToMerge.startPos);
|
|
53
|
-
const endPos = tr.mapping.map(paragraphsToMerge.endPos);
|
|
54
|
-
|
|
55
|
-
if (codeBlock) {
|
|
56
|
-
tr.replaceRangeWith(startPos, endPos, codeBlock);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
paragraphsToMerge = null;
|
|
60
|
-
}
|
|
14
|
+
const markCodeType = schema.marks.code;
|
|
61
15
|
|
|
62
|
-
|
|
63
|
-
if (
|
|
64
|
-
|
|
65
|
-
|
|
16
|
+
doc.descendants((node, pos) => {
|
|
17
|
+
if (node.type.name === 'paragraph') {
|
|
18
|
+
let codeText = '';
|
|
19
|
+
let codeSize = 0;
|
|
20
|
+
for (let childNo = 0; childNo < node.childCount; childNo++) {
|
|
21
|
+
const child = node.child(childNo);
|
|
22
|
+
|
|
23
|
+
if (child.type.name === 'br') {
|
|
24
|
+
codeText += '\n';
|
|
25
|
+
codeSize += child.nodeSize;
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
66
28
|
|
|
67
|
-
|
|
29
|
+
if (child.marks.some((mark) => mark.type === markCodeType)) {
|
|
30
|
+
codeText += child.text || child.textBetween(0, child.content.size);
|
|
31
|
+
codeSize += child.nodeSize;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
68
34
|
|
|
69
|
-
|
|
70
|
-
if (node.isText) {
|
|
71
|
-
retVal += node.text;
|
|
72
|
-
} else {
|
|
73
|
-
retVal = '@TODO: node.type ' + node.type;
|
|
35
|
+
break;
|
|
74
36
|
}
|
|
75
|
-
});
|
|
76
37
|
|
|
77
|
-
|
|
78
|
-
|
|
38
|
+
if (codeSize > 0) {
|
|
39
|
+
const startPos = tr.mapping.map(pos);
|
|
40
|
+
const endPos = tr.mapping.map(pos + 1 + codeSize);
|
|
79
41
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
42
|
+
const textNode = schema.text(codeText);
|
|
43
|
+
const codeBlock = schema.nodes.code_block.createAndFill(null, [
|
|
44
|
+
textNode,
|
|
45
|
+
]);
|
|
84
46
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
paragraphsToMerge = {
|
|
88
|
-
startPos: pos,
|
|
89
|
-
endPos: pos + node.nodeSize,
|
|
90
|
-
innerText: nodesToText(node.content),
|
|
91
|
-
};
|
|
92
|
-
} else {
|
|
93
|
-
paragraphsToMerge = {
|
|
94
|
-
startPos: paragraphsToMerge.startPos,
|
|
95
|
-
endPos: pos + node.nodeSize,
|
|
96
|
-
innerText: paragraphsToMerge.innerText + '\n' +
|
|
97
|
-
nodesToText(node.content),
|
|
98
|
-
};
|
|
47
|
+
if (codeBlock) {
|
|
48
|
+
tr = tr.replaceRangeWith(startPos, endPos, codeBlock);
|
|
99
49
|
}
|
|
100
|
-
return;
|
|
101
50
|
}
|
|
102
|
-
}
|
|
103
51
|
|
|
104
|
-
|
|
105
|
-
|
|
52
|
+
if (codeSize > 0 && codeSize + 2 === node.nodeSize) {
|
|
53
|
+
// tr = tr.deleteRange(tr.mapping.map(pos), tr.mapping.map(pos))
|
|
54
|
+
}
|
|
106
55
|
}
|
|
107
56
|
});
|
|
108
57
|
|
|
109
|
-
if (paragraphsToMerge !== null) {
|
|
110
|
-
flushCodeBlock();
|
|
111
|
-
}
|
|
112
|
-
|
|
113
58
|
if (dispatch) {
|
|
114
59
|
dispatch(tr);
|
|
115
60
|
}
|
|
116
61
|
|
|
117
|
-
return tr.
|
|
62
|
+
return tr.docChanged;
|
|
118
63
|
};
|