@kerebron/extension-odt 0.0.13 → 0.1.0
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/esm/editor/src/CoreEditor.d.ts +3 -8
- package/esm/editor/src/CoreEditor.d.ts.map +1 -1
- package/esm/editor/src/CoreEditor.js +12 -30
- package/esm/editor/src/Extension.d.ts +1 -1
- package/esm/editor/src/Extension.d.ts.map +1 -1
- package/esm/editor/src/Extension.js +1 -1
- package/esm/editor/src/ExtensionManager.js +2 -2
- package/esm/editor/src/mod.d.ts +1 -0
- package/esm/editor/src/mod.d.ts.map +1 -1
- package/esm/editor/src/mod.js +1 -0
- package/esm/editor/src/nodeToTreeString.d.ts +4 -0
- package/esm/editor/src/nodeToTreeString.d.ts.map +1 -0
- package/esm/editor/src/nodeToTreeString.js +53 -0
- package/esm/editor/src/utilities/createNodeFromContent.d.ts +2 -6
- package/esm/editor/src/utilities/createNodeFromContent.d.ts.map +1 -1
- package/esm/editor/src/utilities/createNodeFromContent.js +5 -90
- package/esm/extension-odt/src/ExtensionOdt.d.ts +7 -2
- package/esm/extension-odt/src/ExtensionOdt.d.ts.map +1 -1
- package/esm/extension-odt/src/ExtensionOdt.js +23 -5
- package/esm/extension-odt/src/OdtParser.d.ts +72 -3
- package/esm/extension-odt/src/OdtParser.d.ts.map +1 -1
- package/esm/extension-odt/src/OdtParser.js +375 -113
- package/esm/extension-odt/src/postprocess/convertCodeParagraphsToCodeBlocks.d.ts +3 -0
- package/esm/extension-odt/src/postprocess/convertCodeParagraphsToCodeBlocks.d.ts.map +1 -0
- package/esm/extension-odt/src/postprocess/convertCodeParagraphsToCodeBlocks.js +72 -0
- package/esm/extension-odt/src/postprocess/fixContinuedLists.d.ts +3 -0
- package/esm/extension-odt/src/postprocess/fixContinuedLists.d.ts.map +1 -0
- package/esm/extension-odt/src/postprocess/fixContinuedLists.js +83 -0
- package/esm/extension-odt/src/postprocess/postProcess.d.ts +3 -0
- package/esm/extension-odt/src/postprocess/postProcess.d.ts.map +1 -0
- package/esm/extension-odt/src/postprocess/postProcess.js +10 -0
- package/esm/extension-odt/src/postprocess/removeUnusedBookmarks.d.ts +3 -0
- package/esm/extension-odt/src/postprocess/removeUnusedBookmarks.d.ts.map +1 -0
- package/esm/extension-odt/src/postprocess/removeUnusedBookmarks.js +27 -0
- package/package.json +4 -4
- package/esm/editor/src/debugDoc.d.ts +0 -3
- package/esm/editor/src/debugDoc.d.ts.map +0 -1
- package/esm/editor/src/debugDoc.js +0 -33
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Mark, } from 'prosemirror-model';
|
|
2
|
+
const COURIER_FONTS = ['Courier New', 'Courier', 'Roboto Mono'];
|
|
2
3
|
function attrs(spec, token, style) {
|
|
3
4
|
if (spec.getAttrs)
|
|
4
5
|
return spec.getAttrs(token, style);
|
|
@@ -24,11 +25,16 @@ function resolveStyle(stylesTree, automaticStyles, name) {
|
|
|
24
25
|
}
|
|
25
26
|
style['styles'] = [name];
|
|
26
27
|
if (style['@parent-style-name']) {
|
|
27
|
-
const
|
|
28
|
-
if (
|
|
29
|
-
const styles = [...style['styles'], ...
|
|
28
|
+
const parentStyle = resolveStyle(stylesTree, automaticStyles, style['@parent-style-name']);
|
|
29
|
+
if (parentStyle) {
|
|
30
|
+
const styles = [...style['styles'], ...parentStyle['styles']];
|
|
31
|
+
for (const key in style) {
|
|
32
|
+
if (typeof style[key] === 'undefined') {
|
|
33
|
+
delete style[key];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
30
36
|
style = {
|
|
31
|
-
...
|
|
37
|
+
...parentStyle,
|
|
32
38
|
...style,
|
|
33
39
|
styles,
|
|
34
40
|
};
|
|
@@ -37,13 +43,19 @@ function resolveStyle(stylesTree, automaticStyles, name) {
|
|
|
37
43
|
return style;
|
|
38
44
|
}
|
|
39
45
|
class OdtParseState {
|
|
40
|
-
constructor(schema, stylesTree, automaticStyles) {
|
|
46
|
+
constructor(schema, tokens, stylesTree, automaticStyles) {
|
|
41
47
|
Object.defineProperty(this, "schema", {
|
|
42
48
|
enumerable: true,
|
|
43
49
|
configurable: true,
|
|
44
50
|
writable: true,
|
|
45
51
|
value: schema
|
|
46
52
|
});
|
|
53
|
+
Object.defineProperty(this, "tokens", {
|
|
54
|
+
enumerable: true,
|
|
55
|
+
configurable: true,
|
|
56
|
+
writable: true,
|
|
57
|
+
value: tokens
|
|
58
|
+
});
|
|
47
59
|
Object.defineProperty(this, "stylesTree", {
|
|
48
60
|
enumerable: true,
|
|
49
61
|
configurable: true,
|
|
@@ -62,6 +74,18 @@ class OdtParseState {
|
|
|
62
74
|
writable: true,
|
|
63
75
|
value: void 0
|
|
64
76
|
});
|
|
77
|
+
Object.defineProperty(this, "textMarks", {
|
|
78
|
+
enumerable: true,
|
|
79
|
+
configurable: true,
|
|
80
|
+
writable: true,
|
|
81
|
+
value: new Set()
|
|
82
|
+
});
|
|
83
|
+
Object.defineProperty(this, "nextTextMarks", {
|
|
84
|
+
enumerable: true,
|
|
85
|
+
configurable: true,
|
|
86
|
+
writable: true,
|
|
87
|
+
value: new Set()
|
|
88
|
+
});
|
|
65
89
|
this.stack = [];
|
|
66
90
|
this.openNode(schema.topNodeType, null);
|
|
67
91
|
}
|
|
@@ -78,17 +102,26 @@ class OdtParseState {
|
|
|
78
102
|
if (!text)
|
|
79
103
|
return;
|
|
80
104
|
let top = this.top(), nodes = top.content, last = nodes[nodes.length - 1];
|
|
81
|
-
let
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
105
|
+
let marks = top.marks;
|
|
106
|
+
for (const textMark of this.textMarks) {
|
|
107
|
+
const markType = this.schema.marks[textMark.markName];
|
|
108
|
+
const mark = markType.create(textMark.markAttributes || {});
|
|
109
|
+
marks = mark.addToSet(marks);
|
|
110
|
+
}
|
|
111
|
+
for (const textMark of this.nextTextMarks) {
|
|
112
|
+
const markType = this.schema.marks[textMark.markName];
|
|
113
|
+
const mark = markType.create(textMark.markAttributes || {});
|
|
114
|
+
marks = mark.addToSet(marks);
|
|
115
|
+
}
|
|
116
|
+
this.nextTextMarks.clear();
|
|
117
|
+
let node = this.schema.text(text, marks), merged;
|
|
86
118
|
nodes.push(node);
|
|
87
119
|
}
|
|
88
120
|
// Adds the given mark to the set of active marks.
|
|
89
121
|
openMark(mark) {
|
|
90
122
|
let top = this.top();
|
|
91
123
|
top.marks = mark.addToSet(top.marks);
|
|
124
|
+
return mark.type;
|
|
92
125
|
}
|
|
93
126
|
// Removes the given mark from the set of active marks.
|
|
94
127
|
closeMark(mark) {
|
|
@@ -96,9 +129,12 @@ class OdtParseState {
|
|
|
96
129
|
top.marks = mark.removeFromSet(top.marks);
|
|
97
130
|
}
|
|
98
131
|
// Add a node at the current position.
|
|
99
|
-
addNode(type, attrs, content) {
|
|
132
|
+
addNode(type, attrs, content, marks = Mark.none) {
|
|
100
133
|
let top = this.top();
|
|
101
|
-
|
|
134
|
+
if (top?.marks) {
|
|
135
|
+
marks = [...top.marks, ...marks];
|
|
136
|
+
}
|
|
137
|
+
let node = type.createAndFill(attrs, content, marks);
|
|
102
138
|
if (!node)
|
|
103
139
|
return null;
|
|
104
140
|
this.push(node);
|
|
@@ -106,37 +142,58 @@ class OdtParseState {
|
|
|
106
142
|
}
|
|
107
143
|
// Wrap subsequent content in a node of the given type.
|
|
108
144
|
openNode(type, attrs) {
|
|
109
|
-
// console.log('openNode', type.name, attrs);
|
|
110
145
|
this.stack.push({
|
|
111
146
|
type: type,
|
|
112
147
|
attrs: attrs,
|
|
113
148
|
content: [],
|
|
114
|
-
marks: Mark.none
|
|
149
|
+
marks: Mark.none
|
|
115
150
|
});
|
|
116
151
|
}
|
|
117
152
|
// Close and return the node that is currently on top of the stack.
|
|
118
|
-
closeNode() {
|
|
153
|
+
closeNode(marks = Mark.none) {
|
|
119
154
|
let info = this.stack.pop();
|
|
120
|
-
|
|
121
|
-
return this.addNode(info.type, info.attrs, info.content);
|
|
155
|
+
return this.addNode(info.type, info.attrs, info.content, marks);
|
|
122
156
|
}
|
|
123
157
|
handleElement(nodeType, element) {
|
|
124
|
-
const spec = tokens[nodeType];
|
|
158
|
+
const spec = this.tokens[nodeType];
|
|
125
159
|
if (!spec) {
|
|
126
160
|
console.warn('No spec for:', nodeType, element, this.stack.map((item) => item.type.name));
|
|
127
161
|
return;
|
|
128
162
|
}
|
|
129
|
-
|
|
163
|
+
if (spec.custom) {
|
|
164
|
+
spec.custom(this, element);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
130
167
|
const children = spec.children ? spec.children(element) : [];
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
168
|
+
const style = ('object' === typeof element && element['@style-name']) ? resolveStyle(this.stylesTree, this.automaticStyles, element['@style-name']) : {};
|
|
169
|
+
const markToClose = [];
|
|
170
|
+
const textProperties = style && style['text-properties'] || {};
|
|
171
|
+
const marks = [];
|
|
172
|
+
if (COURIER_FONTS.indexOf(textProperties['@font-name'] || '') > -1) {
|
|
173
|
+
this.textMarks.add({
|
|
174
|
+
markName: 'code',
|
|
175
|
+
markAttributes: {}
|
|
176
|
+
});
|
|
177
|
+
const markType = this.schema.mark('code');
|
|
178
|
+
marks.push(markType);
|
|
179
|
+
}
|
|
180
|
+
// if (style.textProperties?.fontStyle === 'italic' && style.textProperties?.fontWeight === 'bold') {
|
|
181
|
+
// const block = this.chunks.createNode('BI');
|
|
182
|
+
// this.chunks.append(currentTagNode, block);
|
|
183
|
+
// currentTagNode = block;
|
|
184
|
+
// } else
|
|
185
|
+
if (textProperties['@font-style'] === 'italic') {
|
|
186
|
+
const markType = this.schema.marks['em'];
|
|
187
|
+
markToClose.push(this.openMark(markType.create(attrs(spec, element, style))));
|
|
188
|
+
}
|
|
189
|
+
else if (textProperties['@font-weight'] === 'bold') {
|
|
190
|
+
const markType = this.schema.marks['strong'];
|
|
191
|
+
markToClose.push(this.openMark(markType.create(attrs(spec, element, style))));
|
|
135
192
|
}
|
|
136
193
|
if (spec.block) {
|
|
137
194
|
let block = spec.block;
|
|
138
195
|
if ('string' !== typeof block) {
|
|
139
|
-
block = block(element, style);
|
|
196
|
+
block = block(element, style)[0];
|
|
140
197
|
}
|
|
141
198
|
let nodeType = this.schema.nodeType(block);
|
|
142
199
|
this.openNode(nodeType, attrs(spec, element, style));
|
|
@@ -146,12 +203,12 @@ class OdtParseState {
|
|
|
146
203
|
});
|
|
147
204
|
}
|
|
148
205
|
// this.addText(withoutTrailingNewline(tok.content));
|
|
149
|
-
this.closeNode();
|
|
206
|
+
this.closeNode(marks);
|
|
150
207
|
}
|
|
151
208
|
else if (spec.node) {
|
|
152
209
|
}
|
|
153
210
|
else if (spec.mark) {
|
|
154
|
-
|
|
211
|
+
const markType = this.schema.marks[spec.mark];
|
|
155
212
|
this.openMark(markType.create(attrs(spec, element, style)));
|
|
156
213
|
if (children) {
|
|
157
214
|
iterateChildren(children, (nodeType, node) => {
|
|
@@ -170,6 +227,13 @@ class OdtParseState {
|
|
|
170
227
|
});
|
|
171
228
|
}
|
|
172
229
|
}
|
|
230
|
+
while (markToClose.length > 0) {
|
|
231
|
+
const markType = markToClose.pop();
|
|
232
|
+
this.closeMark(markType);
|
|
233
|
+
}
|
|
234
|
+
if (COURIER_FONTS.indexOf(textProperties['@font-name'] || '') > -1) {
|
|
235
|
+
this.textMarks.forEach(x => x.markName === 'code' ? this.textMarks.delete(x) : x);
|
|
236
|
+
}
|
|
173
237
|
}
|
|
174
238
|
}
|
|
175
239
|
function iterateChildren(nodes, callback) {
|
|
@@ -207,105 +271,303 @@ function iterateEnum($value) {
|
|
|
207
271
|
return item;
|
|
208
272
|
});
|
|
209
273
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
},
|
|
238
|
-
'list-item': {
|
|
239
|
-
block: 'list_item',
|
|
240
|
-
children: (odtElement) => iterateEnum(odtElement.$value),
|
|
241
|
-
},
|
|
242
|
-
'table': {
|
|
243
|
-
block: 'table',
|
|
244
|
-
children: (odtElement) => odtElement['table-row'].map((item) => ({ 'table-row': item })),
|
|
245
|
-
},
|
|
246
|
-
'table-row': {
|
|
247
|
-
block: 'table_row',
|
|
248
|
-
children: (odtElement) => odtElement['table-cell'].map((item) => ({ 'table-cell': item })),
|
|
249
|
-
},
|
|
250
|
-
'table-cell': {
|
|
251
|
-
block: 'table_cell',
|
|
252
|
-
children: (odtElement) => iterateEnum(odtElement.$value),
|
|
253
|
-
},
|
|
254
|
-
'a': {
|
|
255
|
-
mark: 'link',
|
|
256
|
-
getAttrs: (tok) => ({
|
|
257
|
-
href: tok['@href'],
|
|
258
|
-
// title: tok.attrGet('title') || null,
|
|
259
|
-
}),
|
|
260
|
-
children: (odtElement) => odtElement['span'].map(item => ({ 'span': item }))
|
|
261
|
-
},
|
|
262
|
-
'$value': {
|
|
263
|
-
children: (odtElement) => iterateEnum(odtElement),
|
|
264
|
-
},
|
|
265
|
-
'$text': {
|
|
266
|
-
// TODO: fix trimming: https://github.com/tafia/quick-xml/issues/285
|
|
267
|
-
text: (odtElement) => String(odtElement || ''),
|
|
268
|
-
},
|
|
269
|
-
's': {
|
|
270
|
-
text: (odtElement) => {
|
|
271
|
-
const chars = odtElement['@c'] || 1;
|
|
272
|
-
return ' '.substring(0, chars);
|
|
273
|
-
},
|
|
274
|
-
},
|
|
275
|
-
'tab': {
|
|
276
|
-
text: (odtElement) => '\t',
|
|
277
|
-
},
|
|
278
|
-
'table-of-content': {
|
|
279
|
-
block: 'paragraph',
|
|
280
|
-
children: (odtElement) => odtElement['index-body']['p'] || [],
|
|
281
|
-
},
|
|
282
|
-
'frame': {
|
|
283
|
-
ignore: true,
|
|
284
|
-
},
|
|
285
|
-
'rect': {
|
|
286
|
-
ignore: true,
|
|
287
|
-
},
|
|
288
|
-
'bookmark': {
|
|
289
|
-
ignore: true,
|
|
290
|
-
},
|
|
291
|
-
'annotation': {
|
|
292
|
-
ignore: true,
|
|
293
|
-
},
|
|
294
|
-
};
|
|
274
|
+
class ListNumbering {
|
|
275
|
+
constructor() {
|
|
276
|
+
Object.defineProperty(this, "levels", {
|
|
277
|
+
enumerable: true,
|
|
278
|
+
configurable: true,
|
|
279
|
+
writable: true,
|
|
280
|
+
value: {}
|
|
281
|
+
});
|
|
282
|
+
Object.defineProperty(this, "levelNodes", {
|
|
283
|
+
enumerable: true,
|
|
284
|
+
configurable: true,
|
|
285
|
+
writable: true,
|
|
286
|
+
value: {}
|
|
287
|
+
});
|
|
288
|
+
for (let i = 0; i < 20; i++) {
|
|
289
|
+
this.levels[i] = 1;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
clearAbove(level) {
|
|
293
|
+
for (let i = level + 1; i < 20; i++) {
|
|
294
|
+
this.levels[i] = 1;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
setLevelNode(level, node) {
|
|
298
|
+
this.levelNodes[level] = node;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
295
301
|
export class OdtParser {
|
|
296
|
-
constructor(schema) {
|
|
302
|
+
constructor(schema, config = {}) {
|
|
297
303
|
Object.defineProperty(this, "schema", {
|
|
298
304
|
enumerable: true,
|
|
299
305
|
configurable: true,
|
|
300
306
|
writable: true,
|
|
301
307
|
value: schema
|
|
302
308
|
});
|
|
309
|
+
Object.defineProperty(this, "config", {
|
|
310
|
+
enumerable: true,
|
|
311
|
+
configurable: true,
|
|
312
|
+
writable: true,
|
|
313
|
+
value: config
|
|
314
|
+
});
|
|
315
|
+
Object.defineProperty(this, "listStack", {
|
|
316
|
+
enumerable: true,
|
|
317
|
+
configurable: true,
|
|
318
|
+
writable: true,
|
|
319
|
+
value: []
|
|
320
|
+
});
|
|
321
|
+
Object.defineProperty(this, "listNumberings", {
|
|
322
|
+
enumerable: true,
|
|
323
|
+
configurable: true,
|
|
324
|
+
writable: true,
|
|
325
|
+
value: new Map()
|
|
326
|
+
});
|
|
327
|
+
Object.defineProperty(this, "lastNumbering", {
|
|
328
|
+
enumerable: true,
|
|
329
|
+
configurable: true,
|
|
330
|
+
writable: true,
|
|
331
|
+
value: void 0
|
|
332
|
+
});
|
|
333
|
+
Object.defineProperty(this, "preserveMinLevel", {
|
|
334
|
+
enumerable: true,
|
|
335
|
+
configurable: true,
|
|
336
|
+
writable: true,
|
|
337
|
+
value: 999
|
|
338
|
+
});
|
|
303
339
|
// this.tokenHandlers = tokenHandlers(schema, tokens);
|
|
304
340
|
}
|
|
305
341
|
parse(files) {
|
|
306
342
|
const contentTree = files.contentTree;
|
|
307
343
|
const stylesTree = files.stylesTree;
|
|
308
|
-
const
|
|
344
|
+
const automaticStyles = contentTree['automatic-styles'];
|
|
345
|
+
const tokens = {
|
|
346
|
+
'body': {
|
|
347
|
+
children: (odtElement) => iterateEnum(odtElement.text?.$value),
|
|
348
|
+
},
|
|
349
|
+
'p': {
|
|
350
|
+
block: (odtElement, style) => {
|
|
351
|
+
if (style.styles.find((item) => item.startsWith('Heading_20_'))) {
|
|
352
|
+
return ['heading'];
|
|
353
|
+
}
|
|
354
|
+
return ['paragraph'];
|
|
355
|
+
},
|
|
356
|
+
getAttrs: (odtElement, style) => {
|
|
357
|
+
const heading = style.styles.find((item) => item.startsWith('Heading_20_'));
|
|
358
|
+
if (heading) {
|
|
359
|
+
return {
|
|
360
|
+
level: parseInt(heading.substring('Heading_20_'.length)),
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
},
|
|
364
|
+
children: (odtElement) => iterateEnum(odtElement.$value),
|
|
365
|
+
},
|
|
366
|
+
'span': {
|
|
367
|
+
children: (odtElement) => iterateEnum(odtElement.$value),
|
|
368
|
+
},
|
|
369
|
+
'list': {
|
|
370
|
+
custom: (state, odtElement) => {
|
|
371
|
+
const list = {
|
|
372
|
+
level: this.listStack.length + 1,
|
|
373
|
+
odtElement
|
|
374
|
+
};
|
|
375
|
+
this.listStack.push(list);
|
|
376
|
+
let style = {};
|
|
377
|
+
let listId = null;
|
|
378
|
+
for (let i = this.listStack.length - 1; i >= 0; i--) {
|
|
379
|
+
const element = this.listStack[i].odtElement;
|
|
380
|
+
if (!listId) {
|
|
381
|
+
if (element['@id']) {
|
|
382
|
+
listId = element['@id'];
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
if (!style['@style-name']) {
|
|
386
|
+
style = ('object' === typeof element && element['@style-name']) ? resolveStyle(stylesTree, automaticStyles, element['@style-name']) : {};
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
let nodeTypeName = 'bullet_list';
|
|
390
|
+
const attrs = {};
|
|
391
|
+
if (style) {
|
|
392
|
+
const numLevelStyle = style['list-level-style-number'].find(levelStyle => parseInt(levelStyle['@level']) === list.level);
|
|
393
|
+
if (numLevelStyle) {
|
|
394
|
+
attrs['type'] = numLevelStyle['@num-format'] || '1';
|
|
395
|
+
nodeTypeName = 'ordered_list';
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
let listNumbering = null;
|
|
399
|
+
if (listId && this.listNumberings.has(listId)) {
|
|
400
|
+
listNumbering = this.listNumberings.get(listId);
|
|
401
|
+
}
|
|
402
|
+
let isContinue = false;
|
|
403
|
+
if (odtElement['@continue-list'] && this.listNumberings.has(odtElement['@continue-list'])) {
|
|
404
|
+
listNumbering = this.listNumberings.get(odtElement['@continue-list']);
|
|
405
|
+
isContinue = true;
|
|
406
|
+
}
|
|
407
|
+
if (odtElement['@continue-numbering']) {
|
|
408
|
+
listNumbering = this.lastNumbering;
|
|
409
|
+
isContinue = true;
|
|
410
|
+
}
|
|
411
|
+
if (!listNumbering) {
|
|
412
|
+
listNumbering = new ListNumbering();
|
|
413
|
+
}
|
|
414
|
+
if (isContinue) {
|
|
415
|
+
this.preserveMinLevel = 999;
|
|
416
|
+
}
|
|
417
|
+
if (listId) {
|
|
418
|
+
this.listNumberings.set(listId, listNumbering);
|
|
419
|
+
}
|
|
420
|
+
this.lastNumbering = listNumbering;
|
|
421
|
+
if (this.preserveMinLevel <= list.level) {
|
|
422
|
+
listNumbering.clearAbove(list.level - 1);
|
|
423
|
+
}
|
|
424
|
+
if (nodeTypeName === 'ordered_list') {
|
|
425
|
+
attrs['start'] = listNumbering.levels[list.level] || 1;
|
|
426
|
+
}
|
|
427
|
+
let nodeType = this.schema.nodeType(nodeTypeName);
|
|
428
|
+
state.openNode(nodeType, attrs);
|
|
429
|
+
const children = odtElement['list-item'].map((item) => ({ 'list-item': item }));
|
|
430
|
+
if (children) {
|
|
431
|
+
iterateChildren(children, (nodeType, node) => {
|
|
432
|
+
state.handleElement(nodeType, node);
|
|
433
|
+
});
|
|
434
|
+
listNumbering.levels[list.level] += children.length;
|
|
435
|
+
}
|
|
436
|
+
state.closeNode();
|
|
437
|
+
if (this.preserveMinLevel >= list.level) {
|
|
438
|
+
this.preserveMinLevel = list.level;
|
|
439
|
+
}
|
|
440
|
+
this.listStack.pop();
|
|
441
|
+
}
|
|
442
|
+
},
|
|
443
|
+
'list-item': {
|
|
444
|
+
block: 'list_item',
|
|
445
|
+
children: (odtElement) => iterateEnum(odtElement.$value),
|
|
446
|
+
},
|
|
447
|
+
'table': {
|
|
448
|
+
block: 'table',
|
|
449
|
+
children: (odtElement) => odtElement['table-row'].map((item) => ({ 'table-row': item })),
|
|
450
|
+
},
|
|
451
|
+
'table-row': {
|
|
452
|
+
block: 'table_row',
|
|
453
|
+
children: (odtElement) => odtElement['table-cell'].map((item) => ({ 'table-cell': item })),
|
|
454
|
+
},
|
|
455
|
+
'table-cell': {
|
|
456
|
+
block: 'table_cell',
|
|
457
|
+
children: (odtElement) => iterateEnum(odtElement.$value),
|
|
458
|
+
},
|
|
459
|
+
'a': {
|
|
460
|
+
mark: 'link',
|
|
461
|
+
getAttrs: (tok) => {
|
|
462
|
+
let href = tok['@href'];
|
|
463
|
+
if (this.config.linkFromRewriter) {
|
|
464
|
+
href = this.config.linkFromRewriter(href);
|
|
465
|
+
}
|
|
466
|
+
return {
|
|
467
|
+
href,
|
|
468
|
+
// title: tok.attrGet('title') || null,
|
|
469
|
+
};
|
|
470
|
+
},
|
|
471
|
+
children: (odtElement) => iterateEnum(odtElement.$value),
|
|
472
|
+
},
|
|
473
|
+
'$value': {
|
|
474
|
+
children: (odtElement) => iterateEnum(odtElement),
|
|
475
|
+
},
|
|
476
|
+
'$text': {
|
|
477
|
+
// TODO: fix trimming: https://github.com/tafia/quick-xml/issues/285
|
|
478
|
+
text: (odtElement) => String(odtElement || ''),
|
|
479
|
+
},
|
|
480
|
+
's': {
|
|
481
|
+
text: (odtElement) => {
|
|
482
|
+
const chars = odtElement['@c'] || 1;
|
|
483
|
+
return ' '.substring(0, chars);
|
|
484
|
+
},
|
|
485
|
+
},
|
|
486
|
+
'tab': {
|
|
487
|
+
text: (odtElement) => '\t',
|
|
488
|
+
},
|
|
489
|
+
'line-break': {
|
|
490
|
+
block: 'br'
|
|
491
|
+
},
|
|
492
|
+
'soft-page-break': {
|
|
493
|
+
block: 'br'
|
|
494
|
+
},
|
|
495
|
+
'table-of-content': {
|
|
496
|
+
block: 'paragraph',
|
|
497
|
+
children: (odtElement) => odtElement['index-body']['p'] || [],
|
|
498
|
+
},
|
|
499
|
+
'change-start': {
|
|
500
|
+
custom(state) {
|
|
501
|
+
state.textMarks.add({
|
|
502
|
+
markName: 'change',
|
|
503
|
+
markAttributes: {}
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
},
|
|
507
|
+
'change-end': {
|
|
508
|
+
custom(state) {
|
|
509
|
+
state.textMarks.forEach(x => x.markName === 'change' ? state.textMarks.delete(x) : x);
|
|
510
|
+
}
|
|
511
|
+
},
|
|
512
|
+
'frame': {
|
|
513
|
+
custom: (state, odtElement) => {
|
|
514
|
+
if (odtElement.object && odtElement.object['@href']) { // TODO MathML
|
|
515
|
+
// const fileName= drawFrame.object.href.replace(/\s/g, '_').replace(/^\.\//, '') + '.xml';
|
|
516
|
+
// try {
|
|
517
|
+
// const mathMl = this.xmlMap[fileName];
|
|
518
|
+
// if (mathMl && mathMl.indexOf('<math ') > -1) {
|
|
519
|
+
// const node = this.chunks.createNode('MATHML');
|
|
520
|
+
// const latex = MathMLToLaTeX.convert(mathMl);
|
|
521
|
+
// this.chunks.appendText(node, latex);
|
|
522
|
+
// this.chunks.append(currentTagNode, node);
|
|
523
|
+
// }
|
|
524
|
+
// } catch (err) {
|
|
525
|
+
// console.warn(err);
|
|
526
|
+
// }
|
|
527
|
+
}
|
|
528
|
+
if (odtElement.image && odtElement.image['@href']) { // TODO links rewrite
|
|
529
|
+
const nodeType = this.schema.nodeType('image');
|
|
530
|
+
const alt = odtElement.description?.value || '';
|
|
531
|
+
state.addNode(nodeType, {
|
|
532
|
+
src: odtElement.image['@href'],
|
|
533
|
+
alt
|
|
534
|
+
}, []);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
},
|
|
538
|
+
'rect': {
|
|
539
|
+
ignore: true,
|
|
540
|
+
},
|
|
541
|
+
'bookmark': {
|
|
542
|
+
custom(state, element) {
|
|
543
|
+
state.nextTextMarks.add({
|
|
544
|
+
markName: 'bookmark',
|
|
545
|
+
markAttributes: {
|
|
546
|
+
id: element['@name']
|
|
547
|
+
}
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
},
|
|
551
|
+
'bookmark-start': {
|
|
552
|
+
custom(state, element) {
|
|
553
|
+
state.textMarks.add({
|
|
554
|
+
markName: 'bookmark',
|
|
555
|
+
markAttributes: {
|
|
556
|
+
id: element['@name']
|
|
557
|
+
}
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
},
|
|
561
|
+
'bookmark-end': {
|
|
562
|
+
custom(state, element) {
|
|
563
|
+
state.textMarks.forEach(x => x.markName === 'bookmark' && x.markAttributes.id === element['@name'] ? state.textMarks.delete(x) : x);
|
|
564
|
+
}
|
|
565
|
+
},
|
|
566
|
+
'annotation': {
|
|
567
|
+
ignore: true,
|
|
568
|
+
},
|
|
569
|
+
};
|
|
570
|
+
const state = new OdtParseState(this.schema, tokens, stylesTree, contentTree['automatic-styles']);
|
|
309
571
|
state.handleElement('body', contentTree.body);
|
|
310
572
|
let doc;
|
|
311
573
|
do {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convertCodeParagraphsToCodeBlocks.d.ts","sourceRoot":"","sources":["../../../../src/extension-odt/src/postprocess/convertCodeParagraphsToCodeBlocks.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,OAAO,EAER,MAAM,mBAAmB,CAAC;AAqB3B,eAAO,MAAM,iCAAiC,EAAE,OA2E/C,CAAA"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
function onlyHasCodeMarkedText(paragraph, codeMarkType) {
|
|
2
|
+
if (paragraph.content.size === 0) {
|
|
3
|
+
return paragraph.marks.some(mark => mark.type.name === codeMarkType.name);
|
|
4
|
+
}
|
|
5
|
+
let allAreCodeMarked = true;
|
|
6
|
+
paragraph.content.forEach(child => {
|
|
7
|
+
if (!child.isText ||
|
|
8
|
+
!child.marks.some(mark => mark.type.name === codeMarkType.name)) {
|
|
9
|
+
allAreCodeMarked = false;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
return allAreCodeMarked;
|
|
13
|
+
}
|
|
14
|
+
export const convertCodeParagraphsToCodeBlocks = (state, dispatch) => {
|
|
15
|
+
const doc = state.doc;
|
|
16
|
+
const schema = state.schema;
|
|
17
|
+
let tr = state.tr;
|
|
18
|
+
let paragraphsToMerge = null;
|
|
19
|
+
function flushCodeBlock() {
|
|
20
|
+
if (paragraphsToMerge === null) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const textNode = schema.text(paragraphsToMerge.innerText);
|
|
24
|
+
const codeBlock = schema.nodes.code_block.createAndFill(null, [textNode]);
|
|
25
|
+
const startPos = tr.mapping.map(paragraphsToMerge.startPos);
|
|
26
|
+
const endPos = tr.mapping.map(paragraphsToMerge.endPos);
|
|
27
|
+
tr.replaceRangeWith(startPos, endPos, codeBlock);
|
|
28
|
+
paragraphsToMerge = null;
|
|
29
|
+
}
|
|
30
|
+
function nodesToText(fragment) {
|
|
31
|
+
if (fragment.content.length === 0) {
|
|
32
|
+
return '';
|
|
33
|
+
}
|
|
34
|
+
let retVal = '';
|
|
35
|
+
fragment.content.forEach(node => {
|
|
36
|
+
if (node.isText) {
|
|
37
|
+
retVal += node.text;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
retVal = '@TODO: node.type ' + node.type;
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
return retVal;
|
|
44
|
+
}
|
|
45
|
+
doc.forEach((node, pos) => {
|
|
46
|
+
if (node.type.name === 'paragraph') {
|
|
47
|
+
const isCodeOnly = onlyHasCodeMarkedText(node, schema.marks.code);
|
|
48
|
+
const isEmpty = node.content.size === 0;
|
|
49
|
+
if (isCodeOnly) {
|
|
50
|
+
if (paragraphsToMerge === null) {
|
|
51
|
+
paragraphsToMerge = { startPos: pos, endPos: pos + node.nodeSize, innerText: nodesToText(node.content) };
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
paragraphsToMerge = { startPos: paragraphsToMerge.startPos, endPos: pos + node.nodeSize,
|
|
55
|
+
innerText: paragraphsToMerge.innerText + '\n' + nodesToText(node.content)
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (paragraphsToMerge !== null) {
|
|
62
|
+
flushCodeBlock();
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
if (paragraphsToMerge !== null) {
|
|
66
|
+
flushCodeBlock();
|
|
67
|
+
}
|
|
68
|
+
if (dispatch) {
|
|
69
|
+
dispatch(tr);
|
|
70
|
+
}
|
|
71
|
+
return tr.steps.length > 0;
|
|
72
|
+
};
|