@a3s-lab/office 0.45.0 → 0.47.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/README.md +23 -0
- package/dist/{0~2330.js → 0~2133.js} +312 -6
- package/dist/0~document-editor.js +4311 -3876
- package/dist/0~work-docx-export.js +198 -3
- package/dist/0~work-docx-import.js +53 -8
- package/dist/0~work-office-diagnostics.js +28 -8
- package/dist/4174.js +2253 -1604
- package/dist/internal/features/work/editors/document-command-catalog.d.ts +15 -1
- package/dist/internal/features/work/editors/document-text-box-ribbon.d.ts +4 -0
- package/dist/internal/features/work/editors/document-toolbar.d.ts +2 -1
- package/dist/internal/features/work/editors/use-document-insert-commands.d.ts +1 -0
- package/dist/internal/features/work/work-document-field-node.d.ts +2 -2
- package/dist/internal/features/work/work-document-fields.d.ts +36 -2
- package/dist/internal/features/work/work-document-text-box.d.ts +64 -0
- package/dist/internal/features/work/work-docx-bookmark-import.d.ts +1 -1
- package/dist/internal/features/work/work-docx-field-import.d.ts +5 -1
- package/dist/internal/features/work/work-docx-import.d.ts +3 -1
- package/dist/internal/features/work/work-docx-text-box-export.d.ts +25 -0
- package/dist/internal/features/work/work-docx-text-box-import.d.ts +26 -0
- package/dist/styles.css +63 -0
- package/package.json +6 -3
package/dist/4174.js
CHANGED
|
@@ -215,1617 +215,1898 @@ function normalizedReferenceText(value) {
|
|
|
215
215
|
function stringAttribute(value) {
|
|
216
216
|
return 'string' == typeof value ? value.trim() : '';
|
|
217
217
|
}
|
|
218
|
-
const
|
|
219
|
-
const
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
addCommands () {
|
|
232
|
-
return {
|
|
233
|
-
insertDocumentBookmark: (name)=>(props)=>insertDocumentBookmarkCommand(props, name),
|
|
234
|
-
deleteDocumentBookmark: (id)=>(props)=>deleteDocumentBookmarkCommand(props, id)
|
|
235
|
-
};
|
|
236
|
-
},
|
|
237
|
-
addProseMirrorPlugins () {
|
|
238
|
-
return [
|
|
239
|
-
createDocumentBookmarkPlugin(this.name)
|
|
240
|
-
];
|
|
241
|
-
},
|
|
242
|
-
addAttributes () {
|
|
243
|
-
return {
|
|
244
|
-
id: {
|
|
245
|
-
default: '',
|
|
246
|
-
parseHTML: (element)=>element.dataset.bookmarkId ?? '',
|
|
247
|
-
renderHTML: ()=>({})
|
|
248
|
-
},
|
|
249
|
-
name: {
|
|
250
|
-
default: '',
|
|
251
|
-
parseHTML: (element)=>element.dataset.bookmarkName ?? '',
|
|
252
|
-
renderHTML: ()=>({})
|
|
253
|
-
},
|
|
254
|
-
nativeId: {
|
|
255
|
-
default: null,
|
|
256
|
-
parseHTML: (element)=>normalizeDocumentBookmarkNativeId(element.dataset.officeBookmarkId),
|
|
257
|
-
renderHTML: ()=>({})
|
|
258
|
-
},
|
|
259
|
-
kind: {
|
|
260
|
-
default: 'start',
|
|
261
|
-
parseHTML: (element)=>documentBookmarkBoundaryKind(element.dataset.bookmarkKind),
|
|
262
|
-
renderHTML: ()=>({})
|
|
263
|
-
}
|
|
264
|
-
};
|
|
265
|
-
},
|
|
266
|
-
parseHTML () {
|
|
267
|
-
return [
|
|
268
|
-
{
|
|
269
|
-
tag: 'span[data-document-bookmark-boundary]',
|
|
270
|
-
getAttrs: (node)=>{
|
|
271
|
-
if (!(node instanceof HTMLElement)) return false;
|
|
272
|
-
return {
|
|
273
|
-
id: node.dataset.bookmarkId ?? '',
|
|
274
|
-
name: node.dataset.bookmarkName ?? '',
|
|
275
|
-
nativeId: normalizeDocumentBookmarkNativeId(node.dataset.officeBookmarkId),
|
|
276
|
-
kind: documentBookmarkBoundaryKind(node.dataset.bookmarkKind)
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
];
|
|
281
|
-
},
|
|
282
|
-
renderHTML ({ node, HTMLAttributes }) {
|
|
283
|
-
const name = normalizeDocumentBookmarkName(node.attrs.name) ?? '';
|
|
284
|
-
const nativeId = normalizeDocumentBookmarkNativeId(node.attrs.nativeId);
|
|
285
|
-
const kind = documentBookmarkBoundaryKind(node.attrs.kind);
|
|
286
|
-
return [
|
|
287
|
-
'span',
|
|
288
|
-
mergeAttributes(HTMLAttributes, {
|
|
289
|
-
...'start' === kind && name ? {
|
|
290
|
-
id: name
|
|
291
|
-
} : {},
|
|
292
|
-
'data-document-bookmark-boundary': 'true',
|
|
293
|
-
'data-bookmark-kind': kind,
|
|
294
|
-
'data-bookmark-id': 'string' == typeof node.attrs.id ? node.attrs.id : '',
|
|
295
|
-
'data-bookmark-name': name,
|
|
296
|
-
'data-office-bookmark-id': null === nativeId ? void 0 : String(nativeId),
|
|
297
|
-
class: `work-document-bookmark-boundary ${kind}`,
|
|
298
|
-
contenteditable: 'false',
|
|
299
|
-
'aria-hidden': 'true'
|
|
300
|
-
})
|
|
301
|
-
];
|
|
302
|
-
},
|
|
303
|
-
renderText () {
|
|
304
|
-
return '';
|
|
305
|
-
}
|
|
306
|
-
});
|
|
307
|
-
function validateDocumentBookmarkName(value) {
|
|
308
|
-
const name = value.trim();
|
|
309
|
-
return BOOKMARK_UI_NAME_PATTERN.test(name) && Array.from(name).length <= MAX_BOOKMARK_NAME_LENGTH ? null : DOCUMENT_BOOKMARK_VALIDATION_MESSAGE;
|
|
310
|
-
}
|
|
311
|
-
function normalizeDocumentBookmarkName(value) {
|
|
312
|
-
if ('string' != typeof value) return null;
|
|
313
|
-
const name = value.trim();
|
|
314
|
-
return BOOKMARK_NAME_PATTERN.test(name) && Array.from(name).length <= MAX_BOOKMARK_NAME_LENGTH ? name : null;
|
|
315
|
-
}
|
|
316
|
-
function normalizeDocumentBookmarkNativeId(value) {
|
|
317
|
-
if (null == value || '' === value || 'string' == typeof value && !value.trim()) return null;
|
|
318
|
-
const number = 'number' == typeof value ? value : Number(value);
|
|
319
|
-
return Number.isSafeInteger(number) && number >= 0 && number <= MAX_BOOKMARK_NATIVE_ID ? number : null;
|
|
218
|
+
const DOCUMENT_HTML_FINGERPRINT_VERSION = 'p1';
|
|
219
|
+
const DOCUMENT_HTML_HASH_BASE = 0x01000193;
|
|
220
|
+
const LEGACY_FNV_OFFSET = 0x811c9dc5;
|
|
221
|
+
function createDocumentHtmlFingerprintSegment(source, from = 0, to = source.length) {
|
|
222
|
+
if (!Number.isSafeInteger(from) || !Number.isSafeInteger(to) || from < 0 || to < from || to > source.length) throw new RangeError('The document HTML fingerprint range is invalid.');
|
|
223
|
+
let hash = 0;
|
|
224
|
+
for(let index = from; index < to; index += 1)hash = Math.imul(hash, DOCUMENT_HTML_HASH_BASE) + source.charCodeAt(index) >>> 0;
|
|
225
|
+
const length = to - from;
|
|
226
|
+
return {
|
|
227
|
+
hash,
|
|
228
|
+
length,
|
|
229
|
+
power: documentHtmlHashPower(length)
|
|
230
|
+
};
|
|
320
231
|
}
|
|
321
|
-
function
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
232
|
+
function combineDocumentHtmlFingerprintSegments(segments) {
|
|
233
|
+
let combined = {
|
|
234
|
+
hash: 0,
|
|
235
|
+
length: 0,
|
|
236
|
+
power: 1
|
|
237
|
+
};
|
|
238
|
+
for (const segment of segments)combined = {
|
|
239
|
+
hash: Math.imul(combined.hash, segment.power) + segment.hash >>> 0,
|
|
240
|
+
length: combined.length + segment.length,
|
|
241
|
+
power: Math.imul(combined.power, segment.power) >>> 0
|
|
242
|
+
};
|
|
243
|
+
return combined;
|
|
329
244
|
}
|
|
330
|
-
function
|
|
331
|
-
return
|
|
332
|
-
const display = documentBookmarkReferenceDisplay(editor.state.doc, bookmark);
|
|
333
|
-
return {
|
|
334
|
-
type: 'bookmark',
|
|
335
|
-
id: bookmark.id,
|
|
336
|
-
name: bookmark.name,
|
|
337
|
-
title: display,
|
|
338
|
-
display,
|
|
339
|
-
instruction: documentBookmarkReferenceInstruction(bookmark.name)
|
|
340
|
-
};
|
|
341
|
-
});
|
|
245
|
+
function documentHtmlFingerprintForSegment(segment) {
|
|
246
|
+
return `${DOCUMENT_HTML_FINGERPRINT_VERSION}:${segment.length.toString(36)}:${segment.hash.toString(36)}`;
|
|
342
247
|
}
|
|
343
|
-
function
|
|
344
|
-
|
|
345
|
-
const matches = editorDocumentBookmarks(editor).filter((bookmark)=>from >= bookmark.from + 1 && to <= bookmark.to);
|
|
346
|
-
return matches.sort((left, right)=>left.to - left.from - (right.to - right.from))[0] ?? null;
|
|
248
|
+
function documentHtmlFingerprint(html) {
|
|
249
|
+
return documentHtmlFingerprintForSegment(createDocumentHtmlFingerprintSegment(html));
|
|
347
250
|
}
|
|
348
|
-
function
|
|
349
|
-
|
|
350
|
-
return editorDocumentBookmarks(editor).some((bookmark)=>bookmark.id !== exceptId && bookmark.name.toLowerCase() === name);
|
|
251
|
+
function documentHtmlFingerprintMatches(html, candidate) {
|
|
252
|
+
return candidate.startsWith(`${DOCUMENT_HTML_FINGERPRINT_VERSION}:`) ? candidate === documentHtmlFingerprint(html) : candidate === legacyDocumentHtmlFingerprint(html);
|
|
351
253
|
}
|
|
352
|
-
function
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
const registry = createBookmarkRegistry();
|
|
358
|
-
for (const pair of collection.pairs){
|
|
359
|
-
const previous = {
|
|
360
|
-
id: bookmarkInternalId(pair.id),
|
|
361
|
-
name: normalizeDocumentBookmarkName(pair.name) ?? ''
|
|
362
|
-
};
|
|
363
|
-
const identity = uniqueDocumentBookmarkIdentity(pair, registry);
|
|
364
|
-
applyBookmarkIdentityToElement(pair.start, identity, 'start');
|
|
365
|
-
applyBookmarkIdentityToElement(pair.end, identity, 'end');
|
|
366
|
-
if (previous.id && previous.name && (previous.id !== identity.id || previous.name !== identity.name)) retargetDomBookmarkReferences(document1.body, pair.start, pair.end, previous, identity);
|
|
254
|
+
function legacyDocumentHtmlFingerprint(html) {
|
|
255
|
+
let hash = LEGACY_FNV_OFFSET;
|
|
256
|
+
for(let index = 0; index < html.length; index += 1){
|
|
257
|
+
hash ^= html.charCodeAt(index);
|
|
258
|
+
hash = Math.imul(hash, DOCUMENT_HTML_HASH_BASE);
|
|
367
259
|
}
|
|
368
|
-
|
|
369
|
-
return document1.body.innerHTML;
|
|
370
|
-
}
|
|
371
|
-
function insertDocumentBookmarkCommand({ dispatch, editor, state, tr }, value) {
|
|
372
|
-
const name = value.trim();
|
|
373
|
-
const boundaryType = editor.schema.nodes.documentBookmarkBoundary;
|
|
374
|
-
const selection = state.selection;
|
|
375
|
-
if (!boundaryType || validateDocumentBookmarkName(name) || documentBookmarkNameExists(editor, name) || !selection.$from.parent.inlineContent || !selection.$to.parent.inlineContent) return false;
|
|
376
|
-
if (!dispatch) return true;
|
|
377
|
-
const registry = bookmarkRegistryForDocument(state.doc, boundaryType.name);
|
|
378
|
-
const identity = uniqueDocumentBookmarkIdentity({
|
|
379
|
-
id: createUniqueBookmarkId(registry.ids),
|
|
380
|
-
name,
|
|
381
|
-
nativeId: nextBookmarkNativeId(registry.nativeIds)
|
|
382
|
-
}, registry);
|
|
383
|
-
const start = boundaryType.create({
|
|
384
|
-
...identity,
|
|
385
|
-
kind: 'start'
|
|
386
|
-
});
|
|
387
|
-
const end = boundaryType.create({
|
|
388
|
-
...identity,
|
|
389
|
-
kind: 'end'
|
|
390
|
-
});
|
|
391
|
-
const from = selection.from;
|
|
392
|
-
const to = selection.to;
|
|
393
|
-
tr.insert(to, end);
|
|
394
|
-
tr.insert(from, start);
|
|
395
|
-
tr.setSelection(TextSelection.create(tr.doc, from + 1, to + 1));
|
|
396
|
-
dispatch(tr.scrollIntoView());
|
|
397
|
-
return true;
|
|
260
|
+
return `${html.length.toString(36)}:${(hash >>> 0).toString(36)}`;
|
|
398
261
|
}
|
|
399
|
-
function
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
262
|
+
function documentHtmlHashPower(length) {
|
|
263
|
+
let exponent = length;
|
|
264
|
+
let factor = DOCUMENT_HTML_HASH_BASE;
|
|
265
|
+
let power = 1;
|
|
266
|
+
while(exponent > 0){
|
|
267
|
+
if (exponent % 2 === 1) power = Math.imul(power, factor) >>> 0;
|
|
268
|
+
factor = Math.imul(factor, factor) >>> 0;
|
|
269
|
+
exponent = Math.floor(exponent / 2);
|
|
270
|
+
}
|
|
271
|
+
return power;
|
|
408
272
|
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
273
|
+
const SECTION_CLOSE = '</section>';
|
|
274
|
+
const TABLE_BODY_OPEN = '<tbody>';
|
|
275
|
+
const TABLE_CLOSE = '</tbody></table>';
|
|
276
|
+
const projectionFingerprints = new WeakMap();
|
|
277
|
+
function createDocumentLazyHtmlProjection(html, root) {
|
|
278
|
+
if (!html.startsWith('<section') || !html.endsWith(SECTION_CLOSE)) return null;
|
|
279
|
+
const sectionOpenEnd = html.indexOf('>') + 1;
|
|
280
|
+
if (sectionOpenEnd <= 0) return null;
|
|
281
|
+
let cursor = sectionOpenEnd;
|
|
282
|
+
const orderedRanges = [];
|
|
283
|
+
const ranges = new Map();
|
|
284
|
+
for (const chunk of lazyDocumentLeafChunks(root)){
|
|
285
|
+
const id = 'string' == typeof chunk.attrs?.id ? chunk.attrs.id : '';
|
|
286
|
+
if (!id || ranges.has(id)) return null;
|
|
287
|
+
const from = cursor;
|
|
288
|
+
let tablePart = null;
|
|
289
|
+
const content = chunk.content ?? [];
|
|
290
|
+
for (const node of content){
|
|
291
|
+
const scanned = scanSimpleDocumentNodeHtml(html, cursor, node);
|
|
292
|
+
if (!scanned) return null;
|
|
293
|
+
cursor = scanned.to;
|
|
294
|
+
if (scanned.tablePart) {
|
|
295
|
+
if (1 !== content.length || tablePart) return null;
|
|
296
|
+
tablePart = scanned.tablePart;
|
|
416
297
|
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
if ('documentBookmarkBoundary' === boundaryNodeName && !documentHasIntegrityFeature(state.doc, 1)) return null;
|
|
427
|
-
const collection = collectDocumentBookmarkPairs(state.doc, boundaryNodeName);
|
|
428
|
-
const retained = oldState ? retainedDocumentBookmarkPairs(oldState, state, transactions, boundaryNodeName) : new Set();
|
|
429
|
-
const ordered = [
|
|
430
|
-
...collection.pairs.filter((pair)=>retained.has(pairPositionKey(pair))),
|
|
431
|
-
...collection.pairs.filter((pair)=>!retained.has(pairPositionKey(pair)))
|
|
432
|
-
];
|
|
433
|
-
const registry = createBookmarkRegistry();
|
|
434
|
-
const updates = new Map();
|
|
435
|
-
const renames = [];
|
|
436
|
-
const effectivePairs = [];
|
|
437
|
-
for (const pair of ordered){
|
|
438
|
-
const identity = uniqueDocumentBookmarkIdentity(pair, registry);
|
|
439
|
-
if (!sameBookmarkIdentity(pair.start.node.attrs, identity)) updates.set(pair.from, identity);
|
|
440
|
-
if (!sameBookmarkIdentity(pair.end.node.attrs, identity)) updates.set(pair.to, identity);
|
|
441
|
-
if (!sameBookmarkIdentity(pair, identity)) {
|
|
442
|
-
if (pair.id && pair.name && (pair.id !== identity.id || pair.name !== identity.name)) renames.push({
|
|
443
|
-
from: pair.from,
|
|
444
|
-
to: pair.to,
|
|
445
|
-
previousId: pair.id,
|
|
446
|
-
nextId: identity.id,
|
|
447
|
-
previousName: pair.name,
|
|
448
|
-
nextName: identity.name
|
|
449
|
-
});
|
|
450
|
-
}
|
|
451
|
-
effectivePairs.push({
|
|
452
|
-
...pair,
|
|
453
|
-
...identity
|
|
454
|
-
});
|
|
455
|
-
}
|
|
456
|
-
const tr = state.tr;
|
|
457
|
-
for (const boundary of documentBookmarkBoundaries(state.doc, boundaryNodeName)){
|
|
458
|
-
const identity = updates.get(boundary.position);
|
|
459
|
-
if (identity) tr.setNodeMarkup(boundary.position, void 0, {
|
|
460
|
-
...boundary.node.attrs,
|
|
461
|
-
...identity
|
|
462
|
-
});
|
|
298
|
+
}
|
|
299
|
+
const range = {
|
|
300
|
+
from,
|
|
301
|
+
id,
|
|
302
|
+
tablePart,
|
|
303
|
+
to: cursor
|
|
304
|
+
};
|
|
305
|
+
orderedRanges.push(range);
|
|
306
|
+
ranges.set(id, range);
|
|
463
307
|
}
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
308
|
+
if (cursor !== html.length - SECTION_CLOSE.length) return null;
|
|
309
|
+
return {
|
|
310
|
+
html,
|
|
311
|
+
orderedRanges,
|
|
312
|
+
ranges
|
|
313
|
+
};
|
|
470
314
|
}
|
|
471
|
-
function
|
|
472
|
-
|
|
473
|
-
const
|
|
474
|
-
const
|
|
475
|
-
const
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
const mappedTo = mapping.mapResult(previous.to, 1);
|
|
484
|
-
const exact = current.find((pair)=>pair.from === mappedFrom.pos && pair.to === mappedTo.pos && pair.id === previous.id);
|
|
485
|
-
if (exact) {
|
|
486
|
-
retained.add(pairPositionKey(exact));
|
|
487
|
-
continue;
|
|
315
|
+
function patchDocumentLazyHtmlProjection(projection, replacements) {
|
|
316
|
+
if (!replacements.size) return projection.html;
|
|
317
|
+
for (const id of replacements.keys())if (!projection.ranges.has(id)) return null;
|
|
318
|
+
const fingerprintState = documentLazyHtmlFingerprintState(projection);
|
|
319
|
+
const parts = [];
|
|
320
|
+
let cursor = 0;
|
|
321
|
+
for (const range of projection.orderedRanges){
|
|
322
|
+
const replacement = replacements.get(range.id);
|
|
323
|
+
if (void 0 !== replacement) {
|
|
324
|
+
parts.push(projection.html.slice(cursor, range.from), replacement);
|
|
325
|
+
fingerprintState.ranges.set(range.id, createDocumentHtmlFingerprintSegment(replacement));
|
|
326
|
+
cursor = range.to;
|
|
488
327
|
}
|
|
489
|
-
const sameIdentity = currentById.get(previous.id);
|
|
490
|
-
if (sameIdentity?.length === 1) retained.add(pairPositionKey(sameIdentity[0]));
|
|
491
328
|
}
|
|
492
|
-
|
|
329
|
+
parts.push(projection.html.slice(cursor));
|
|
330
|
+
const html = parts.join('');
|
|
331
|
+
let offset = 0;
|
|
332
|
+
for (const range of projection.orderedRanges){
|
|
333
|
+
const previousFrom = range.from;
|
|
334
|
+
const previousLength = range.to - previousFrom;
|
|
335
|
+
const replacement = replacements.get(range.id);
|
|
336
|
+
const nextLength = replacement?.length ?? previousLength;
|
|
337
|
+
range.from = previousFrom + offset;
|
|
338
|
+
range.to = range.from + nextLength;
|
|
339
|
+
offset += nextLength - previousLength;
|
|
340
|
+
}
|
|
341
|
+
projection.html = html;
|
|
342
|
+
fingerprintState.fingerprint = documentHtmlFingerprintForSegment(combineDocumentHtmlFingerprintSegments([
|
|
343
|
+
fingerprintState.prefix,
|
|
344
|
+
...projection.orderedRanges.map((range)=>{
|
|
345
|
+
const segment = fingerprintState.ranges.get(range.id);
|
|
346
|
+
if (!segment) throw new Error('The lazy HTML fingerprint segment is missing.');
|
|
347
|
+
return segment;
|
|
348
|
+
}),
|
|
349
|
+
fingerprintState.suffix
|
|
350
|
+
]));
|
|
351
|
+
return html;
|
|
493
352
|
}
|
|
494
|
-
function
|
|
495
|
-
|
|
496
|
-
if (!linkType) return;
|
|
497
|
-
const names = new Set(bookmarks.map((bookmark)=>bookmark.name.toLowerCase()));
|
|
498
|
-
state.doc.descendants((node, position)=>{
|
|
499
|
-
if (!node.isText) return;
|
|
500
|
-
const link = node.marks.find((mark)=>mark.type === linkType);
|
|
501
|
-
if (!link) return;
|
|
502
|
-
const href = 'string' == typeof link.attrs.href ? link.attrs.href : '';
|
|
503
|
-
if (!href.startsWith('#')) return;
|
|
504
|
-
const target = href.slice(1);
|
|
505
|
-
const rename = renames.filter((candidate)=>position > candidate.from && position < candidate.to && target.toLowerCase() === candidate.previousName.toLowerCase()).sort((left, right)=>left.to - left.from - (right.to - right.from))[0];
|
|
506
|
-
const nextHref = rename ? `#${rename.nextName}` : href;
|
|
507
|
-
const nextTarget = nextHref.slice(1).toLowerCase();
|
|
508
|
-
const nextClass = toggleClassToken(link.attrs.class, MISSING_LINK_CLASS, !names.has(nextTarget));
|
|
509
|
-
if (nextHref === href && nextClass === normalizedClass(link.attrs.class)) return;
|
|
510
|
-
replaceLinkMark(state, tr, node, position, link, {
|
|
511
|
-
...link.attrs,
|
|
512
|
-
href: nextHref,
|
|
513
|
-
class: nextClass || null
|
|
514
|
-
});
|
|
515
|
-
});
|
|
353
|
+
function documentLazyHtmlProjectionFingerprint(projection) {
|
|
354
|
+
return projectionFingerprints.get(projection)?.fingerprint ?? null;
|
|
516
355
|
}
|
|
517
|
-
function
|
|
518
|
-
|
|
519
|
-
|
|
356
|
+
function documentLazyHtmlChunkFragment(html, tablePart) {
|
|
357
|
+
if (!tablePart || 'complete' === tablePart) return html;
|
|
358
|
+
const bodyOpen = html.indexOf(TABLE_BODY_OPEN);
|
|
359
|
+
const bodyClose = html.lastIndexOf('</tbody>');
|
|
360
|
+
if (bodyOpen < 0 || bodyClose < bodyOpen) return null;
|
|
361
|
+
const rowsFrom = bodyOpen + TABLE_BODY_OPEN.length;
|
|
362
|
+
if ('first' === tablePart) return html.slice(0, bodyClose);
|
|
363
|
+
if ('middle' === tablePart) return html.slice(rowsFrom, bodyClose);
|
|
364
|
+
return html.slice(rowsFrom);
|
|
520
365
|
}
|
|
521
|
-
function
|
|
522
|
-
const
|
|
523
|
-
const
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
const
|
|
528
|
-
if (
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
open.set(key, stack);
|
|
366
|
+
function lazyDocumentLeafChunks(root) {
|
|
367
|
+
const chunks = [];
|
|
368
|
+
const pending = [
|
|
369
|
+
root
|
|
370
|
+
];
|
|
371
|
+
while(pending.length){
|
|
372
|
+
const node = pending.pop();
|
|
373
|
+
if (!node) continue;
|
|
374
|
+
if ('documentChunk' === node.type && node.attrs?.windowContainer !== true) {
|
|
375
|
+
chunks.push(node);
|
|
532
376
|
continue;
|
|
533
377
|
}
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
orphans.push(boundary);
|
|
538
|
-
continue;
|
|
378
|
+
for(let index = (node.content?.length ?? 0) - 1; index >= 0; index -= 1){
|
|
379
|
+
const child = node.content?.[index];
|
|
380
|
+
if (child) pending.push(child);
|
|
539
381
|
}
|
|
540
|
-
pairs.push(bookmarkPair(start, boundary));
|
|
541
382
|
}
|
|
542
|
-
|
|
543
|
-
pairs.sort((left, right)=>left.from - right.from || left.to - right.to);
|
|
544
|
-
return {
|
|
545
|
-
pairs,
|
|
546
|
-
orphans
|
|
547
|
-
};
|
|
548
|
-
}
|
|
549
|
-
function documentBookmarkBoundaries(document1, boundaryNodeName) {
|
|
550
|
-
if (!boundaryNodeName) return [];
|
|
551
|
-
const boundaries = [];
|
|
552
|
-
document1.descendants((node, position)=>{
|
|
553
|
-
if (node.type.name !== boundaryNodeName) return;
|
|
554
|
-
boundaries.push({
|
|
555
|
-
node,
|
|
556
|
-
position,
|
|
557
|
-
kind: documentBookmarkBoundaryKind(node.attrs.kind)
|
|
558
|
-
});
|
|
559
|
-
});
|
|
560
|
-
return boundaries;
|
|
383
|
+
return chunks;
|
|
561
384
|
}
|
|
562
|
-
function
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
385
|
+
function documentLazyHtmlFingerprintState(projection) {
|
|
386
|
+
const existing = projectionFingerprints.get(projection);
|
|
387
|
+
if (existing) return existing;
|
|
388
|
+
const first = projection.orderedRanges[0];
|
|
389
|
+
const last = projection.orderedRanges.at(-1);
|
|
390
|
+
const ranges = new Map();
|
|
391
|
+
for (const range of projection.orderedRanges)ranges.set(range.id, createDocumentHtmlFingerprintSegment(projection.html, range.from, range.to));
|
|
392
|
+
const prefix = createDocumentHtmlFingerprintSegment(projection.html, 0, first?.from ?? projection.html.length);
|
|
393
|
+
const suffix = createDocumentHtmlFingerprintSegment(projection.html, last?.to ?? projection.html.length, projection.html.length);
|
|
394
|
+
const state = {
|
|
395
|
+
fingerprint: documentHtmlFingerprintForSegment(combineDocumentHtmlFingerprintSegments([
|
|
396
|
+
prefix,
|
|
397
|
+
...projection.orderedRanges.map((range)=>{
|
|
398
|
+
const segment = ranges.get(range.id);
|
|
399
|
+
if (!segment) throw new Error('The lazy HTML fingerprint segment is missing.');
|
|
400
|
+
return segment;
|
|
401
|
+
}),
|
|
402
|
+
suffix
|
|
403
|
+
])),
|
|
404
|
+
prefix,
|
|
405
|
+
ranges,
|
|
406
|
+
suffix
|
|
571
407
|
};
|
|
408
|
+
projectionFingerprints.set(projection, state);
|
|
409
|
+
return state;
|
|
572
410
|
}
|
|
573
|
-
function
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
const
|
|
577
|
-
|
|
411
|
+
function scanSimpleDocumentNodeHtml(html, from, node) {
|
|
412
|
+
if ('paragraph' === node.type) {
|
|
413
|
+
if (!html.startsWith('<p>', from)) return null;
|
|
414
|
+
const close = html.indexOf('</p>', from + 3);
|
|
415
|
+
return close < 0 ? null : {
|
|
416
|
+
tablePart: null,
|
|
417
|
+
to: close + 4
|
|
418
|
+
};
|
|
578
419
|
}
|
|
579
|
-
return
|
|
420
|
+
if ('table' !== node.type) return null;
|
|
421
|
+
const virtualIndex = Number(node.attrs?.virtualTableIndex);
|
|
422
|
+
const virtualCount = Number(node.attrs?.virtualTableCount);
|
|
423
|
+
const virtual = Boolean('string' == typeof node.attrs?.virtualTableId && node.attrs.virtualTableId && Number.isSafeInteger(virtualIndex) && Number.isSafeInteger(virtualCount) && virtualIndex >= 0 && virtualCount > 0 && virtualIndex < virtualCount);
|
|
424
|
+
let cursor = from;
|
|
425
|
+
if (!virtual || 0 === virtualIndex) {
|
|
426
|
+
if (!html.startsWith('<table', cursor)) return null;
|
|
427
|
+
const body = html.indexOf(TABLE_BODY_OPEN, cursor);
|
|
428
|
+
if (body < 0) return null;
|
|
429
|
+
cursor = body + TABLE_BODY_OPEN.length;
|
|
430
|
+
}
|
|
431
|
+
for (const row of node.content ?? []){
|
|
432
|
+
if ('tableRow' !== row.type || !html.startsWith('<tr>', cursor)) return null;
|
|
433
|
+
const close = html.indexOf('</tr>', cursor + 4);
|
|
434
|
+
if (close < 0) return null;
|
|
435
|
+
cursor = close + 5;
|
|
436
|
+
}
|
|
437
|
+
if (!virtual || virtualIndex === virtualCount - 1) {
|
|
438
|
+
if (!html.startsWith(TABLE_CLOSE, cursor)) return null;
|
|
439
|
+
cursor += TABLE_CLOSE.length;
|
|
440
|
+
}
|
|
441
|
+
const tablePart = virtual ? 1 === virtualCount ? 'complete' : 0 === virtualIndex ? 'first' : virtualIndex === virtualCount - 1 ? 'last' : 'middle' : 'complete';
|
|
442
|
+
return {
|
|
443
|
+
tablePart,
|
|
444
|
+
to: cursor
|
|
445
|
+
};
|
|
580
446
|
}
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
447
|
+
const DOCUMENT_LAZY_BLOCK_NODE = 'documentLazyBlock';
|
|
448
|
+
const DOCUMENT_LAZY_INITIAL_CHUNK_COUNT = 2;
|
|
449
|
+
const DOCUMENT_LAZY_POSITION_BOUNDARY = '\ufffc';
|
|
450
|
+
const SIMPLE_LAZY_CONTAINER_TYPES = new Set([
|
|
451
|
+
'paragraph',
|
|
452
|
+
'table',
|
|
453
|
+
'tableCell',
|
|
454
|
+
'tableRow'
|
|
455
|
+
]);
|
|
456
|
+
const preparedModels = new WeakMap();
|
|
457
|
+
function prepareLazyDocumentEditorSource(model, allowCreate, html) {
|
|
458
|
+
const startedAt = lazyDocumentNow();
|
|
459
|
+
const cacheHit = preparedModels.has(model);
|
|
460
|
+
let prepared = preparedModels.get(model);
|
|
461
|
+
if (prepared) {
|
|
462
|
+
if (!prepared.root) {
|
|
463
|
+
const htmlProjection = prepared.htmlProjection;
|
|
464
|
+
const rebuilt = createPreparedLazyDocumentEditorSource(model.root, prepared.payloads);
|
|
465
|
+
if (!rebuilt) return null;
|
|
466
|
+
rebuilt.htmlProjection = htmlProjection;
|
|
467
|
+
prepared = rebuilt;
|
|
468
|
+
preparedModels.set(model, rebuilt);
|
|
469
|
+
}
|
|
470
|
+
} else {
|
|
471
|
+
if (!allowCreate) return null;
|
|
472
|
+
const created = createPreparedLazyDocumentEditorSource(model.root);
|
|
473
|
+
if (!created) return null;
|
|
474
|
+
prepared = created;
|
|
475
|
+
preparedModels.set(model, created);
|
|
586
476
|
}
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
477
|
+
if (!prepared.htmlProjection && html) prepared.htmlProjection = createDocumentLazyHtmlProjection(html, model.root);
|
|
478
|
+
if (!prepared.root) return null;
|
|
479
|
+
const result = {
|
|
480
|
+
lazyChunkCount: prepared.lazyChunkCount,
|
|
481
|
+
payloads: prepared.payloads,
|
|
482
|
+
root: prepared.root
|
|
592
483
|
};
|
|
593
|
-
|
|
594
|
-
|
|
484
|
+
recordLazyDocumentMeasure('a3s-office.document.lazy-editor-source', startedAt, lazyDocumentNow(), {
|
|
485
|
+
cacheHit
|
|
486
|
+
});
|
|
487
|
+
return result;
|
|
595
488
|
}
|
|
596
|
-
function
|
|
597
|
-
|
|
598
|
-
const name = normalizeDocumentBookmarkName(source.name);
|
|
599
|
-
const nativeId = normalizeDocumentBookmarkNativeId(source.nativeId);
|
|
600
|
-
return id && name && null !== nativeId ? {
|
|
601
|
-
id,
|
|
602
|
-
name,
|
|
603
|
-
nativeId
|
|
604
|
-
} : null;
|
|
489
|
+
function documentLazyHtmlProjection(model) {
|
|
490
|
+
return model ? preparedModels.get(model)?.htmlProjection ?? null : null;
|
|
605
491
|
}
|
|
606
|
-
function
|
|
607
|
-
|
|
492
|
+
function invalidateDocumentLazyHtmlProjection(model) {
|
|
493
|
+
if (model) {
|
|
494
|
+
const prepared = preparedModels.get(model);
|
|
495
|
+
if (prepared) prepared.htmlProjection = null;
|
|
496
|
+
}
|
|
608
497
|
}
|
|
609
|
-
function
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
registry.nativeIds.add(identity.nativeId);
|
|
498
|
+
function documentLazyChunkContent(model, chunkId) {
|
|
499
|
+
if (!model || !chunkId) return null;
|
|
500
|
+
return preparedModels.get(model)?.payloads.get(chunkId) ?? null;
|
|
613
501
|
}
|
|
614
|
-
function
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
502
|
+
function materializeLazyDocumentEditorRoot(root, model) {
|
|
503
|
+
const prepared = model ? preparedModels.get(model) : null;
|
|
504
|
+
if (!prepared) return root;
|
|
505
|
+
const visit = (node)=>{
|
|
506
|
+
if ('documentChunk' === node.type && node.attrs?.windowContainer !== true) {
|
|
507
|
+
const id = documentChunkId(node);
|
|
508
|
+
if (!id) return node;
|
|
509
|
+
if (documentChunkIsLazy(node)) {
|
|
510
|
+
const payload = prepared.payloads.get(id);
|
|
511
|
+
if (!payload) throw new Error(`The lazy document chunk payload "${id}" is missing.`);
|
|
512
|
+
return {
|
|
513
|
+
...node,
|
|
514
|
+
content: [
|
|
515
|
+
...payload
|
|
516
|
+
]
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
if (node.content?.length) prepared.payloads.set(id, node.content);
|
|
520
|
+
return node;
|
|
521
|
+
}
|
|
522
|
+
if (!node.content?.length) return node;
|
|
523
|
+
let changed = false;
|
|
524
|
+
const content = node.content.map((child)=>{
|
|
525
|
+
const next = visit(child);
|
|
526
|
+
if (next !== child) changed = true;
|
|
527
|
+
return next;
|
|
528
|
+
});
|
|
529
|
+
return changed ? {
|
|
530
|
+
...node,
|
|
531
|
+
content
|
|
532
|
+
} : node;
|
|
619
533
|
};
|
|
534
|
+
return visit(root);
|
|
620
535
|
}
|
|
621
|
-
function
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
536
|
+
function transferLazyDocumentModelState(previous, next) {
|
|
537
|
+
if (!previous) return;
|
|
538
|
+
const prepared = preparedModels.get(previous);
|
|
539
|
+
if (!prepared) return;
|
|
540
|
+
preparedModels.set(next, {
|
|
541
|
+
htmlProjection: prepared.htmlProjection,
|
|
542
|
+
lazyChunkCount: prepared.lazyChunkCount,
|
|
543
|
+
payloads: prepared.payloads,
|
|
544
|
+
root: null
|
|
545
|
+
});
|
|
629
546
|
}
|
|
630
|
-
function
|
|
631
|
-
if (
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
const
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
suffix += 1;
|
|
547
|
+
function simpleDocumentNodeSize(node) {
|
|
548
|
+
if ('text' === node.type) return 'string' == typeof node.text && node.text ? node.text.length : null;
|
|
549
|
+
if (!SIMPLE_LAZY_CONTAINER_TYPES.has(node.type)) return null;
|
|
550
|
+
let size = 2;
|
|
551
|
+
for (const child of node.content ?? []){
|
|
552
|
+
const childSize = simpleDocumentNodeSize(child);
|
|
553
|
+
if (null === childSize) return null;
|
|
554
|
+
size += childSize;
|
|
639
555
|
}
|
|
640
|
-
|
|
556
|
+
return size;
|
|
641
557
|
}
|
|
642
|
-
function
|
|
643
|
-
|
|
644
|
-
|
|
558
|
+
function createPreparedLazyDocumentEditorSource(root, previousPayloads) {
|
|
559
|
+
const payloads = new Map();
|
|
560
|
+
let leafIndex = 0;
|
|
561
|
+
let lazyChunkCount = 0;
|
|
562
|
+
let unsupported = false;
|
|
563
|
+
const visit = (node)=>{
|
|
564
|
+
if ('documentChunk' === node.type && node.attrs?.windowContainer !== true) {
|
|
565
|
+
const id = documentChunkId(node);
|
|
566
|
+
const payload = id ? previousPayloads?.get(id) ?? node.content ?? [] : [];
|
|
567
|
+
if (!id || !payload.length) {
|
|
568
|
+
unsupported = true;
|
|
569
|
+
return node;
|
|
570
|
+
}
|
|
571
|
+
payloads.set(id, payload);
|
|
572
|
+
const currentIndex = leafIndex;
|
|
573
|
+
leafIndex += 1;
|
|
574
|
+
if (currentIndex < DOCUMENT_LAZY_INITIAL_CHUNK_COUNT) return node;
|
|
575
|
+
const placeholder = lazyPlaceholderForContent(id, payload);
|
|
576
|
+
if (!placeholder) {
|
|
577
|
+
unsupported = true;
|
|
578
|
+
return node;
|
|
579
|
+
}
|
|
580
|
+
lazyChunkCount += 1;
|
|
581
|
+
return {
|
|
582
|
+
...node,
|
|
583
|
+
content: [
|
|
584
|
+
placeholder
|
|
585
|
+
]
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
if (!node.content?.length) return node;
|
|
589
|
+
let changed = false;
|
|
590
|
+
const content = node.content.map((child)=>{
|
|
591
|
+
const next = visit(child);
|
|
592
|
+
if (next !== child) changed = true;
|
|
593
|
+
return next;
|
|
594
|
+
});
|
|
595
|
+
return changed ? {
|
|
596
|
+
...node,
|
|
597
|
+
content
|
|
598
|
+
} : node;
|
|
599
|
+
};
|
|
600
|
+
const compactRoot = visit(root);
|
|
601
|
+
if (unsupported || leafIndex <= DOCUMENT_LAZY_INITIAL_CHUNK_COUNT || 0 === lazyChunkCount) return null;
|
|
602
|
+
return {
|
|
603
|
+
htmlProjection: null,
|
|
604
|
+
lazyChunkCount,
|
|
605
|
+
payloads,
|
|
606
|
+
root: compactRoot
|
|
607
|
+
};
|
|
645
608
|
}
|
|
646
|
-
function
|
|
647
|
-
|
|
609
|
+
function lazyPlaceholderForContent(chunkId, content) {
|
|
610
|
+
const tapeParts = [];
|
|
611
|
+
const statistics = {
|
|
612
|
+
contentSize: 0,
|
|
613
|
+
paragraphCount: 0
|
|
614
|
+
};
|
|
615
|
+
for (const node of content)if (!appendDocumentNodePositionTape(node, tapeParts, statistics)) return null;
|
|
616
|
+
if (statistics.contentSize < 2 || tapeParts[0] !== DOCUMENT_LAZY_POSITION_BOUNDARY || tapeParts.at(-1) !== DOCUMENT_LAZY_POSITION_BOUNDARY) return null;
|
|
617
|
+
tapeParts[0] = '';
|
|
618
|
+
tapeParts[tapeParts.length - 1] = '';
|
|
619
|
+
const filler = tapeParts.join('');
|
|
620
|
+
return {
|
|
621
|
+
type: DOCUMENT_LAZY_BLOCK_NODE,
|
|
622
|
+
attrs: {
|
|
623
|
+
chunkId,
|
|
624
|
+
contentSize: statistics.contentSize,
|
|
625
|
+
paragraphCount: statistics.paragraphCount
|
|
626
|
+
},
|
|
627
|
+
...filler ? {
|
|
628
|
+
content: [
|
|
629
|
+
{
|
|
630
|
+
type: 'text',
|
|
631
|
+
text: filler
|
|
632
|
+
}
|
|
633
|
+
]
|
|
634
|
+
} : {
|
|
635
|
+
content: []
|
|
636
|
+
}
|
|
637
|
+
};
|
|
648
638
|
}
|
|
649
|
-
function
|
|
650
|
-
|
|
639
|
+
function appendDocumentNodePositionTape(node, parts, statistics) {
|
|
640
|
+
if ('text' === node.type) {
|
|
641
|
+
if ('string' != typeof node.text || !node.text) return false;
|
|
642
|
+
parts.push(node.text);
|
|
643
|
+
statistics.contentSize += node.text.length;
|
|
644
|
+
return true;
|
|
645
|
+
}
|
|
646
|
+
if (!SIMPLE_LAZY_CONTAINER_TYPES.has(node.type)) return false;
|
|
647
|
+
if ('paragraph' === node.type) statistics.paragraphCount += 1;
|
|
648
|
+
statistics.contentSize += 2;
|
|
649
|
+
parts.push(DOCUMENT_LAZY_POSITION_BOUNDARY);
|
|
650
|
+
for (const child of node.content ?? [])if (!appendDocumentNodePositionTape(child, parts, statistics)) return false;
|
|
651
|
+
parts.push(DOCUMENT_LAZY_POSITION_BOUNDARY);
|
|
652
|
+
return true;
|
|
651
653
|
}
|
|
652
|
-
function
|
|
653
|
-
|
|
654
|
-
if (id) return `id:${id}`;
|
|
655
|
-
return `legacy:${String(attributes.name ?? '')}:${String(attributes.nativeId ?? '')}`;
|
|
654
|
+
function documentChunkIsLazy(node) {
|
|
655
|
+
return 'documentChunk' === node.type && node.attrs?.windowContainer !== true && node.content?.length === 1 && node.content[0]?.type === DOCUMENT_LAZY_BLOCK_NODE;
|
|
656
656
|
}
|
|
657
|
-
function
|
|
658
|
-
|
|
657
|
+
function documentChunkId(node) {
|
|
658
|
+
const id = node.attrs?.id;
|
|
659
|
+
return 'string' == typeof id && id ? id : null;
|
|
659
660
|
}
|
|
660
|
-
function
|
|
661
|
-
|
|
662
|
-
for (const transaction of transactions)mapping.appendMapping(transaction.mapping);
|
|
663
|
-
return mapping;
|
|
661
|
+
function lazyDocumentNow() {
|
|
662
|
+
return globalThis.performance?.now?.() ?? Date.now();
|
|
664
663
|
}
|
|
665
|
-
function
|
|
666
|
-
|
|
664
|
+
function recordLazyDocumentMeasure(name, start, end, detail) {
|
|
665
|
+
try {
|
|
666
|
+
globalThis.performance?.measure(name, {
|
|
667
|
+
detail,
|
|
668
|
+
end,
|
|
669
|
+
start
|
|
670
|
+
});
|
|
671
|
+
} catch {}
|
|
667
672
|
}
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
for
|
|
673
|
-
const
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
673
|
+
const statisticsByDocument = new WeakMap();
|
|
674
|
+
function documentWordCount(value) {
|
|
675
|
+
let asciiCount = 0;
|
|
676
|
+
let inAsciiWord = false;
|
|
677
|
+
for(let index = 0; index < value.length; index += 1){
|
|
678
|
+
const code = value.charCodeAt(index);
|
|
679
|
+
const asciiLetterOrNumber = code >= 0x30 && code <= 0x39 || code >= 0x41 && code <= 0x5a || code >= 0x61 && code <= 0x7a;
|
|
680
|
+
if (asciiLetterOrNumber) {
|
|
681
|
+
if (!inAsciiWord) asciiCount += 1;
|
|
682
|
+
inAsciiWord = true;
|
|
678
683
|
continue;
|
|
679
684
|
}
|
|
680
|
-
|
|
681
|
-
if (!
|
|
682
|
-
|
|
683
|
-
|
|
685
|
+
inAsciiWord = false;
|
|
686
|
+
if (!(code <= 0x7f) && 0xfffc !== code) return unicodeDocumentWordCount(value);
|
|
687
|
+
}
|
|
688
|
+
return asciiCount;
|
|
689
|
+
}
|
|
690
|
+
function unicodeDocumentWordCount(value) {
|
|
691
|
+
let count = 0;
|
|
692
|
+
for (const _match of value.matchAll(/[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]|[\p{L}\p{N}]+/gu))count += 1;
|
|
693
|
+
return count;
|
|
694
|
+
}
|
|
695
|
+
function documentTextStatistics(editor) {
|
|
696
|
+
const document1 = editor.state.doc;
|
|
697
|
+
const cached = statisticsByDocument.get(document1);
|
|
698
|
+
if (cached) return cached;
|
|
699
|
+
const source = editor.getText({
|
|
700
|
+
blockSeparator: '\n'
|
|
701
|
+
});
|
|
702
|
+
let characterCountWithSpaces = 0;
|
|
703
|
+
let characterCountWithoutSpaces = 0;
|
|
704
|
+
for(let index = 0; index < source.length; index += 1){
|
|
705
|
+
const codePoint = source.codePointAt(index);
|
|
706
|
+
if (void 0 !== codePoint) {
|
|
707
|
+
if (codePoint > 0xffff) index += 1;
|
|
708
|
+
if (codePoint !== "".codePointAt(0) && 0x0a !== codePoint && 0x0d !== codePoint) {
|
|
709
|
+
characterCountWithSpaces += 1;
|
|
710
|
+
if (!isEcmaScriptWhitespace(codePoint)) characterCountWithoutSpaces += 1;
|
|
711
|
+
}
|
|
684
712
|
}
|
|
685
|
-
pairs.push({
|
|
686
|
-
id: start.dataset.bookmarkId,
|
|
687
|
-
name: start.dataset.bookmarkName,
|
|
688
|
-
nativeId: normalizeDocumentBookmarkNativeId(start.dataset.officeBookmarkId) ?? void 0,
|
|
689
|
-
start,
|
|
690
|
-
end: boundary
|
|
691
|
-
});
|
|
692
713
|
}
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
714
|
+
let paragraphCount = 0;
|
|
715
|
+
document1.descendants((node)=>{
|
|
716
|
+
if (node.type.name === DOCUMENT_LAZY_BLOCK_NODE) {
|
|
717
|
+
const logicalParagraphs = Number(node.attrs.paragraphCount);
|
|
718
|
+
paragraphCount += Number.isSafeInteger(logicalParagraphs) && logicalParagraphs >= 0 ? logicalParagraphs : 0;
|
|
719
|
+
return false;
|
|
720
|
+
}
|
|
721
|
+
if (node.isTextblock) paragraphCount += 1;
|
|
722
|
+
return true;
|
|
723
|
+
});
|
|
724
|
+
const statistics = {
|
|
725
|
+
characterCountWithSpaces,
|
|
726
|
+
characterCountWithoutSpaces,
|
|
727
|
+
paragraphCount,
|
|
728
|
+
wordCount: documentWordCount(source)
|
|
697
729
|
};
|
|
730
|
+
statisticsByDocument.set(document1, statistics);
|
|
731
|
+
return statistics;
|
|
698
732
|
}
|
|
699
|
-
function
|
|
700
|
-
const
|
|
701
|
-
|
|
733
|
+
function transferDocumentTextStatistics(previous, next) {
|
|
734
|
+
const statistics = statisticsByDocument.get(previous);
|
|
735
|
+
if (statistics) statisticsByDocument.set(next, statistics);
|
|
702
736
|
}
|
|
703
|
-
function
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
737
|
+
function transferChangedDocumentTextStatistics(previous, next, changes) {
|
|
738
|
+
const cached = statisticsByDocument.get(previous);
|
|
739
|
+
if (!cached || !changes.length) return false;
|
|
740
|
+
const statistics = {
|
|
741
|
+
...cached
|
|
742
|
+
};
|
|
743
|
+
for (const { after, before } of changes){
|
|
744
|
+
applyDocumentTextStatisticsDelta(statistics, simpleDocumentSubtreeStatistics(before), -1);
|
|
745
|
+
applyDocumentTextStatisticsDelta(statistics, simpleDocumentSubtreeStatistics(after), 1);
|
|
746
|
+
}
|
|
747
|
+
if (Object.values(statistics).some((value)=>value < 0)) return false;
|
|
748
|
+
statisticsByDocument.set(next, statistics);
|
|
749
|
+
return true;
|
|
714
750
|
}
|
|
715
|
-
function
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
751
|
+
function simpleDocumentSubtreeStatistics(root) {
|
|
752
|
+
const statistics = {
|
|
753
|
+
characterCountWithSpaces: 0,
|
|
754
|
+
characterCountWithoutSpaces: 0,
|
|
755
|
+
paragraphCount: 0,
|
|
756
|
+
wordCount: 0
|
|
757
|
+
};
|
|
758
|
+
const visit = (node)=>{
|
|
759
|
+
if (node.type.name === DOCUMENT_LAZY_BLOCK_NODE) {
|
|
760
|
+
accumulateDocumentTextStatistics(statistics, node.textContent);
|
|
761
|
+
const logicalParagraphs = Number(node.attrs.paragraphCount);
|
|
762
|
+
statistics.paragraphCount += Number.isSafeInteger(logicalParagraphs) && logicalParagraphs >= 0 ? logicalParagraphs : 0;
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
if (node.isTextblock) {
|
|
766
|
+
accumulateDocumentTextStatistics(statistics, node.textContent);
|
|
767
|
+
statistics.paragraphCount += 1;
|
|
768
|
+
return;
|
|
769
|
+
}
|
|
770
|
+
node.forEach(visit);
|
|
771
|
+
};
|
|
772
|
+
visit(root);
|
|
773
|
+
return statistics;
|
|
774
|
+
}
|
|
775
|
+
function accumulateDocumentTextStatistics(statistics, source) {
|
|
776
|
+
for(let index = 0; index < source.length; index += 1){
|
|
777
|
+
const codePoint = source.codePointAt(index);
|
|
778
|
+
if (void 0 !== codePoint) {
|
|
779
|
+
if (codePoint > 0xffff) index += 1;
|
|
780
|
+
if (codePoint !== "".codePointAt(0) && 0x0a !== codePoint && 0x0d !== codePoint) {
|
|
781
|
+
statistics.characterCountWithSpaces += 1;
|
|
782
|
+
if (!isEcmaScriptWhitespace(codePoint)) statistics.characterCountWithoutSpaces += 1;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
720
785
|
}
|
|
786
|
+
statistics.wordCount += documentWordCount(source);
|
|
721
787
|
}
|
|
722
|
-
function
|
|
723
|
-
|
|
788
|
+
function applyDocumentTextStatisticsDelta(target, value, direction) {
|
|
789
|
+
target.characterCountWithSpaces += direction * value.characterCountWithSpaces;
|
|
790
|
+
target.characterCountWithoutSpaces += direction * value.characterCountWithoutSpaces;
|
|
791
|
+
target.paragraphCount += direction * value.paragraphCount;
|
|
792
|
+
target.wordCount += direction * value.wordCount;
|
|
724
793
|
}
|
|
725
|
-
function
|
|
726
|
-
|
|
727
|
-
if (enabled) tokens.add(token);
|
|
728
|
-
else tokens.delete(token);
|
|
729
|
-
return Array.from(tokens).join(' ');
|
|
794
|
+
function isEcmaScriptWhitespace(codePoint) {
|
|
795
|
+
return codePoint >= 0x09 && codePoint <= 0x0d || 0x20 === codePoint || 0xa0 === codePoint || 0x1680 === codePoint || codePoint >= 0x2000 && codePoint <= 0x200a || 0x2028 === codePoint || 0x2029 === codePoint || 0x202f === codePoint || 0x205f === codePoint || 0x3000 === codePoint || 0xfeff === codePoint;
|
|
730
796
|
}
|
|
731
|
-
const
|
|
732
|
-
const
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
797
|
+
const FIELD_SELECTOR = 'span[data-document-field]';
|
|
798
|
+
const FIELD_TEXT_BOUNDARY = '\uFFFC';
|
|
799
|
+
const FIELD_COMMANDS = {
|
|
800
|
+
page: 'PAGE',
|
|
801
|
+
numPages: 'NUMPAGES',
|
|
802
|
+
section: 'SECTION',
|
|
803
|
+
sectionPages: 'SECTIONPAGES',
|
|
804
|
+
date: 'DATE \\@ "yyyy年M月d日"',
|
|
805
|
+
time: 'TIME \\@ "HH:mm"',
|
|
806
|
+
wordCount: 'NUMWORDS',
|
|
807
|
+
characterCount: 'NUMCHARS',
|
|
808
|
+
pageReference: 'PAGEREF'
|
|
809
|
+
};
|
|
810
|
+
const FIELD_LABELS = {
|
|
811
|
+
page: '当前页码',
|
|
812
|
+
numPages: '总页数',
|
|
813
|
+
section: '当前节号',
|
|
814
|
+
sectionPages: '本节页数',
|
|
815
|
+
date: '当前日期',
|
|
816
|
+
time: '当前时间',
|
|
817
|
+
wordCount: '字数',
|
|
818
|
+
characterCount: '字符数',
|
|
819
|
+
pageReference: '目标页码'
|
|
820
|
+
};
|
|
821
|
+
function documentFieldKind(value) {
|
|
822
|
+
if ('page' === value || 'numPages' === value || 'section' === value || 'sectionPages' === value || 'date' === value || 'time' === value || 'wordCount' === value || 'characterCount' === value || 'pageReference' === value) return value;
|
|
823
|
+
return null;
|
|
741
824
|
}
|
|
742
|
-
function
|
|
743
|
-
|
|
825
|
+
function docxDocumentFieldKind(instruction) {
|
|
826
|
+
const command = /^\s*([a-z][a-z0-9]*)\b/i.exec(instruction)?.[1]?.toUpperCase();
|
|
827
|
+
if ('PAGE' === command) return 'page';
|
|
828
|
+
if ('NUMPAGES' === command) return 'numPages';
|
|
829
|
+
if ('SECTION' === command) return 'section';
|
|
830
|
+
if ('SECTIONPAGES' === command) return 'sectionPages';
|
|
831
|
+
if ('DATE' === command) return 'date';
|
|
832
|
+
if ('TIME' === command) return 'time';
|
|
833
|
+
if ('NUMWORDS' === command) return 'wordCount';
|
|
834
|
+
if ('NUMCHARS' === command) return 'characterCount';
|
|
835
|
+
if ('PAGEREF' === command) return 'pageReference';
|
|
836
|
+
return null;
|
|
744
837
|
}
|
|
745
|
-
function
|
|
746
|
-
|
|
838
|
+
function documentFieldInstruction(kind, options = {}) {
|
|
839
|
+
if ('pageReference' === kind) return documentPageReferenceInstruction(options.targetName, '', true);
|
|
840
|
+
return FIELD_COMMANDS[kind];
|
|
747
841
|
}
|
|
748
|
-
function
|
|
749
|
-
|
|
842
|
+
function documentPageReferenceInstruction(targetName, source = '', defaultHyperlink = false) {
|
|
843
|
+
const target = normalizeFieldTarget(targetName);
|
|
844
|
+
if (!target) return FIELD_COMMANDS.pageReference;
|
|
845
|
+
const switches = [];
|
|
846
|
+
if (/(?:^|\s)\\h(?:\s|$)/i.test(source)) switches.push('\\h');
|
|
847
|
+
if (/(?:^|\s)\\\*\s+MERGEFORMAT(?:\s|$)/i.test(source)) switches.push('\\* MERGEFORMAT');
|
|
848
|
+
if (!switches.length && defaultHyperlink) switches.push('\\h');
|
|
849
|
+
return `PAGEREF ${target}${switches.length ? ` ${switches.join(' ')}` : ''}`;
|
|
750
850
|
}
|
|
751
|
-
function
|
|
752
|
-
|
|
753
|
-
figure: 0,
|
|
754
|
-
table: 0
|
|
755
|
-
};
|
|
756
|
-
const usedIds = new Set();
|
|
757
|
-
return Array.from(document1.body.querySelectorAll(CAPTION_SELECTOR)).map((element, index)=>{
|
|
758
|
-
const kind = documentCaptionKind(element.dataset.captionKind) ?? 'figure';
|
|
759
|
-
counters[kind] += 1;
|
|
760
|
-
const number = counters[kind];
|
|
761
|
-
const id = uniqueCaptionId(element.dataset.captionId, kind, index + 1, usedIds);
|
|
762
|
-
const label = documentCaptionLabel(kind);
|
|
763
|
-
element.dataset.documentCaption = 'true';
|
|
764
|
-
element.dataset.captionId = id;
|
|
765
|
-
element.dataset.captionKind = kind;
|
|
766
|
-
element.dataset.captionNumber = String(number);
|
|
767
|
-
element.dataset.captionLabel = label;
|
|
768
|
-
element.classList.add('work-document-caption');
|
|
769
|
-
const title = element.textContent?.replace(/\s+/g, ' ').trim() ?? '';
|
|
770
|
-
const display = documentCaptionDisplay(kind, number);
|
|
771
|
-
element.setAttribute('aria-label', title ? `${display} ${title}` : display);
|
|
772
|
-
return {
|
|
773
|
-
id,
|
|
774
|
-
kind,
|
|
775
|
-
number,
|
|
776
|
-
label,
|
|
777
|
-
title,
|
|
778
|
-
display
|
|
779
|
-
};
|
|
780
|
-
});
|
|
851
|
+
function documentFieldLabel(kind) {
|
|
852
|
+
return FIELD_LABELS[kind];
|
|
781
853
|
}
|
|
782
|
-
function
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
854
|
+
function documentFieldDisplay(kind, context, instruction = documentFieldInstruction(kind), cachedValue = '') {
|
|
855
|
+
if ('page' === kind) return String(positiveInteger(context.pageNumber));
|
|
856
|
+
if ('numPages' === kind) return String(positiveInteger(context.totalPages));
|
|
857
|
+
if ('section' === kind) return String(positiveInteger(context.sectionNumber));
|
|
858
|
+
if ('sectionPages' === kind) return String(positiveInteger(context.sectionPages));
|
|
859
|
+
if ('wordCount' === kind) return String(nonNegativeInteger(context.wordCount, cachedValue));
|
|
860
|
+
if ('characterCount' === kind) return String(nonNegativeInteger(context.characterCount, cachedValue));
|
|
861
|
+
if ('pageReference' === kind) {
|
|
862
|
+
const target = docxDocumentFieldTarget(instruction);
|
|
863
|
+
const hasResolutionContext = void 0 !== context.referencePageNumber || void 0 !== context.bookmarkPageNumbers;
|
|
864
|
+
const page = context.referencePageNumber ?? (target ? context.bookmarkPageNumbers?.get(`name:${target.toLowerCase()}`) : void 0);
|
|
865
|
+
return page && Number.isSafeInteger(page) && page > 0 ? String(page) : hasResolutionContext ? '引用缺失' : cachedValue.trim() || '引用缺失';
|
|
866
|
+
}
|
|
867
|
+
const now = validDate(context.now) ?? new Date();
|
|
868
|
+
const format = dateFormatSwitch(instruction) ?? ('date' === kind ? 'yyyy年M月d日' : 'HH:mm');
|
|
869
|
+
const display = formatWordDate(now, format);
|
|
870
|
+
return display || cachedValue || documentFieldLabel(kind);
|
|
871
|
+
}
|
|
872
|
+
function normalizeDocumentFieldsHtml(source) {
|
|
873
|
+
const document1 = new DOMParser().parseFromString(source, 'text/html');
|
|
874
|
+
const usedIds = new Set();
|
|
875
|
+
for (const [index, element] of Array.from(document1.body.querySelectorAll(FIELD_SELECTOR)).entries()){
|
|
876
|
+
const instruction = element.dataset.fieldInstruction?.trim() ?? '';
|
|
877
|
+
const kind = documentFieldKind(element.dataset.fieldKind) ?? docxDocumentFieldKind(instruction);
|
|
878
|
+
if (!kind) {
|
|
879
|
+
element.replaceWith(document1.createTextNode(element.textContent ?? ''));
|
|
793
880
|
continue;
|
|
794
881
|
}
|
|
795
|
-
|
|
796
|
-
element.dataset.
|
|
797
|
-
element.dataset.
|
|
798
|
-
element.dataset.
|
|
799
|
-
element.
|
|
882
|
+
const display = element.dataset.fieldDisplay?.trim() || element.textContent?.trim() || documentFieldLabel(kind);
|
|
883
|
+
element.dataset.documentField = 'true';
|
|
884
|
+
element.dataset.fieldId = uniqueFieldId(element.dataset.fieldId, index + 1, usedIds);
|
|
885
|
+
element.dataset.fieldKind = kind;
|
|
886
|
+
element.dataset.fieldInstruction = instruction || documentFieldInstruction(kind);
|
|
887
|
+
if ('pageReference' === kind) {
|
|
888
|
+
const targetName = normalizeFieldTarget(element.dataset.fieldTargetName) ?? docxDocumentFieldTarget(instruction);
|
|
889
|
+
if (targetName) {
|
|
890
|
+
element.dataset.fieldTargetName = targetName;
|
|
891
|
+
element.dataset.fieldInstruction = documentPageReferenceInstruction(targetName, instruction);
|
|
892
|
+
delete element.dataset.fieldOrphaned;
|
|
893
|
+
} else {
|
|
894
|
+
delete element.dataset.fieldTargetName;
|
|
895
|
+
element.dataset.fieldOrphaned = 'true';
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
element.dataset.fieldDisplay = display;
|
|
899
|
+
element.classList.add('work-document-field');
|
|
900
|
+
element.textContent = display;
|
|
800
901
|
}
|
|
902
|
+
return document1.body.innerHTML;
|
|
801
903
|
}
|
|
802
|
-
function
|
|
904
|
+
function resolveDocumentFieldsHtml(source, context) {
|
|
905
|
+
const document1 = new DOMParser().parseFromString(normalizeDocumentFieldsHtml(source), 'text/html');
|
|
906
|
+
for (const element of Array.from(document1.body.querySelectorAll(FIELD_SELECTOR))){
|
|
907
|
+
const kind = documentFieldKind(element.dataset.fieldKind);
|
|
908
|
+
if (!kind) continue;
|
|
909
|
+
const referencePageNumber = 'pageReference' === kind ? context.referencePageNumber ?? (element.dataset.fieldTargetId ? context.bookmarkPageNumbers?.get(`id:${element.dataset.fieldTargetId.trim()}`) : void 0) : context.referencePageNumber;
|
|
910
|
+
const display = documentFieldDisplay(kind, {
|
|
911
|
+
...context,
|
|
912
|
+
referencePageNumber
|
|
913
|
+
}, element.dataset.fieldInstruction, element.dataset.fieldDisplay);
|
|
914
|
+
element.dataset.fieldDisplay = display;
|
|
915
|
+
element.textContent = display;
|
|
916
|
+
}
|
|
917
|
+
return document1.body.innerHTML;
|
|
918
|
+
}
|
|
919
|
+
function uniqueFieldId(source, index, usedIds) {
|
|
803
920
|
const candidate = source?.trim();
|
|
804
921
|
if (candidate && !usedIds.has(candidate)) {
|
|
805
922
|
usedIds.add(candidate);
|
|
806
923
|
return candidate;
|
|
807
924
|
}
|
|
808
925
|
let suffix = index;
|
|
809
|
-
while(usedIds.has(`document
|
|
810
|
-
const id = `document
|
|
926
|
+
while(usedIds.has(`document-field-${suffix}`))suffix += 1;
|
|
927
|
+
const id = `document-field-${suffix}`;
|
|
811
928
|
usedIds.add(id);
|
|
812
929
|
return id;
|
|
813
930
|
}
|
|
931
|
+
function dateFormatSwitch(instruction) {
|
|
932
|
+
return /\\@\s+"([^"]+)"/i.exec(instruction)?.[1] ?? null;
|
|
933
|
+
}
|
|
934
|
+
function docxDocumentFieldTarget(instruction) {
|
|
935
|
+
const kind = docxDocumentFieldKind(instruction);
|
|
936
|
+
if ('pageReference' !== kind) return null;
|
|
937
|
+
return normalizeFieldTarget(/^\s*PAGEREF\s+([^\s\\]+)/i.exec(instruction)?.[1]);
|
|
938
|
+
}
|
|
939
|
+
function supportedDocxDocumentFieldInstruction(instruction) {
|
|
940
|
+
const kind = docxDocumentFieldKind(instruction);
|
|
941
|
+
if (!kind) return false;
|
|
942
|
+
const source = instruction.trim();
|
|
943
|
+
if ('pageReference' === kind) {
|
|
944
|
+
const match = /^PAGEREF\s+([^\s\\]+)([\s\S]*)$/i.exec(source);
|
|
945
|
+
const target = normalizeFieldTarget(match?.[1]);
|
|
946
|
+
if (!target || !match) return false;
|
|
947
|
+
let rest = match[2] ?? '';
|
|
948
|
+
const hyperlink = /^\s+\\h\b/i.exec(rest);
|
|
949
|
+
if (hyperlink) rest = rest.slice(hyperlink[0].length);
|
|
950
|
+
return onlyMergeFormatSwitch(rest);
|
|
951
|
+
}
|
|
952
|
+
if ('date' === kind || 'time' === kind) {
|
|
953
|
+
const command = 'date' === kind ? 'DATE' : 'TIME';
|
|
954
|
+
const match = new RegExp(`^${command}\\b([\\s\\S]*)$`, 'i').exec(source);
|
|
955
|
+
if (!match) return false;
|
|
956
|
+
let rest = match[1] ?? '';
|
|
957
|
+
const format = /^\s+\\@\s+"[^"\r\n]{1,128}"/i.exec(rest);
|
|
958
|
+
if (format) rest = rest.slice(format[0].length);
|
|
959
|
+
return onlyMergeFormatSwitch(rest);
|
|
960
|
+
}
|
|
961
|
+
const command = FIELD_COMMANDS[kind];
|
|
962
|
+
const match = new RegExp(`^${command}\\b([\\s\\S]*)$`, 'i').exec(source);
|
|
963
|
+
return Boolean(match && onlyMergeFormatSwitch(match[1] ?? ''));
|
|
964
|
+
}
|
|
965
|
+
function onlyMergeFormatSwitch(source) {
|
|
966
|
+
return /^(?:\s+\\\*\s+MERGEFORMAT)?\s*$/i.test(source);
|
|
967
|
+
}
|
|
968
|
+
function documentFieldStatisticsFromText(source) {
|
|
969
|
+
const normalized = source.replace(/\r\n?/g, '\n');
|
|
970
|
+
let characterCount = 0;
|
|
971
|
+
for(let index = 0; index < normalized.length; index += 1){
|
|
972
|
+
const codePoint = normalized.codePointAt(index);
|
|
973
|
+
if (void 0 !== codePoint) {
|
|
974
|
+
if (codePoint > 0xffff) index += 1;
|
|
975
|
+
if (0x0a !== codePoint && 0xfffc !== codePoint) characterCount += 1;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
return {
|
|
979
|
+
wordCount: documentWordCount(normalized),
|
|
980
|
+
characterCount
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
function documentFieldStatisticsFromHtml(source) {
|
|
984
|
+
const document1 = new DOMParser().parseFromString(source, 'text/html');
|
|
985
|
+
for (const field of Array.from(document1.body.querySelectorAll('[data-document-field]')))field.replaceWith(document1.createTextNode(FIELD_TEXT_BOUNDARY));
|
|
986
|
+
return documentFieldStatisticsFromText(document1.body.textContent ?? '');
|
|
987
|
+
}
|
|
988
|
+
function formatWordDate(date, format) {
|
|
989
|
+
const hour12 = date.getHours() % 12 || 12;
|
|
990
|
+
const replacements = {
|
|
991
|
+
'AM/PM': date.getHours() < 12 ? 'AM' : 'PM',
|
|
992
|
+
'am/pm': date.getHours() < 12 ? 'am' : 'pm',
|
|
993
|
+
yyyy: String(date.getFullYear()).padStart(4, '0'),
|
|
994
|
+
yy: String(date.getFullYear() % 100).padStart(2, '0'),
|
|
995
|
+
MMMM: new Intl.DateTimeFormat('zh-CN', {
|
|
996
|
+
month: 'long'
|
|
997
|
+
}).format(date),
|
|
998
|
+
MMM: new Intl.DateTimeFormat('zh-CN', {
|
|
999
|
+
month: 'short'
|
|
1000
|
+
}).format(date),
|
|
1001
|
+
MM: String(date.getMonth() + 1).padStart(2, '0'),
|
|
1002
|
+
M: String(date.getMonth() + 1),
|
|
1003
|
+
dddd: new Intl.DateTimeFormat('zh-CN', {
|
|
1004
|
+
weekday: 'long'
|
|
1005
|
+
}).format(date),
|
|
1006
|
+
ddd: new Intl.DateTimeFormat('zh-CN', {
|
|
1007
|
+
weekday: 'short'
|
|
1008
|
+
}).format(date),
|
|
1009
|
+
dd: String(date.getDate()).padStart(2, '0'),
|
|
1010
|
+
d: String(date.getDate()),
|
|
1011
|
+
HH: String(date.getHours()).padStart(2, '0'),
|
|
1012
|
+
H: String(date.getHours()),
|
|
1013
|
+
hh: String(hour12).padStart(2, '0'),
|
|
1014
|
+
h: String(hour12),
|
|
1015
|
+
mm: String(date.getMinutes()).padStart(2, '0'),
|
|
1016
|
+
m: String(date.getMinutes()),
|
|
1017
|
+
ss: String(date.getSeconds()).padStart(2, '0'),
|
|
1018
|
+
s: String(date.getSeconds())
|
|
1019
|
+
};
|
|
1020
|
+
return format.replace(/AM\/PM|am\/pm|yyyy|MMMM|dddd|MMM|ddd|yy|MM|dd|HH|hh|mm|ss|M|d|H|h|m|s/g, (token)=>replacements[token] ?? token);
|
|
1021
|
+
}
|
|
814
1022
|
function positiveInteger(value) {
|
|
815
|
-
|
|
816
|
-
return Number.isSafeInteger(number) && number > 0 ? number : 1;
|
|
1023
|
+
return Number.isSafeInteger(value) && value > 0 ? value : 1;
|
|
817
1024
|
}
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
const
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
1025
|
+
function nonNegativeInteger(value, cachedValue) {
|
|
1026
|
+
if (void 0 !== value && Number.isSafeInteger(value) && value >= 0) return value;
|
|
1027
|
+
const cached = Number(cachedValue.trim());
|
|
1028
|
+
return Number.isSafeInteger(cached) && cached >= 0 ? cached : 0;
|
|
1029
|
+
}
|
|
1030
|
+
function normalizeFieldTarget(value) {
|
|
1031
|
+
if ('string' != typeof value) return null;
|
|
1032
|
+
const target = value.trim();
|
|
1033
|
+
return /^[\p{L}_][\p{L}\p{N}_]*$/u.test(target) ? target : null;
|
|
1034
|
+
}
|
|
1035
|
+
function validDate(value) {
|
|
1036
|
+
return value && Number.isFinite(value.getTime()) ? value : null;
|
|
1037
|
+
}
|
|
1038
|
+
const BOOKMARK_NAME_PATTERN = /^[\p{L}_][\p{L}\p{N}_]*$/u;
|
|
1039
|
+
const BOOKMARK_UI_NAME_PATTERN = /^[\p{L}][\p{L}\p{N}_]*$/u;
|
|
1040
|
+
const MAX_BOOKMARK_NAME_LENGTH = 40;
|
|
1041
|
+
const MAX_BOOKMARK_NATIVE_ID = 0x7fffffff;
|
|
1042
|
+
const MISSING_LINK_CLASS = 'work-document-link-missing';
|
|
1043
|
+
const DOCUMENT_BOOKMARK_VALIDATION_MESSAGE = '书签名称需以字母开头,只能包含字母、数字和下划线,且不超过 40 个字符。';
|
|
1044
|
+
const DOCUMENT_BOOKMARK_DUPLICATE_MESSAGE = '文档中已存在同名书签。';
|
|
1045
|
+
const DocumentBookmarkBoundary = core_Node.create({
|
|
1046
|
+
name: 'documentBookmarkBoundary',
|
|
1047
|
+
inline: true,
|
|
1048
|
+
group: 'inline',
|
|
1049
|
+
atom: true,
|
|
1050
|
+
selectable: false,
|
|
1051
|
+
addCommands () {
|
|
1052
|
+
return {
|
|
1053
|
+
insertDocumentBookmark: (name)=>(props)=>insertDocumentBookmarkCommand(props, name),
|
|
1054
|
+
deleteDocumentBookmark: (id)=>(props)=>deleteDocumentBookmarkCommand(props, id)
|
|
1055
|
+
};
|
|
824
1056
|
},
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
1057
|
+
addProseMirrorPlugins () {
|
|
1058
|
+
return [
|
|
1059
|
+
createDocumentBookmarkPlugin(this.name)
|
|
1060
|
+
];
|
|
828
1061
|
},
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
1062
|
+
addAttributes () {
|
|
1063
|
+
return {
|
|
1064
|
+
id: {
|
|
1065
|
+
default: '',
|
|
1066
|
+
parseHTML: (element)=>element.dataset.bookmarkId ?? '',
|
|
1067
|
+
renderHTML: ()=>({})
|
|
1068
|
+
},
|
|
1069
|
+
name: {
|
|
1070
|
+
default: '',
|
|
1071
|
+
parseHTML: (element)=>element.dataset.bookmarkName ?? '',
|
|
1072
|
+
renderHTML: ()=>({})
|
|
1073
|
+
},
|
|
1074
|
+
nativeId: {
|
|
1075
|
+
default: null,
|
|
1076
|
+
parseHTML: (element)=>normalizeDocumentBookmarkNativeId(element.dataset.officeBookmarkId),
|
|
1077
|
+
renderHTML: ()=>({})
|
|
1078
|
+
},
|
|
1079
|
+
kind: {
|
|
1080
|
+
default: 'start',
|
|
1081
|
+
parseHTML: (element)=>documentBookmarkBoundaryKind(element.dataset.bookmarkKind),
|
|
1082
|
+
renderHTML: ()=>({})
|
|
1083
|
+
}
|
|
1084
|
+
};
|
|
832
1085
|
},
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
1086
|
+
parseHTML () {
|
|
1087
|
+
return [
|
|
1088
|
+
{
|
|
1089
|
+
tag: 'span[data-document-bookmark-boundary]',
|
|
1090
|
+
getAttrs: (node)=>{
|
|
1091
|
+
if (!(node instanceof HTMLElement)) return false;
|
|
1092
|
+
return {
|
|
1093
|
+
id: node.dataset.bookmarkId ?? '',
|
|
1094
|
+
name: node.dataset.bookmarkName ?? '',
|
|
1095
|
+
nativeId: normalizeDocumentBookmarkNativeId(node.dataset.officeBookmarkId),
|
|
1096
|
+
kind: documentBookmarkBoundaryKind(node.dataset.bookmarkKind)
|
|
1097
|
+
};
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
];
|
|
1101
|
+
},
|
|
1102
|
+
renderHTML ({ node, HTMLAttributes }) {
|
|
1103
|
+
const name = normalizeDocumentBookmarkName(node.attrs.name) ?? '';
|
|
1104
|
+
const nativeId = normalizeDocumentBookmarkNativeId(node.attrs.nativeId);
|
|
1105
|
+
const kind = documentBookmarkBoundaryKind(node.attrs.kind);
|
|
1106
|
+
return [
|
|
1107
|
+
'span',
|
|
1108
|
+
mergeAttributes(HTMLAttributes, {
|
|
1109
|
+
...'start' === kind && name ? {
|
|
1110
|
+
id: name
|
|
1111
|
+
} : {},
|
|
1112
|
+
'data-document-bookmark-boundary': 'true',
|
|
1113
|
+
'data-bookmark-kind': kind,
|
|
1114
|
+
'data-bookmark-id': 'string' == typeof node.attrs.id ? node.attrs.id : '',
|
|
1115
|
+
'data-bookmark-name': name,
|
|
1116
|
+
'data-office-bookmark-id': null === nativeId ? void 0 : String(nativeId),
|
|
1117
|
+
class: `work-document-bookmark-boundary ${kind}`,
|
|
1118
|
+
contenteditable: 'false',
|
|
1119
|
+
'aria-hidden': 'true'
|
|
1120
|
+
})
|
|
1121
|
+
];
|
|
1122
|
+
},
|
|
1123
|
+
renderText () {
|
|
1124
|
+
return '';
|
|
836
1125
|
}
|
|
837
|
-
};
|
|
838
|
-
function
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
styleName: STYLE_DETAILS[style].name,
|
|
842
|
-
selectedStyle: STYLE_DETAILS[style].selectedStyle,
|
|
843
|
-
sources: []
|
|
844
|
-
};
|
|
845
|
-
}
|
|
846
|
-
function documentCitationStyle(value) {
|
|
847
|
-
if ('mla' === value || 'chicago' === value || 'ieee' === value) return value;
|
|
848
|
-
return 'apa';
|
|
1126
|
+
});
|
|
1127
|
+
function validateDocumentBookmarkName(value) {
|
|
1128
|
+
const name = value.trim();
|
|
1129
|
+
return BOOKMARK_UI_NAME_PATTERN.test(name) && Array.from(name).length <= MAX_BOOKMARK_NAME_LENGTH ? null : DOCUMENT_BOOKMARK_VALIDATION_MESSAGE;
|
|
849
1130
|
}
|
|
850
|
-
function
|
|
851
|
-
return
|
|
1131
|
+
function normalizeDocumentBookmarkName(value) {
|
|
1132
|
+
if ('string' != typeof value) return null;
|
|
1133
|
+
const name = value.trim();
|
|
1134
|
+
return BOOKMARK_NAME_PATTERN.test(name) && Array.from(name).length <= MAX_BOOKMARK_NAME_LENGTH ? name : null;
|
|
852
1135
|
}
|
|
853
|
-
function
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
primary[1] || primary[2]
|
|
858
|
-
];
|
|
859
|
-
const additional = /\\m\s+(?:"([^"]+)"|([^\s\\]+))/gi;
|
|
860
|
-
for (const match of instruction.matchAll(additional))tags.push(match[1] || match[2]);
|
|
861
|
-
return uniqueCitationTags(tags);
|
|
1136
|
+
function normalizeDocumentBookmarkNativeId(value) {
|
|
1137
|
+
if (null == value || '' === value || 'string' == typeof value && !value.trim()) return null;
|
|
1138
|
+
const number = 'number' == typeof value ? value : Number(value);
|
|
1139
|
+
return Number.isSafeInteger(number) && number >= 0 && number <= MAX_BOOKMARK_NATIVE_ID ? number : null;
|
|
862
1140
|
}
|
|
863
|
-
function
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
citationTagInstructionValue(tag)
|
|
872
|
-
]),
|
|
873
|
-
'\\l',
|
|
874
|
-
'2052'
|
|
875
|
-
].join(' ');
|
|
1141
|
+
function editorDocumentBookmarks(editor) {
|
|
1142
|
+
return collectDocumentBookmarkPairs(editor.state.doc, 'documentBookmarkBoundary').pairs.map(({ id, name, nativeId, from, to })=>({
|
|
1143
|
+
id,
|
|
1144
|
+
name,
|
|
1145
|
+
nativeId,
|
|
1146
|
+
from,
|
|
1147
|
+
to
|
|
1148
|
+
}));
|
|
876
1149
|
}
|
|
877
|
-
function
|
|
878
|
-
return
|
|
879
|
-
const
|
|
880
|
-
return
|
|
1150
|
+
function editorDocumentBookmarkReferenceTargets(editor) {
|
|
1151
|
+
return collectDocumentBookmarkPairs(editor.state.doc, 'documentBookmarkBoundary').pairs.map((bookmark)=>{
|
|
1152
|
+
const display = documentBookmarkReferenceDisplay(editor.state.doc, bookmark);
|
|
1153
|
+
return {
|
|
1154
|
+
type: 'bookmark',
|
|
1155
|
+
id: bookmark.id,
|
|
1156
|
+
name: bookmark.name,
|
|
1157
|
+
title: display,
|
|
1158
|
+
display,
|
|
1159
|
+
instruction: documentBookmarkReferenceInstruction(bookmark.name)
|
|
1160
|
+
};
|
|
881
1161
|
});
|
|
882
1162
|
}
|
|
883
|
-
function
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
return /^[A-Za-z0-9_:.+-]{1,80}$/.test(value);
|
|
1163
|
+
function activeDocumentBookmark(editor) {
|
|
1164
|
+
const { from, to } = editor.state.selection;
|
|
1165
|
+
const matches = editorDocumentBookmarks(editor).filter((bookmark)=>from >= bookmark.from + 1 && to <= bookmark.to);
|
|
1166
|
+
return matches.sort((left, right)=>left.to - left.from - (right.to - right.from))[0] ?? null;
|
|
888
1167
|
}
|
|
889
|
-
function
|
|
890
|
-
const
|
|
891
|
-
|
|
892
|
-
text: cachedValue || '缺失引文',
|
|
893
|
-
orphaned: true
|
|
894
|
-
};
|
|
895
|
-
const sources = new Map((bibliography?.sources ?? []).map((source)=>[
|
|
896
|
-
source.tag,
|
|
897
|
-
source
|
|
898
|
-
]));
|
|
899
|
-
const missing = normalized.filter((tag)=>!sources.has(tag));
|
|
900
|
-
if (missing.length) return {
|
|
901
|
-
text: 1 === missing.length ? `缺失引文:${missing[0]}` : `缺失引文:${missing.join('、')}`,
|
|
902
|
-
orphaned: true
|
|
903
|
-
};
|
|
904
|
-
const selected = normalized.flatMap((tag)=>{
|
|
905
|
-
const source = sources.get(tag);
|
|
906
|
-
return source ? [
|
|
907
|
-
source
|
|
908
|
-
] : [];
|
|
909
|
-
});
|
|
910
|
-
const style = bibliography?.style ?? 'apa';
|
|
911
|
-
const suppressAuthor = /(?:^|\s)\\n(?:\s|$)/i.test(instruction);
|
|
912
|
-
const suppressYear = /(?:^|\s)\\v(?:\s|$)/i.test(instruction);
|
|
913
|
-
const prefix = citationSwitch(instruction, 'f');
|
|
914
|
-
const suffix = citationSwitch(instruction, 'p');
|
|
915
|
-
const text = 'ieee' === style ? ieeeCitation(selected, bibliography?.sources ?? []) : 'mla' === style ? mlaCitation(selected, suppressAuthor) : 'chicago' === style ? chicagoCitation(selected, suppressAuthor, suppressYear) : apaCitation(selected, suppressAuthor, suppressYear);
|
|
916
|
-
return {
|
|
917
|
-
text: `${prefix}${text}${suffix}`.trim() || cachedValue || normalized.join('; '),
|
|
918
|
-
orphaned: false
|
|
919
|
-
};
|
|
1168
|
+
function documentBookmarkNameExists(editor, value, exceptId) {
|
|
1169
|
+
const name = value.trim().toLowerCase();
|
|
1170
|
+
return editorDocumentBookmarks(editor).some((bookmark)=>bookmark.id !== exceptId && bookmark.name.toLowerCase() === name);
|
|
920
1171
|
}
|
|
921
|
-
function
|
|
1172
|
+
function normalizeDocumentBookmarksHtml(source) {
|
|
922
1173
|
const document1 = new DOMParser().parseFromString(source, 'text/html');
|
|
923
|
-
const
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
1174
|
+
const boundaries = Array.from(document1.body.querySelectorAll('span[data-document-bookmark-boundary]'));
|
|
1175
|
+
const collection = collectDomBookmarkPairs(boundaries);
|
|
1176
|
+
for (const orphan of collection.orphans)orphan.remove();
|
|
1177
|
+
const registry = createBookmarkRegistry();
|
|
1178
|
+
for (const pair of collection.pairs){
|
|
1179
|
+
const previous = {
|
|
1180
|
+
id: bookmarkInternalId(pair.id),
|
|
1181
|
+
name: normalizeDocumentBookmarkName(pair.name) ?? ''
|
|
1182
|
+
};
|
|
1183
|
+
const identity = uniqueDocumentBookmarkIdentity(pair, registry);
|
|
1184
|
+
applyBookmarkIdentityToElement(pair.start, identity, 'start');
|
|
1185
|
+
applyBookmarkIdentityToElement(pair.end, identity, 'end');
|
|
1186
|
+
if (previous.id && previous.name && (previous.id !== identity.id || previous.name !== identity.name)) {
|
|
1187
|
+
retargetDomBookmarkReferences(document1.body, pair.start, pair.end, previous, identity);
|
|
1188
|
+
retargetDomPageReferences(document1.body, pair.start, pair.end, previous, identity);
|
|
931
1189
|
}
|
|
932
|
-
const cached = element.dataset.citationDisplay?.trim() || element.textContent?.trim() || '';
|
|
933
|
-
const resolved = resolveDocumentCitation(normalizedTags, bibliography, instruction, cached);
|
|
934
|
-
element.dataset.documentCitation = 'true';
|
|
935
|
-
element.dataset.citationId = uniqueCitationId(element.dataset.citationId, index + 1, usedIds);
|
|
936
|
-
element.dataset.citationTags = normalizedTags.join(' ');
|
|
937
|
-
element.dataset.citationInstruction = instruction || documentCitationInstruction(normalizedTags);
|
|
938
|
-
element.dataset.citationDisplay = resolved.text;
|
|
939
|
-
if (resolved.orphaned) element.dataset.citationOrphaned = 'true';
|
|
940
|
-
else delete element.dataset.citationOrphaned;
|
|
941
|
-
element.classList.add('work-document-citation');
|
|
942
|
-
element.textContent = resolved.text;
|
|
943
|
-
}
|
|
944
|
-
for (const [index, element] of Array.from(document1.body.querySelectorAll(BIBLIOGRAPHY_SELECTOR)).entries()){
|
|
945
|
-
if (!bibliography) continue;
|
|
946
|
-
const replacement = createBibliographyElement(document1, bibliography, element.dataset.bibliographyId || `document-bibliography-${index + 1}`);
|
|
947
|
-
element.replaceWith(replacement);
|
|
948
1190
|
}
|
|
1191
|
+
synchronizeDomInternalLinks(document1.body, registry.names);
|
|
949
1192
|
return document1.body.innerHTML;
|
|
950
1193
|
}
|
|
951
|
-
function
|
|
952
|
-
const
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
const
|
|
958
|
-
const
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
year ? `${year}.` : '',
|
|
967
|
-
url ?? ''
|
|
968
|
-
].filter(Boolean).join(' ');
|
|
969
|
-
if ('mla' === bibliography.style) return [
|
|
970
|
-
`${authors}.`,
|
|
971
|
-
`“${title}.”`,
|
|
972
|
-
container ? `${container},` : '',
|
|
973
|
-
`${year}.`,
|
|
974
|
-
url ?? ''
|
|
975
|
-
].filter(Boolean).join(' ');
|
|
976
|
-
if ('chicago' === bibliography.style) return [
|
|
977
|
-
`${authors}.`,
|
|
978
|
-
`${year}.`,
|
|
979
|
-
`“${title}.”`,
|
|
980
|
-
container ? `${container}.` : '',
|
|
981
|
-
url ?? ''
|
|
982
|
-
].filter(Boolean).join(' ');
|
|
983
|
-
return [
|
|
984
|
-
`${authors}.`,
|
|
985
|
-
`(${year}).`,
|
|
986
|
-
`${title}.`,
|
|
987
|
-
container ? `${container}.` : '',
|
|
988
|
-
url ?? ''
|
|
989
|
-
].filter(Boolean).join(' ');
|
|
990
|
-
}
|
|
991
|
-
function primaryCitationContributor(source) {
|
|
992
|
-
return source.contributors?.Author ?? Object.values(source.contributors ?? {})[0];
|
|
993
|
-
}
|
|
994
|
-
function createBibliographyElement(document1, bibliography, id) {
|
|
995
|
-
const section = document1.createElement('section');
|
|
996
|
-
section.dataset.documentBibliography = 'true';
|
|
997
|
-
section.dataset.bibliographyId = id;
|
|
998
|
-
section.dataset.bibliographyStyle = bibliography.style;
|
|
999
|
-
section.className = 'work-document-bibliography';
|
|
1000
|
-
const heading = document1.createElement('h2');
|
|
1001
|
-
heading.textContent = '参考文献';
|
|
1002
|
-
section.append(heading);
|
|
1003
|
-
if (!bibliography.sources.length) {
|
|
1004
|
-
const empty = document1.createElement('p');
|
|
1005
|
-
empty.dataset.bibliographyEmpty = 'true';
|
|
1006
|
-
empty.textContent = '尚无文献源';
|
|
1007
|
-
section.append(empty);
|
|
1008
|
-
return section;
|
|
1009
|
-
}
|
|
1010
|
-
bibliography.sources.forEach((source, index)=>{
|
|
1011
|
-
const paragraph = document1.createElement('p');
|
|
1012
|
-
paragraph.dataset.bibliographyEntry = source.tag;
|
|
1013
|
-
paragraph.textContent = documentBibliographyEntry(source, bibliography, index);
|
|
1014
|
-
section.append(paragraph);
|
|
1194
|
+
function insertDocumentBookmarkCommand({ dispatch, editor, state, tr }, value) {
|
|
1195
|
+
const name = value.trim();
|
|
1196
|
+
const boundaryType = editor.schema.nodes.documentBookmarkBoundary;
|
|
1197
|
+
const selection = state.selection;
|
|
1198
|
+
if (!boundaryType || validateDocumentBookmarkName(name) || documentBookmarkNameExists(editor, name) || !selection.$from.parent.inlineContent || !selection.$to.parent.inlineContent) return false;
|
|
1199
|
+
if (!dispatch) return true;
|
|
1200
|
+
const registry = bookmarkRegistryForDocument(state.doc, boundaryType.name);
|
|
1201
|
+
const identity = uniqueDocumentBookmarkIdentity({
|
|
1202
|
+
id: createUniqueBookmarkId(registry.ids),
|
|
1203
|
+
name,
|
|
1204
|
+
nativeId: nextBookmarkNativeId(registry.nativeIds)
|
|
1205
|
+
}, registry);
|
|
1206
|
+
const start = boundaryType.create({
|
|
1207
|
+
...identity,
|
|
1208
|
+
kind: 'start'
|
|
1015
1209
|
});
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
const items = sources.map((source)=>{
|
|
1020
|
-
const author = suppressAuthor ? '' : citationAuthor(source, '&');
|
|
1021
|
-
const year = suppressYear ? '' : source.year?.trim() || 'n.d.';
|
|
1022
|
-
return [
|
|
1023
|
-
author,
|
|
1024
|
-
year
|
|
1025
|
-
].filter(Boolean).join(', ');
|
|
1210
|
+
const end = boundaryType.create({
|
|
1211
|
+
...identity,
|
|
1212
|
+
kind: 'end'
|
|
1026
1213
|
});
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
return
|
|
1034
|
-
suppressAuthor ? '' : citationAuthor(source, 'and'),
|
|
1035
|
-
suppressYear ? '' : source.year?.trim() || 'n.d.'
|
|
1036
|
-
].filter(Boolean).join(' ')).join('; ')})`;
|
|
1214
|
+
const from = selection.from;
|
|
1215
|
+
const to = selection.to;
|
|
1216
|
+
tr.insert(to, end);
|
|
1217
|
+
tr.insert(from, start);
|
|
1218
|
+
tr.setSelection(TextSelection.create(tr.doc, from + 1, to + 1));
|
|
1219
|
+
dispatch(tr.scrollIntoView());
|
|
1220
|
+
return true;
|
|
1037
1221
|
}
|
|
1038
|
-
function
|
|
1039
|
-
const
|
|
1040
|
-
|
|
1222
|
+
function deleteDocumentBookmarkCommand({ dispatch, editor, state, tr }, id) {
|
|
1223
|
+
const bookmark = collectDocumentBookmarkPairs(state.doc, editor.schema.nodes.documentBookmarkBoundary?.name ?? '').pairs.find((candidate)=>candidate.id === id);
|
|
1224
|
+
if (!bookmark) return false;
|
|
1225
|
+
if (!dispatch) return true;
|
|
1226
|
+
tr.delete(bookmark.to, bookmark.to + bookmark.end.node.nodeSize);
|
|
1227
|
+
tr.delete(bookmark.from, bookmark.from + bookmark.start.node.nodeSize);
|
|
1228
|
+
tr.setSelection(TextSelection.near(tr.doc.resolve(bookmark.from)));
|
|
1229
|
+
dispatch(tr.scrollIntoView());
|
|
1230
|
+
return true;
|
|
1041
1231
|
}
|
|
1042
|
-
function
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1232
|
+
function createDocumentBookmarkPlugin(boundaryNodeName) {
|
|
1233
|
+
return new Plugin({
|
|
1234
|
+
view (view) {
|
|
1235
|
+
const transaction = normalizeDocumentBookmarks(view.state, boundaryNodeName);
|
|
1236
|
+
if (transaction) {
|
|
1237
|
+
transaction.setMeta('addToHistory', false);
|
|
1238
|
+
view.dispatch(transaction);
|
|
1239
|
+
}
|
|
1240
|
+
return {};
|
|
1241
|
+
},
|
|
1242
|
+
appendTransaction (transactions, oldState, newState) {
|
|
1243
|
+
if (!transactions.some((transaction)=>transaction.docChanged)) return null;
|
|
1244
|
+
return normalizeDocumentBookmarks(newState, boundaryNodeName, oldState, transactions);
|
|
1245
|
+
}
|
|
1246
|
+
});
|
|
1050
1247
|
}
|
|
1051
|
-
function
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1248
|
+
function normalizeDocumentBookmarks(state, boundaryNodeName, oldState, transactions = []) {
|
|
1249
|
+
if ('documentBookmarkBoundary' === boundaryNodeName && !documentHasIntegrityFeature(state.doc, 1)) return null;
|
|
1250
|
+
const collection = collectDocumentBookmarkPairs(state.doc, boundaryNodeName);
|
|
1251
|
+
const retained = oldState ? retainedDocumentBookmarkPairs(oldState, state, transactions, boundaryNodeName) : new Set();
|
|
1252
|
+
const ordered = [
|
|
1253
|
+
...collection.pairs.filter((pair)=>retained.has(pairPositionKey(pair))),
|
|
1254
|
+
...collection.pairs.filter((pair)=>!retained.has(pairPositionKey(pair)))
|
|
1255
|
+
];
|
|
1256
|
+
const registry = createBookmarkRegistry();
|
|
1257
|
+
const updates = new Map();
|
|
1258
|
+
const renames = [];
|
|
1259
|
+
const effectivePairs = [];
|
|
1260
|
+
for (const pair of ordered){
|
|
1261
|
+
const identity = uniqueDocumentBookmarkIdentity(pair, registry);
|
|
1262
|
+
if (!sameBookmarkIdentity(pair.start.node.attrs, identity)) updates.set(pair.from, identity);
|
|
1263
|
+
if (!sameBookmarkIdentity(pair.end.node.attrs, identity)) updates.set(pair.to, identity);
|
|
1264
|
+
if (!sameBookmarkIdentity(pair, identity)) {
|
|
1265
|
+
if (pair.id && pair.name && (pair.id !== identity.id || pair.name !== identity.name)) renames.push({
|
|
1266
|
+
from: pair.from,
|
|
1267
|
+
to: pair.to,
|
|
1268
|
+
previousId: pair.id,
|
|
1269
|
+
nextId: identity.id,
|
|
1270
|
+
previousName: pair.name,
|
|
1271
|
+
nextName: identity.name
|
|
1272
|
+
});
|
|
1273
|
+
}
|
|
1274
|
+
effectivePairs.push({
|
|
1275
|
+
...pair,
|
|
1276
|
+
...identity
|
|
1277
|
+
});
|
|
1067
1278
|
}
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1279
|
+
const tr = state.tr;
|
|
1280
|
+
for (const boundary of documentBookmarkBoundaries(state.doc, boundaryNodeName)){
|
|
1281
|
+
const identity = updates.get(boundary.position);
|
|
1282
|
+
if (identity) tr.setNodeMarkup(boundary.position, void 0, {
|
|
1283
|
+
...boundary.node.attrs,
|
|
1284
|
+
...identity
|
|
1285
|
+
});
|
|
1286
|
+
}
|
|
1287
|
+
synchronizeInternalLinkMarks(state, tr, effectivePairs, renames);
|
|
1288
|
+
synchronizeDocumentBookmarkReferenceNodes(state, tr, effectivePairs, renames);
|
|
1289
|
+
synchronizeDocumentPageReferenceNodes(state, tr, effectivePairs, renames);
|
|
1290
|
+
for (const orphan of [
|
|
1291
|
+
...collection.orphans
|
|
1292
|
+
].sort((left, right)=>right.position - left.position))tr.delete(orphan.position, orphan.position + orphan.node.nodeSize);
|
|
1293
|
+
return tr.docChanged ? tr : null;
|
|
1073
1294
|
}
|
|
1074
|
-
function
|
|
1075
|
-
|
|
1295
|
+
function retainedDocumentBookmarkPairs(oldState, newState, transactions, boundaryNodeName) {
|
|
1296
|
+
const mapping = transactionMapping(transactions);
|
|
1297
|
+
const retained = new Set();
|
|
1298
|
+
const current = collectDocumentBookmarkPairs(newState.doc, boundaryNodeName).pairs;
|
|
1299
|
+
const currentById = new Map();
|
|
1300
|
+
for (const pair of current){
|
|
1301
|
+
const matches = currentById.get(pair.id) ?? [];
|
|
1302
|
+
matches.push(pair);
|
|
1303
|
+
currentById.set(pair.id, matches);
|
|
1304
|
+
}
|
|
1305
|
+
for (const previous of collectDocumentBookmarkPairs(oldState.doc, boundaryNodeName).pairs){
|
|
1306
|
+
const mappedFrom = mapping.mapResult(previous.from, 1);
|
|
1307
|
+
const mappedTo = mapping.mapResult(previous.to, 1);
|
|
1308
|
+
const exact = current.find((pair)=>pair.from === mappedFrom.pos && pair.to === mappedTo.pos && pair.id === previous.id);
|
|
1309
|
+
if (exact) {
|
|
1310
|
+
retained.add(pairPositionKey(exact));
|
|
1311
|
+
continue;
|
|
1312
|
+
}
|
|
1313
|
+
const sameIdentity = currentById.get(previous.id);
|
|
1314
|
+
if (sameIdentity?.length === 1) retained.add(pairPositionKey(sameIdentity[0]));
|
|
1315
|
+
}
|
|
1316
|
+
return retained;
|
|
1076
1317
|
}
|
|
1077
|
-
function
|
|
1078
|
-
const
|
|
1079
|
-
|
|
1318
|
+
function synchronizeInternalLinkMarks(state, tr, bookmarks, renames) {
|
|
1319
|
+
const linkType = state.schema.marks.link;
|
|
1320
|
+
if (!linkType) return;
|
|
1321
|
+
const names = new Set(bookmarks.map((bookmark)=>bookmark.name.toLowerCase()));
|
|
1322
|
+
state.doc.descendants((node, position)=>{
|
|
1323
|
+
if (!node.isText) return;
|
|
1324
|
+
const link = node.marks.find((mark)=>mark.type === linkType);
|
|
1325
|
+
if (!link) return;
|
|
1326
|
+
const href = 'string' == typeof link.attrs.href ? link.attrs.href : '';
|
|
1327
|
+
if (!href.startsWith('#')) return;
|
|
1328
|
+
const target = href.slice(1);
|
|
1329
|
+
const rename = renames.filter((candidate)=>position > candidate.from && position < candidate.to && target.toLowerCase() === candidate.previousName.toLowerCase()).sort((left, right)=>left.to - left.from - (right.to - right.from))[0];
|
|
1330
|
+
const nextHref = rename ? `#${rename.nextName}` : href;
|
|
1331
|
+
const nextTarget = nextHref.slice(1).toLowerCase();
|
|
1332
|
+
const nextClass = toggleClassToken(link.attrs.class, MISSING_LINK_CLASS, !names.has(nextTarget));
|
|
1333
|
+
if (nextHref === href && nextClass === normalizedClass(link.attrs.class)) return;
|
|
1334
|
+
replaceLinkMark(state, tr, node, position, link, {
|
|
1335
|
+
...link.attrs,
|
|
1336
|
+
href: nextHref,
|
|
1337
|
+
class: nextClass || null
|
|
1338
|
+
});
|
|
1339
|
+
});
|
|
1080
1340
|
}
|
|
1081
|
-
function
|
|
1082
|
-
|
|
1341
|
+
function replaceLinkMark(_state, tr, node, position, link, attributes) {
|
|
1342
|
+
tr.removeMark(position, position + node.nodeSize, link.type);
|
|
1343
|
+
tr.addMark(position, position + node.nodeSize, link.type.create(attributes));
|
|
1083
1344
|
}
|
|
1084
|
-
function
|
|
1085
|
-
const
|
|
1086
|
-
const
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1345
|
+
function collectDocumentBookmarkPairs(document1, boundaryNodeName) {
|
|
1346
|
+
const boundaries = documentBookmarkBoundaries(document1, boundaryNodeName);
|
|
1347
|
+
const open = new Map();
|
|
1348
|
+
const pairs = [];
|
|
1349
|
+
const orphans = [];
|
|
1350
|
+
for (const boundary of boundaries){
|
|
1351
|
+
const key = bookmarkBoundaryPairKey(boundary.node.attrs);
|
|
1352
|
+
if ('start' === boundary.kind) {
|
|
1353
|
+
const stack = open.get(key) ?? [];
|
|
1354
|
+
stack.push(boundary);
|
|
1355
|
+
open.set(key, stack);
|
|
1356
|
+
continue;
|
|
1357
|
+
}
|
|
1358
|
+
const stack = open.get(key);
|
|
1359
|
+
const start = stack?.pop();
|
|
1360
|
+
if (!start) {
|
|
1361
|
+
orphans.push(boundary);
|
|
1362
|
+
continue;
|
|
1092
1363
|
}
|
|
1364
|
+
pairs.push(bookmarkPair(start, boundary));
|
|
1093
1365
|
}
|
|
1094
|
-
|
|
1366
|
+
for (const stack of open.values())orphans.push(...stack);
|
|
1367
|
+
pairs.sort((left, right)=>left.from - right.from || left.to - right.to);
|
|
1368
|
+
return {
|
|
1369
|
+
pairs,
|
|
1370
|
+
orphans
|
|
1371
|
+
};
|
|
1095
1372
|
}
|
|
1096
|
-
function
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
return
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1373
|
+
function documentBookmarkBoundaries(document1, boundaryNodeName) {
|
|
1374
|
+
if (!boundaryNodeName) return [];
|
|
1375
|
+
const boundaries = [];
|
|
1376
|
+
document1.descendants((node, position)=>{
|
|
1377
|
+
if (node.type.name !== boundaryNodeName) return;
|
|
1378
|
+
boundaries.push({
|
|
1379
|
+
node,
|
|
1380
|
+
position,
|
|
1381
|
+
kind: documentBookmarkBoundaryKind(node.attrs.kind)
|
|
1382
|
+
});
|
|
1383
|
+
});
|
|
1384
|
+
return boundaries;
|
|
1107
1385
|
}
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
const count = clampInteger(columns?.count, customCount || DEFAULT_DOCUMENT_COLUMNS.count, 1, MAX_COLUMNS);
|
|
1118
|
-
const spacing = clampNumber(columns?.spacing, DEFAULT_DOCUMENT_COLUMNS.spacing, 0, 30);
|
|
1119
|
-
const normalized = {
|
|
1120
|
-
count,
|
|
1121
|
-
spacing: roundOne(spacing),
|
|
1122
|
-
separator: Boolean(columns?.separator)
|
|
1386
|
+
function bookmarkPair(start, end) {
|
|
1387
|
+
return {
|
|
1388
|
+
id: bookmarkInternalId(start.node.attrs.id),
|
|
1389
|
+
name: normalizeDocumentBookmarkName(start.node.attrs.name) ?? '',
|
|
1390
|
+
nativeId: normalizeDocumentBookmarkNativeId(start.node.attrs.nativeId) ?? -1,
|
|
1391
|
+
from: start.position,
|
|
1392
|
+
to: end.position,
|
|
1393
|
+
start,
|
|
1394
|
+
end
|
|
1123
1395
|
};
|
|
1124
|
-
if (count < 2 || !customCount) return normalized;
|
|
1125
|
-
const source = columns?.custom ?? [];
|
|
1126
|
-
const widths = normalizedPercentages(Array.from({
|
|
1127
|
-
length: count
|
|
1128
|
-
}, (_, index)=>finiteNumber(source[index]?.widthPercent, 100 / count)), 100, MIN_COLUMN_PERCENT);
|
|
1129
|
-
normalized.custom = Array.from({
|
|
1130
|
-
length: count
|
|
1131
|
-
}, (_, index)=>({
|
|
1132
|
-
widthPercent: widths[index],
|
|
1133
|
-
spacing: index === count - 1 ? 0 : roundOne(clampNumber(source[index]?.spacing, normalized.spacing, 0, 30))
|
|
1134
|
-
}));
|
|
1135
|
-
return normalized;
|
|
1136
|
-
}
|
|
1137
|
-
function serializeDocumentColumns(columns) {
|
|
1138
|
-
return JSON.stringify(normalizeDocumentColumns(columns));
|
|
1139
1396
|
}
|
|
1140
|
-
function
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1397
|
+
function bookmarkRegistryForDocument(document1, boundaryNodeName) {
|
|
1398
|
+
const registry = createBookmarkRegistry();
|
|
1399
|
+
for (const pair of collectDocumentBookmarkPairs(document1, boundaryNodeName).pairs){
|
|
1400
|
+
const identity = bookmarkIdentity(pair);
|
|
1401
|
+
if (identity) reserveBookmarkIdentity(identity, registry);
|
|
1402
|
+
}
|
|
1403
|
+
return registry;
|
|
1146
1404
|
}
|
|
1147
|
-
function
|
|
1148
|
-
const
|
|
1149
|
-
if (
|
|
1150
|
-
|
|
1151
|
-
|
|
1405
|
+
function uniqueDocumentBookmarkIdentity(source, registry) {
|
|
1406
|
+
const preferred = bookmarkIdentity(source);
|
|
1407
|
+
if (preferred && !bookmarkIdentityConflicts(preferred, registry)) {
|
|
1408
|
+
reserveBookmarkIdentity(preferred, registry);
|
|
1409
|
+
return preferred;
|
|
1410
|
+
}
|
|
1411
|
+
const baseName = normalizeDocumentBookmarkName(source.name) ?? 'Bookmark';
|
|
1412
|
+
const identity = {
|
|
1413
|
+
id: createUniqueBookmarkId(registry.ids),
|
|
1414
|
+
name: uniqueBookmarkName(baseName, registry.names),
|
|
1415
|
+
nativeId: nextBookmarkNativeId(registry.nativeIds)
|
|
1152
1416
|
};
|
|
1153
|
-
|
|
1154
|
-
return
|
|
1155
|
-
...normalized,
|
|
1156
|
-
custom: Array.from({
|
|
1157
|
-
length: normalized.count
|
|
1158
|
-
}, (_, index)=>({
|
|
1159
|
-
widthPercent: 100 / normalized.count,
|
|
1160
|
-
spacing: index === normalized.count - 1 ? 0 : normalized.spacing
|
|
1161
|
-
}))
|
|
1162
|
-
});
|
|
1417
|
+
reserveBookmarkIdentity(identity, registry);
|
|
1418
|
+
return identity;
|
|
1163
1419
|
}
|
|
1164
|
-
function
|
|
1165
|
-
const
|
|
1166
|
-
|
|
1167
|
-
const
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1420
|
+
function bookmarkIdentity(source) {
|
|
1421
|
+
const id = bookmarkInternalId(source.id);
|
|
1422
|
+
const name = normalizeDocumentBookmarkName(source.name);
|
|
1423
|
+
const nativeId = normalizeDocumentBookmarkNativeId(source.nativeId);
|
|
1424
|
+
return id && name && null !== nativeId ? {
|
|
1425
|
+
id,
|
|
1426
|
+
name,
|
|
1427
|
+
nativeId
|
|
1428
|
+
} : null;
|
|
1429
|
+
}
|
|
1430
|
+
function bookmarkIdentityConflicts(identity, registry) {
|
|
1431
|
+
return registry.ids.has(identity.id) || registry.names.has(identity.name.toLowerCase()) || registry.nativeIds.has(identity.nativeId);
|
|
1432
|
+
}
|
|
1433
|
+
function reserveBookmarkIdentity(identity, registry) {
|
|
1434
|
+
registry.ids.add(identity.id);
|
|
1435
|
+
registry.names.add(identity.name.toLowerCase());
|
|
1436
|
+
registry.nativeIds.add(identity.nativeId);
|
|
1437
|
+
}
|
|
1438
|
+
function createBookmarkRegistry() {
|
|
1178
1439
|
return {
|
|
1179
|
-
|
|
1180
|
-
|
|
1440
|
+
ids: new Set(),
|
|
1441
|
+
names: new Set(),
|
|
1442
|
+
nativeIds: new Set()
|
|
1181
1443
|
};
|
|
1182
1444
|
}
|
|
1183
|
-
function
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
let remainingTotal = total;
|
|
1188
|
-
while(remaining.size){
|
|
1189
|
-
const sourceTotal = Array.from(remaining).reduce((sum, index)=>sum + Math.max(0.001, finiteNumber(values[index], 1)), 0);
|
|
1190
|
-
const belowMinimum = Array.from(remaining).filter((index)=>Math.max(0.001, finiteNumber(values[index], 1)) / sourceTotal * remainingTotal < minimum);
|
|
1191
|
-
if (!belowMinimum.length) {
|
|
1192
|
-
for (const index of remaining)result[index] = Math.max(0.001, finiteNumber(values[index], 1)) / sourceTotal * remainingTotal;
|
|
1193
|
-
break;
|
|
1194
|
-
}
|
|
1195
|
-
for (const index of belowMinimum){
|
|
1196
|
-
result[index] = minimum;
|
|
1197
|
-
remaining.delete(index);
|
|
1198
|
-
remainingTotal -= minimum;
|
|
1199
|
-
}
|
|
1445
|
+
function createUniqueBookmarkId(ids) {
|
|
1446
|
+
for(let attempt = 0; attempt < 8; attempt += 1){
|
|
1447
|
+
const id = createWorkId('bookmark');
|
|
1448
|
+
if (!ids.has(id)) return id;
|
|
1200
1449
|
}
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
return rounded;
|
|
1205
|
-
}
|
|
1206
|
-
function clampInteger(value, fallback, minimum, maximum) {
|
|
1207
|
-
return Math.min(maximum, Math.max(minimum, Math.round(finiteNumber(value, fallback))));
|
|
1450
|
+
let suffix = 1;
|
|
1451
|
+
while(ids.has(`bookmark-${suffix}`))suffix += 1;
|
|
1452
|
+
return `bookmark-${suffix}`;
|
|
1208
1453
|
}
|
|
1209
|
-
function
|
|
1210
|
-
|
|
1454
|
+
function uniqueBookmarkName(base, names) {
|
|
1455
|
+
if (!names.has(base.toLowerCase())) return base;
|
|
1456
|
+
let suffix = 2;
|
|
1457
|
+
while(suffix <= MAX_BOOKMARK_NATIVE_ID){
|
|
1458
|
+
const ending = `_${suffix}`;
|
|
1459
|
+
const prefix = Array.from(base).slice(0, MAX_BOOKMARK_NAME_LENGTH - ending.length).join('');
|
|
1460
|
+
const candidate = `${prefix}${ending}`;
|
|
1461
|
+
if (!names.has(candidate.toLowerCase())) return candidate;
|
|
1462
|
+
suffix += 1;
|
|
1463
|
+
}
|
|
1464
|
+
throw new Error('No unique Word bookmark name is available.');
|
|
1211
1465
|
}
|
|
1212
|
-
function
|
|
1213
|
-
|
|
1466
|
+
function nextBookmarkNativeId(ids) {
|
|
1467
|
+
for(let id = 0; id <= MAX_BOOKMARK_NATIVE_ID; id += 1)if (!ids.has(id)) return id;
|
|
1468
|
+
throw new Error('No unique Word bookmark identifier is available.');
|
|
1214
1469
|
}
|
|
1215
|
-
function
|
|
1216
|
-
return
|
|
1470
|
+
function sameBookmarkIdentity(source, identity) {
|
|
1471
|
+
return bookmarkInternalId(source.id) === identity.id && normalizeDocumentBookmarkName(source.name) === identity.name && normalizeDocumentBookmarkNativeId(source.nativeId) === identity.nativeId;
|
|
1217
1472
|
}
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
page: 'PAGE',
|
|
1221
|
-
numPages: 'NUMPAGES',
|
|
1222
|
-
section: 'SECTION',
|
|
1223
|
-
sectionPages: 'SECTIONPAGES',
|
|
1224
|
-
date: 'DATE \\@ "yyyy年M月d日"',
|
|
1225
|
-
time: 'TIME \\@ "HH:mm"'
|
|
1226
|
-
};
|
|
1227
|
-
const FIELD_LABELS = {
|
|
1228
|
-
page: '当前页码',
|
|
1229
|
-
numPages: '总页数',
|
|
1230
|
-
section: '当前节号',
|
|
1231
|
-
sectionPages: '本节页数',
|
|
1232
|
-
date: '当前日期',
|
|
1233
|
-
time: '当前时间'
|
|
1234
|
-
};
|
|
1235
|
-
function documentFieldKind(value) {
|
|
1236
|
-
if ('page' === value || 'numPages' === value || 'section' === value || 'sectionPages' === value || 'date' === value || 'time' === value) return value;
|
|
1237
|
-
return null;
|
|
1473
|
+
function bookmarkInternalId(value) {
|
|
1474
|
+
return 'string' == typeof value ? value.trim() : '';
|
|
1238
1475
|
}
|
|
1239
|
-
function
|
|
1240
|
-
const
|
|
1241
|
-
if (
|
|
1242
|
-
|
|
1243
|
-
if ('SECTION' === command) return 'section';
|
|
1244
|
-
if ('SECTIONPAGES' === command) return 'sectionPages';
|
|
1245
|
-
if ('DATE' === command) return 'date';
|
|
1246
|
-
if ('TIME' === command) return 'time';
|
|
1247
|
-
return null;
|
|
1476
|
+
function bookmarkBoundaryPairKey(attributes) {
|
|
1477
|
+
const id = bookmarkInternalId(attributes.id);
|
|
1478
|
+
if (id) return `id:${id}`;
|
|
1479
|
+
return `legacy:${String(attributes.name ?? '')}:${String(attributes.nativeId ?? '')}`;
|
|
1248
1480
|
}
|
|
1249
|
-
function
|
|
1250
|
-
return
|
|
1481
|
+
function documentBookmarkBoundaryKind(value) {
|
|
1482
|
+
return 'end' === value ? 'end' : 'start';
|
|
1251
1483
|
}
|
|
1252
|
-
function
|
|
1253
|
-
|
|
1484
|
+
function transactionMapping(transactions) {
|
|
1485
|
+
const mapping = new Mapping();
|
|
1486
|
+
for (const transaction of transactions)mapping.appendMapping(transaction.mapping);
|
|
1487
|
+
return mapping;
|
|
1254
1488
|
}
|
|
1255
|
-
function
|
|
1256
|
-
|
|
1257
|
-
if ('numPages' === kind) return String(work_document_fields_positiveInteger(context.totalPages));
|
|
1258
|
-
if ('section' === kind) return String(work_document_fields_positiveInteger(context.sectionNumber));
|
|
1259
|
-
if ('sectionPages' === kind) return String(work_document_fields_positiveInteger(context.sectionPages));
|
|
1260
|
-
const now = validDate(context.now) ?? new Date();
|
|
1261
|
-
const format = dateFormatSwitch(instruction) ?? ('date' === kind ? 'yyyy年M月d日' : 'HH:mm');
|
|
1262
|
-
const display = formatWordDate(now, format);
|
|
1263
|
-
return display || cachedValue || documentFieldLabel(kind);
|
|
1489
|
+
function pairPositionKey(pair) {
|
|
1490
|
+
return `${pair.from}:${pair.to}`;
|
|
1264
1491
|
}
|
|
1265
|
-
function
|
|
1266
|
-
const
|
|
1267
|
-
const
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
const
|
|
1271
|
-
if (
|
|
1272
|
-
|
|
1492
|
+
function collectDomBookmarkPairs(boundaries) {
|
|
1493
|
+
const open = new Map();
|
|
1494
|
+
const pairs = [];
|
|
1495
|
+
const orphans = [];
|
|
1496
|
+
for (const boundary of boundaries){
|
|
1497
|
+
const key = domBookmarkPairKey(boundary);
|
|
1498
|
+
if ('start' === documentBookmarkBoundaryKind(boundary.dataset.bookmarkKind)) {
|
|
1499
|
+
const stack = open.get(key) ?? [];
|
|
1500
|
+
stack.push(boundary);
|
|
1501
|
+
open.set(key, stack);
|
|
1273
1502
|
continue;
|
|
1274
1503
|
}
|
|
1275
|
-
const
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
const document1 = new DOMParser().parseFromString(normalizeDocumentFieldsHtml(source), 'text/html');
|
|
1288
|
-
for (const element of Array.from(document1.body.querySelectorAll(FIELD_SELECTOR))){
|
|
1289
|
-
const kind = documentFieldKind(element.dataset.fieldKind);
|
|
1290
|
-
if (!kind) continue;
|
|
1291
|
-
const display = documentFieldDisplay(kind, context, element.dataset.fieldInstruction, element.dataset.fieldDisplay);
|
|
1292
|
-
element.dataset.fieldDisplay = display;
|
|
1293
|
-
element.textContent = display;
|
|
1294
|
-
}
|
|
1295
|
-
return document1.body.innerHTML;
|
|
1296
|
-
}
|
|
1297
|
-
function uniqueFieldId(source, index, usedIds) {
|
|
1298
|
-
const candidate = source?.trim();
|
|
1299
|
-
if (candidate && !usedIds.has(candidate)) {
|
|
1300
|
-
usedIds.add(candidate);
|
|
1301
|
-
return candidate;
|
|
1504
|
+
const start = open.get(key)?.pop();
|
|
1505
|
+
if (!start) {
|
|
1506
|
+
orphans.push(boundary);
|
|
1507
|
+
continue;
|
|
1508
|
+
}
|
|
1509
|
+
pairs.push({
|
|
1510
|
+
id: start.dataset.bookmarkId,
|
|
1511
|
+
name: start.dataset.bookmarkName,
|
|
1512
|
+
nativeId: normalizeDocumentBookmarkNativeId(start.dataset.officeBookmarkId) ?? void 0,
|
|
1513
|
+
start,
|
|
1514
|
+
end: boundary
|
|
1515
|
+
});
|
|
1302
1516
|
}
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
return id;
|
|
1308
|
-
}
|
|
1309
|
-
function dateFormatSwitch(instruction) {
|
|
1310
|
-
return /\\@\s+"([^"]+)"/i.exec(instruction)?.[1] ?? null;
|
|
1311
|
-
}
|
|
1312
|
-
function formatWordDate(date, format) {
|
|
1313
|
-
const hour12 = date.getHours() % 12 || 12;
|
|
1314
|
-
const replacements = {
|
|
1315
|
-
'AM/PM': date.getHours() < 12 ? 'AM' : 'PM',
|
|
1316
|
-
'am/pm': date.getHours() < 12 ? 'am' : 'pm',
|
|
1317
|
-
yyyy: String(date.getFullYear()).padStart(4, '0'),
|
|
1318
|
-
yy: String(date.getFullYear() % 100).padStart(2, '0'),
|
|
1319
|
-
MMMM: new Intl.DateTimeFormat('zh-CN', {
|
|
1320
|
-
month: 'long'
|
|
1321
|
-
}).format(date),
|
|
1322
|
-
MMM: new Intl.DateTimeFormat('zh-CN', {
|
|
1323
|
-
month: 'short'
|
|
1324
|
-
}).format(date),
|
|
1325
|
-
MM: String(date.getMonth() + 1).padStart(2, '0'),
|
|
1326
|
-
M: String(date.getMonth() + 1),
|
|
1327
|
-
dddd: new Intl.DateTimeFormat('zh-CN', {
|
|
1328
|
-
weekday: 'long'
|
|
1329
|
-
}).format(date),
|
|
1330
|
-
ddd: new Intl.DateTimeFormat('zh-CN', {
|
|
1331
|
-
weekday: 'short'
|
|
1332
|
-
}).format(date),
|
|
1333
|
-
dd: String(date.getDate()).padStart(2, '0'),
|
|
1334
|
-
d: String(date.getDate()),
|
|
1335
|
-
HH: String(date.getHours()).padStart(2, '0'),
|
|
1336
|
-
H: String(date.getHours()),
|
|
1337
|
-
hh: String(hour12).padStart(2, '0'),
|
|
1338
|
-
h: String(hour12),
|
|
1339
|
-
mm: String(date.getMinutes()).padStart(2, '0'),
|
|
1340
|
-
m: String(date.getMinutes()),
|
|
1341
|
-
ss: String(date.getSeconds()).padStart(2, '0'),
|
|
1342
|
-
s: String(date.getSeconds())
|
|
1517
|
+
for (const stack of open.values())orphans.push(...stack);
|
|
1518
|
+
return {
|
|
1519
|
+
pairs,
|
|
1520
|
+
orphans
|
|
1343
1521
|
};
|
|
1344
|
-
return format.replace(/AM\/PM|am\/pm|yyyy|MMMM|dddd|MMM|ddd|yy|MM|dd|HH|hh|mm|ss|M|d|H|h|m|s/g, (token)=>replacements[token] ?? token);
|
|
1345
|
-
}
|
|
1346
|
-
function work_document_fields_positiveInteger(value) {
|
|
1347
|
-
return Number.isSafeInteger(value) && value > 0 ? value : 1;
|
|
1348
1522
|
}
|
|
1349
|
-
function
|
|
1350
|
-
|
|
1523
|
+
function domBookmarkPairKey(element) {
|
|
1524
|
+
const id = element.dataset.bookmarkId?.trim();
|
|
1525
|
+
return id ? `id:${id}` : `legacy:${element.dataset.bookmarkName ?? ''}:${element.dataset.officeBookmarkId ?? ''}`;
|
|
1351
1526
|
}
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
left: validMargin(content.margins?.left, DEFAULT_DOCUMENT_MARGINS.left)
|
|
1364
|
-
};
|
|
1527
|
+
function applyBookmarkIdentityToElement(element, identity, kind) {
|
|
1528
|
+
element.dataset.documentBookmarkBoundary = 'true';
|
|
1529
|
+
element.dataset.bookmarkKind = kind;
|
|
1530
|
+
element.dataset.bookmarkId = identity.id;
|
|
1531
|
+
element.dataset.bookmarkName = identity.name;
|
|
1532
|
+
element.dataset.officeBookmarkId = String(identity.nativeId);
|
|
1533
|
+
element.classList.add('work-document-bookmark-boundary', kind);
|
|
1534
|
+
element.contentEditable = 'false';
|
|
1535
|
+
element.setAttribute('aria-hidden', 'true');
|
|
1536
|
+
if ('start' === kind) element.id = identity.name;
|
|
1537
|
+
else element.removeAttribute('id');
|
|
1365
1538
|
}
|
|
1366
|
-
function
|
|
1367
|
-
|
|
1539
|
+
function synchronizeDomInternalLinks(root, names) {
|
|
1540
|
+
for (const link of root.querySelectorAll('a[href^="#"]')){
|
|
1541
|
+
const target = (link.getAttribute('href') ?? '').slice(1).toLowerCase();
|
|
1542
|
+
link.classList.toggle(MISSING_LINK_CLASS, !names.has(target));
|
|
1543
|
+
if (!link.className) link.removeAttribute('class');
|
|
1544
|
+
}
|
|
1368
1545
|
}
|
|
1369
|
-
function
|
|
1370
|
-
|
|
1546
|
+
function synchronizeDocumentPageReferenceNodes(state, tr, bookmarks, renames) {
|
|
1547
|
+
state.doc.descendants((node, position)=>{
|
|
1548
|
+
if ('documentField' !== node.type.name) return;
|
|
1549
|
+
const kind = 'pageReference' === node.attrs.kind ? 'pageReference' : docxDocumentFieldKind(work_document_bookmarks_stringAttribute(node.attrs.instruction));
|
|
1550
|
+
if ('pageReference' !== kind) return;
|
|
1551
|
+
let targetId = work_document_bookmarks_stringAttribute(node.attrs.targetId);
|
|
1552
|
+
let targetName = work_document_bookmarks_stringAttribute(node.attrs.targetName) || docxDocumentFieldTarget(work_document_bookmarks_stringAttribute(node.attrs.instruction)) || '';
|
|
1553
|
+
const rename = renames.filter((candidate)=>position > candidate.from && position < candidate.to && (targetId && targetId === candidate.previousId || targetName && targetName.toLowerCase() === candidate.previousName.toLowerCase())).sort((left, right)=>left.to - left.from - (right.to - right.from))[0];
|
|
1554
|
+
if (rename) {
|
|
1555
|
+
targetId = rename.nextId;
|
|
1556
|
+
targetName = rename.nextName;
|
|
1557
|
+
}
|
|
1558
|
+
const target = bookmarks.find((bookmark)=>targetId && bookmark.id === targetId || targetName && bookmark.name.toLowerCase() === targetName.toLowerCase()) ?? null;
|
|
1559
|
+
const nextTargetId = target?.id ?? targetId;
|
|
1560
|
+
const nextTargetName = target?.name ?? targetName;
|
|
1561
|
+
const instruction = target ? documentPageReferenceInstruction(nextTargetName, work_document_bookmarks_stringAttribute(node.attrs.instruction)) : work_document_bookmarks_stringAttribute(node.attrs.instruction);
|
|
1562
|
+
const orphaned = !target;
|
|
1563
|
+
if (node.attrs.targetId === nextTargetId && node.attrs.targetName === nextTargetName && node.attrs.instruction === instruction && node.attrs.orphaned === orphaned) return;
|
|
1564
|
+
tr.setNodeMarkup(position, void 0, {
|
|
1565
|
+
...node.attrs,
|
|
1566
|
+
targetId: nextTargetId,
|
|
1567
|
+
targetName: nextTargetName,
|
|
1568
|
+
instruction,
|
|
1569
|
+
orphaned
|
|
1570
|
+
});
|
|
1571
|
+
});
|
|
1371
1572
|
}
|
|
1372
|
-
function
|
|
1373
|
-
|
|
1573
|
+
function retargetDomPageReferences(root, start, end, previous, next) {
|
|
1574
|
+
const range = root.ownerDocument.createRange();
|
|
1575
|
+
range.setStartAfter(start);
|
|
1576
|
+
range.setEndBefore(end);
|
|
1577
|
+
for (const field of root.querySelectorAll('span[data-document-field][data-field-kind="pageReference"]')){
|
|
1578
|
+
if (!range.intersectsNode(field)) continue;
|
|
1579
|
+
const id = field.dataset.fieldTargetId?.trim() ?? '';
|
|
1580
|
+
const name = field.dataset.fieldTargetName?.trim() ?? '';
|
|
1581
|
+
if (id === previous.id || name.toLowerCase() === previous.name.toLowerCase()) {
|
|
1582
|
+
field.dataset.fieldTargetId = next.id;
|
|
1583
|
+
field.dataset.fieldTargetName = next.name;
|
|
1584
|
+
field.dataset.fieldInstruction = documentPageReferenceInstruction(next.name, field.dataset.fieldInstruction);
|
|
1585
|
+
delete field.dataset.fieldOrphaned;
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1374
1588
|
}
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
const LEGACY_FNV_OFFSET = 0x811c9dc5;
|
|
1378
|
-
function createDocumentHtmlFingerprintSegment(source, from = 0, to = source.length) {
|
|
1379
|
-
if (!Number.isSafeInteger(from) || !Number.isSafeInteger(to) || from < 0 || to < from || to > source.length) throw new RangeError('The document HTML fingerprint range is invalid.');
|
|
1380
|
-
let hash = 0;
|
|
1381
|
-
for(let index = from; index < to; index += 1)hash = Math.imul(hash, DOCUMENT_HTML_HASH_BASE) + source.charCodeAt(index) >>> 0;
|
|
1382
|
-
const length = to - from;
|
|
1383
|
-
return {
|
|
1384
|
-
hash,
|
|
1385
|
-
length,
|
|
1386
|
-
power: documentHtmlHashPower(length)
|
|
1387
|
-
};
|
|
1589
|
+
function normalizedClass(value) {
|
|
1590
|
+
return 'string' == typeof value ? value.trim().split(/\s+/).filter(Boolean).join(' ') : '';
|
|
1388
1591
|
}
|
|
1389
|
-
function
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
};
|
|
1395
|
-
for (const segment of segments)combined = {
|
|
1396
|
-
hash: Math.imul(combined.hash, segment.power) + segment.hash >>> 0,
|
|
1397
|
-
length: combined.length + segment.length,
|
|
1398
|
-
power: Math.imul(combined.power, segment.power) >>> 0
|
|
1399
|
-
};
|
|
1400
|
-
return combined;
|
|
1592
|
+
function toggleClassToken(value, token, enabled) {
|
|
1593
|
+
const tokens = new Set(normalizedClass(value).split(' ').filter(Boolean));
|
|
1594
|
+
if (enabled) tokens.add(token);
|
|
1595
|
+
else tokens.delete(token);
|
|
1596
|
+
return Array.from(tokens).join(' ');
|
|
1401
1597
|
}
|
|
1402
|
-
function
|
|
1403
|
-
return
|
|
1598
|
+
function work_document_bookmarks_stringAttribute(value) {
|
|
1599
|
+
return 'string' == typeof value ? value.trim() : '';
|
|
1404
1600
|
}
|
|
1405
|
-
|
|
1406
|
-
|
|
1601
|
+
const CAPTION_SELECTOR = 'figcaption[data-document-caption]';
|
|
1602
|
+
const REFERENCE_SELECTOR = 'span[data-document-cross-reference]';
|
|
1603
|
+
function normalizeDocumentCaptionsHtml(source) {
|
|
1604
|
+
const document1 = new DOMParser().parseFromString(source, 'text/html');
|
|
1605
|
+
const targets = normalizeCaptions(document1);
|
|
1606
|
+
normalizeReferences(document1, new Map(targets.map((target)=>[
|
|
1607
|
+
target.id,
|
|
1608
|
+
target
|
|
1609
|
+
])));
|
|
1610
|
+
return document1.body.innerHTML;
|
|
1407
1611
|
}
|
|
1408
|
-
function
|
|
1409
|
-
return
|
|
1612
|
+
function documentCaptionKind(value) {
|
|
1613
|
+
return 'figure' === value || 'table' === value ? value : null;
|
|
1410
1614
|
}
|
|
1411
|
-
function
|
|
1412
|
-
|
|
1413
|
-
for(let index = 0; index < html.length; index += 1){
|
|
1414
|
-
hash ^= html.charCodeAt(index);
|
|
1415
|
-
hash = Math.imul(hash, DOCUMENT_HTML_HASH_BASE);
|
|
1416
|
-
}
|
|
1417
|
-
return `${html.length.toString(36)}:${(hash >>> 0).toString(36)}`;
|
|
1615
|
+
function documentCaptionLabel(kind) {
|
|
1616
|
+
return 'table' === kind ? '表' : '图';
|
|
1418
1617
|
}
|
|
1419
|
-
function
|
|
1420
|
-
|
|
1421
|
-
let factor = DOCUMENT_HTML_HASH_BASE;
|
|
1422
|
-
let power = 1;
|
|
1423
|
-
while(exponent > 0){
|
|
1424
|
-
if (exponent % 2 === 1) power = Math.imul(power, factor) >>> 0;
|
|
1425
|
-
factor = Math.imul(factor, factor) >>> 0;
|
|
1426
|
-
exponent = Math.floor(exponent / 2);
|
|
1427
|
-
}
|
|
1428
|
-
return power;
|
|
1618
|
+
function documentCaptionDisplay(kind, number) {
|
|
1619
|
+
return `${documentCaptionLabel(kind)} ${work_document_captions_positiveInteger(number)}`;
|
|
1429
1620
|
}
|
|
1430
|
-
|
|
1431
|
-
const
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
if (1 !== content.length || tablePart) return null;
|
|
1453
|
-
tablePart = scanned.tablePart;
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
1456
|
-
const range = {
|
|
1457
|
-
from,
|
|
1621
|
+
function normalizeCaptions(document1) {
|
|
1622
|
+
const counters = {
|
|
1623
|
+
figure: 0,
|
|
1624
|
+
table: 0
|
|
1625
|
+
};
|
|
1626
|
+
const usedIds = new Set();
|
|
1627
|
+
return Array.from(document1.body.querySelectorAll(CAPTION_SELECTOR)).map((element, index)=>{
|
|
1628
|
+
const kind = documentCaptionKind(element.dataset.captionKind) ?? 'figure';
|
|
1629
|
+
counters[kind] += 1;
|
|
1630
|
+
const number = counters[kind];
|
|
1631
|
+
const id = uniqueCaptionId(element.dataset.captionId, kind, index + 1, usedIds);
|
|
1632
|
+
const label = documentCaptionLabel(kind);
|
|
1633
|
+
element.dataset.documentCaption = 'true';
|
|
1634
|
+
element.dataset.captionId = id;
|
|
1635
|
+
element.dataset.captionKind = kind;
|
|
1636
|
+
element.dataset.captionNumber = String(number);
|
|
1637
|
+
element.dataset.captionLabel = label;
|
|
1638
|
+
element.classList.add('work-document-caption');
|
|
1639
|
+
const title = element.textContent?.replace(/\s+/g, ' ').trim() ?? '';
|
|
1640
|
+
const display = documentCaptionDisplay(kind, number);
|
|
1641
|
+
element.setAttribute('aria-label', title ? `${display} ${title}` : display);
|
|
1642
|
+
return {
|
|
1458
1643
|
id,
|
|
1459
|
-
|
|
1460
|
-
|
|
1644
|
+
kind,
|
|
1645
|
+
number,
|
|
1646
|
+
label,
|
|
1647
|
+
title,
|
|
1648
|
+
display
|
|
1461
1649
|
};
|
|
1462
|
-
|
|
1463
|
-
ranges.set(id, range);
|
|
1464
|
-
}
|
|
1465
|
-
if (cursor !== html.length - SECTION_CLOSE.length) return null;
|
|
1466
|
-
return {
|
|
1467
|
-
html,
|
|
1468
|
-
orderedRanges,
|
|
1469
|
-
ranges
|
|
1470
|
-
};
|
|
1650
|
+
});
|
|
1471
1651
|
}
|
|
1472
|
-
function
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
if (
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1652
|
+
function normalizeReferences(document1, targets) {
|
|
1653
|
+
for (const element of Array.from(document1.body.querySelectorAll(REFERENCE_SELECTOR))){
|
|
1654
|
+
if ('bookmark' === element.dataset.referenceTargetType) continue;
|
|
1655
|
+
const id = element.dataset.referenceTargetId?.trim() ?? '';
|
|
1656
|
+
const target = targets.get(id);
|
|
1657
|
+
element.dataset.documentCrossReference = 'true';
|
|
1658
|
+
element.dataset.referenceTargetId = id;
|
|
1659
|
+
element.classList.add('work-document-cross-reference');
|
|
1660
|
+
if (!target) {
|
|
1661
|
+
element.dataset.referenceOrphaned = 'true';
|
|
1662
|
+
element.textContent = '引用缺失';
|
|
1663
|
+
continue;
|
|
1484
1664
|
}
|
|
1665
|
+
delete element.dataset.referenceOrphaned;
|
|
1666
|
+
element.dataset.captionKind = target.kind;
|
|
1667
|
+
element.dataset.captionNumber = String(target.number);
|
|
1668
|
+
element.dataset.captionLabel = target.label;
|
|
1669
|
+
element.textContent = target.display;
|
|
1485
1670
|
}
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
const replacement = replacements.get(range.id);
|
|
1493
|
-
const nextLength = replacement?.length ?? previousLength;
|
|
1494
|
-
range.from = previousFrom + offset;
|
|
1495
|
-
range.to = range.from + nextLength;
|
|
1496
|
-
offset += nextLength - previousLength;
|
|
1671
|
+
}
|
|
1672
|
+
function uniqueCaptionId(source, kind, index, usedIds) {
|
|
1673
|
+
const candidate = source?.trim();
|
|
1674
|
+
if (candidate && !usedIds.has(candidate)) {
|
|
1675
|
+
usedIds.add(candidate);
|
|
1676
|
+
return candidate;
|
|
1497
1677
|
}
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1678
|
+
let suffix = index;
|
|
1679
|
+
while(usedIds.has(`document-${kind}-caption-${suffix}`))suffix += 1;
|
|
1680
|
+
const id = `document-${kind}-caption-${suffix}`;
|
|
1681
|
+
usedIds.add(id);
|
|
1682
|
+
return id;
|
|
1683
|
+
}
|
|
1684
|
+
function work_document_captions_positiveInteger(value) {
|
|
1685
|
+
const number = Number(value);
|
|
1686
|
+
return Number.isSafeInteger(number) && number > 0 ? number : 1;
|
|
1687
|
+
}
|
|
1688
|
+
const CITATION_SELECTOR = 'span[data-document-citation]';
|
|
1689
|
+
const BIBLIOGRAPHY_SELECTOR = 'section[data-document-bibliography]';
|
|
1690
|
+
const STYLE_DETAILS = {
|
|
1691
|
+
apa: {
|
|
1692
|
+
name: 'APA',
|
|
1693
|
+
selectedStyle: '\\APASixthEditionOfficeOnline.xsl'
|
|
1694
|
+
},
|
|
1695
|
+
mla: {
|
|
1696
|
+
name: 'MLA',
|
|
1697
|
+
selectedStyle: '\\MLASeventhEditionOfficeOnline.xsl'
|
|
1698
|
+
},
|
|
1699
|
+
chicago: {
|
|
1700
|
+
name: 'Chicago',
|
|
1701
|
+
selectedStyle: '\\CHICAGO.XSL'
|
|
1702
|
+
},
|
|
1703
|
+
ieee: {
|
|
1704
|
+
name: 'IEEE',
|
|
1705
|
+
selectedStyle: '\\IEEE.XSL'
|
|
1706
|
+
}
|
|
1707
|
+
};
|
|
1708
|
+
function createDocumentBibliography(style = 'apa') {
|
|
1709
|
+
return {
|
|
1710
|
+
style,
|
|
1711
|
+
styleName: STYLE_DETAILS[style].name,
|
|
1712
|
+
selectedStyle: STYLE_DETAILS[style].selectedStyle,
|
|
1713
|
+
sources: []
|
|
1714
|
+
};
|
|
1509
1715
|
}
|
|
1510
|
-
function
|
|
1511
|
-
|
|
1716
|
+
function documentCitationStyle(value) {
|
|
1717
|
+
if ('mla' === value || 'chicago' === value || 'ieee' === value) return value;
|
|
1718
|
+
return 'apa';
|
|
1512
1719
|
}
|
|
1513
|
-
function
|
|
1514
|
-
|
|
1515
|
-
const bodyOpen = html.indexOf(TABLE_BODY_OPEN);
|
|
1516
|
-
const bodyClose = html.lastIndexOf('</tbody>');
|
|
1517
|
-
if (bodyOpen < 0 || bodyClose < bodyOpen) return null;
|
|
1518
|
-
const rowsFrom = bodyOpen + TABLE_BODY_OPEN.length;
|
|
1519
|
-
if ('first' === tablePart) return html.slice(0, bodyClose);
|
|
1520
|
-
if ('middle' === tablePart) return html.slice(rowsFrom, bodyClose);
|
|
1521
|
-
return html.slice(rowsFrom);
|
|
1720
|
+
function documentCitationStyleDetails(style) {
|
|
1721
|
+
return STYLE_DETAILS[style];
|
|
1522
1722
|
}
|
|
1523
|
-
function
|
|
1524
|
-
const
|
|
1525
|
-
|
|
1526
|
-
|
|
1723
|
+
function documentCitationTagsFromInstruction(instruction) {
|
|
1724
|
+
const primary = /^\s*CITATION\s+(?:"([^"]+)"|([^\s\\]+))/i.exec(instruction);
|
|
1725
|
+
if (!primary) return [];
|
|
1726
|
+
const tags = [
|
|
1727
|
+
primary[1] || primary[2]
|
|
1527
1728
|
];
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
if ('documentChunk' === node.type && node.attrs?.windowContainer !== true) {
|
|
1532
|
-
chunks.push(node);
|
|
1533
|
-
continue;
|
|
1534
|
-
}
|
|
1535
|
-
for(let index = (node.content?.length ?? 0) - 1; index >= 0; index -= 1){
|
|
1536
|
-
const child = node.content?.[index];
|
|
1537
|
-
if (child) pending.push(child);
|
|
1538
|
-
}
|
|
1539
|
-
}
|
|
1540
|
-
return chunks;
|
|
1729
|
+
const additional = /\\m\s+(?:"([^"]+)"|([^\s\\]+))/gi;
|
|
1730
|
+
for (const match of instruction.matchAll(additional))tags.push(match[1] || match[2]);
|
|
1731
|
+
return uniqueCitationTags(tags);
|
|
1541
1732
|
}
|
|
1542
|
-
function
|
|
1543
|
-
const
|
|
1544
|
-
if (
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
const segment = ranges.get(range.id);
|
|
1556
|
-
if (!segment) throw new Error('The lazy HTML fingerprint segment is missing.');
|
|
1557
|
-
return segment;
|
|
1558
|
-
}),
|
|
1559
|
-
suffix
|
|
1560
|
-
])),
|
|
1561
|
-
prefix,
|
|
1562
|
-
ranges,
|
|
1563
|
-
suffix
|
|
1564
|
-
};
|
|
1565
|
-
projectionFingerprints.set(projection, state);
|
|
1566
|
-
return state;
|
|
1733
|
+
function documentCitationInstruction(tags) {
|
|
1734
|
+
const normalized = uniqueCitationTags(tags);
|
|
1735
|
+
if (!normalized.length) return '';
|
|
1736
|
+
return [
|
|
1737
|
+
'CITATION',
|
|
1738
|
+
citationTagInstructionValue(normalized[0]),
|
|
1739
|
+
...normalized.slice(1).flatMap((tag)=>[
|
|
1740
|
+
'\\m',
|
|
1741
|
+
citationTagInstructionValue(tag)
|
|
1742
|
+
]),
|
|
1743
|
+
'\\l',
|
|
1744
|
+
'2052'
|
|
1745
|
+
].join(' ');
|
|
1567
1746
|
}
|
|
1568
|
-
function
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
if (!
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1747
|
+
function renameDocumentCitationTagInInstruction(instruction, previousTag, nextTag) {
|
|
1748
|
+
return instruction.replace(/(^\s*CITATION\s+|\\m\s+)("[^"]+"|[^\s\\]+)/gi, (match, prefix, source)=>{
|
|
1749
|
+
const tag = source.startsWith('"') ? source.slice(1, -1) : source;
|
|
1750
|
+
return tag === previousTag ? `${prefix}${citationTagInstructionValue(nextTag)}` : match;
|
|
1751
|
+
});
|
|
1752
|
+
}
|
|
1753
|
+
function documentCitationTags(value) {
|
|
1754
|
+
return uniqueCitationTags((value ?? '').split(/\s+/));
|
|
1755
|
+
}
|
|
1756
|
+
function isValidDocumentCitationTag(value) {
|
|
1757
|
+
return /^[A-Za-z0-9_:.+-]{1,80}$/.test(value);
|
|
1758
|
+
}
|
|
1759
|
+
function resolveDocumentCitation(tags, bibliography, instruction = '', cachedValue = '') {
|
|
1760
|
+
const normalized = uniqueCitationTags(tags);
|
|
1761
|
+
if (!normalized.length) return {
|
|
1762
|
+
text: cachedValue || '缺失引文',
|
|
1763
|
+
orphaned: true
|
|
1764
|
+
};
|
|
1765
|
+
const sources = new Map((bibliography?.sources ?? []).map((source)=>[
|
|
1766
|
+
source.tag,
|
|
1767
|
+
source
|
|
1768
|
+
]));
|
|
1769
|
+
const missing = normalized.filter((tag)=>!sources.has(tag));
|
|
1770
|
+
if (missing.length) return {
|
|
1771
|
+
text: 1 === missing.length ? `缺失引文:${missing[0]}` : `缺失引文:${missing.join('、')}`,
|
|
1772
|
+
orphaned: true
|
|
1773
|
+
};
|
|
1774
|
+
const selected = normalized.flatMap((tag)=>{
|
|
1775
|
+
const source = sources.get(tag);
|
|
1776
|
+
return source ? [
|
|
1777
|
+
source
|
|
1778
|
+
] : [];
|
|
1779
|
+
});
|
|
1780
|
+
const style = bibliography?.style ?? 'apa';
|
|
1781
|
+
const suppressAuthor = /(?:^|\s)\\n(?:\s|$)/i.test(instruction);
|
|
1782
|
+
const suppressYear = /(?:^|\s)\\v(?:\s|$)/i.test(instruction);
|
|
1783
|
+
const prefix = citationSwitch(instruction, 'f');
|
|
1784
|
+
const suffix = citationSwitch(instruction, 'p');
|
|
1785
|
+
const text = 'ieee' === style ? ieeeCitation(selected, bibliography?.sources ?? []) : 'mla' === style ? mlaCitation(selected, suppressAuthor) : 'chicago' === style ? chicagoCitation(selected, suppressAuthor, suppressYear) : apaCitation(selected, suppressAuthor, suppressYear);
|
|
1599
1786
|
return {
|
|
1600
|
-
|
|
1601
|
-
|
|
1787
|
+
text: `${prefix}${text}${suffix}`.trim() || cachedValue || normalized.join('; '),
|
|
1788
|
+
orphaned: false
|
|
1602
1789
|
};
|
|
1603
1790
|
}
|
|
1604
|
-
|
|
1605
|
-
const
|
|
1606
|
-
const
|
|
1607
|
-
const
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
function prepareLazyDocumentEditorSource(model, allowCreate, html) {
|
|
1615
|
-
const startedAt = lazyDocumentNow();
|
|
1616
|
-
const cacheHit = preparedModels.has(model);
|
|
1617
|
-
let prepared = preparedModels.get(model);
|
|
1618
|
-
if (prepared) {
|
|
1619
|
-
if (!prepared.root) {
|
|
1620
|
-
const htmlProjection = prepared.htmlProjection;
|
|
1621
|
-
const rebuilt = createPreparedLazyDocumentEditorSource(model.root, prepared.payloads);
|
|
1622
|
-
if (!rebuilt) return null;
|
|
1623
|
-
rebuilt.htmlProjection = htmlProjection;
|
|
1624
|
-
prepared = rebuilt;
|
|
1625
|
-
preparedModels.set(model, rebuilt);
|
|
1791
|
+
function normalizeDocumentCitationsHtml(source, bibliography) {
|
|
1792
|
+
const document1 = new DOMParser().parseFromString(source, 'text/html');
|
|
1793
|
+
const usedIds = new Set();
|
|
1794
|
+
for (const [index, element] of Array.from(document1.body.querySelectorAll(CITATION_SELECTOR)).entries()){
|
|
1795
|
+
const instruction = element.dataset.citationInstruction?.trim() ?? '';
|
|
1796
|
+
const tags = documentCitationTags(element.dataset.citationTags);
|
|
1797
|
+
const normalizedTags = tags.length ? tags : documentCitationTagsFromInstruction(instruction);
|
|
1798
|
+
if (!normalizedTags.length) {
|
|
1799
|
+
element.replaceWith(document1.createTextNode(element.textContent ?? ''));
|
|
1800
|
+
continue;
|
|
1626
1801
|
}
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1802
|
+
const cached = element.dataset.citationDisplay?.trim() || element.textContent?.trim() || '';
|
|
1803
|
+
const resolved = resolveDocumentCitation(normalizedTags, bibliography, instruction, cached);
|
|
1804
|
+
element.dataset.documentCitation = 'true';
|
|
1805
|
+
element.dataset.citationId = uniqueCitationId(element.dataset.citationId, index + 1, usedIds);
|
|
1806
|
+
element.dataset.citationTags = normalizedTags.join(' ');
|
|
1807
|
+
element.dataset.citationInstruction = instruction || documentCitationInstruction(normalizedTags);
|
|
1808
|
+
element.dataset.citationDisplay = resolved.text;
|
|
1809
|
+
if (resolved.orphaned) element.dataset.citationOrphaned = 'true';
|
|
1810
|
+
else delete element.dataset.citationOrphaned;
|
|
1811
|
+
element.classList.add('work-document-citation');
|
|
1812
|
+
element.textContent = resolved.text;
|
|
1813
|
+
}
|
|
1814
|
+
for (const [index, element] of Array.from(document1.body.querySelectorAll(BIBLIOGRAPHY_SELECTOR)).entries()){
|
|
1815
|
+
if (!bibliography) continue;
|
|
1816
|
+
const replacement = createBibliographyElement(document1, bibliography, element.dataset.bibliographyId || `document-bibliography-${index + 1}`);
|
|
1817
|
+
element.replaceWith(replacement);
|
|
1818
|
+
}
|
|
1819
|
+
return document1.body.innerHTML;
|
|
1820
|
+
}
|
|
1821
|
+
function renderDocumentBibliographyHtml(bibliography, id = 'document-bibliography-1') {
|
|
1822
|
+
const document1 = new DOMParser().parseFromString('', 'text/html');
|
|
1823
|
+
document1.body.append(createBibliographyElement(document1, bibliography, id));
|
|
1824
|
+
return document1.body.innerHTML;
|
|
1825
|
+
}
|
|
1826
|
+
function documentBibliographyEntry(source, bibliography, index) {
|
|
1827
|
+
const people = primaryCitationContributor(source);
|
|
1828
|
+
const authors = people?.corporate?.trim() || people?.people?.map((person)=>bibliographyPersonName(person, bibliography.style)).join(', ') || '未知作者';
|
|
1829
|
+
const title = source.title.trim() || 'Untitled';
|
|
1830
|
+
const year = source.year?.trim() || 'n.d.';
|
|
1831
|
+
const container = citationContainer(source);
|
|
1832
|
+
const url = source.url?.trim();
|
|
1833
|
+
if ('ieee' === bibliography.style) return [
|
|
1834
|
+
`[${index + 1}] ${authors}, “${title}.”`,
|
|
1835
|
+
container ? `${container},` : '',
|
|
1836
|
+
year ? `${year}.` : '',
|
|
1837
|
+
url ?? ''
|
|
1838
|
+
].filter(Boolean).join(' ');
|
|
1839
|
+
if ('mla' === bibliography.style) return [
|
|
1840
|
+
`${authors}.`,
|
|
1841
|
+
`“${title}.”`,
|
|
1842
|
+
container ? `${container},` : '',
|
|
1843
|
+
`${year}.`,
|
|
1844
|
+
url ?? ''
|
|
1845
|
+
].filter(Boolean).join(' ');
|
|
1846
|
+
if ('chicago' === bibliography.style) return [
|
|
1847
|
+
`${authors}.`,
|
|
1848
|
+
`${year}.`,
|
|
1849
|
+
`“${title}.”`,
|
|
1850
|
+
container ? `${container}.` : '',
|
|
1851
|
+
url ?? ''
|
|
1852
|
+
].filter(Boolean).join(' ');
|
|
1853
|
+
return [
|
|
1854
|
+
`${authors}.`,
|
|
1855
|
+
`(${year}).`,
|
|
1856
|
+
`${title}.`,
|
|
1857
|
+
container ? `${container}.` : '',
|
|
1858
|
+
url ?? ''
|
|
1859
|
+
].filter(Boolean).join(' ');
|
|
1860
|
+
}
|
|
1861
|
+
function primaryCitationContributor(source) {
|
|
1862
|
+
return source.contributors?.Author ?? Object.values(source.contributors ?? {})[0];
|
|
1863
|
+
}
|
|
1864
|
+
function createBibliographyElement(document1, bibliography, id) {
|
|
1865
|
+
const section = document1.createElement('section');
|
|
1866
|
+
section.dataset.documentBibliography = 'true';
|
|
1867
|
+
section.dataset.bibliographyId = id;
|
|
1868
|
+
section.dataset.bibliographyStyle = bibliography.style;
|
|
1869
|
+
section.className = 'work-document-bibliography';
|
|
1870
|
+
const heading = document1.createElement('h2');
|
|
1871
|
+
heading.textContent = '参考文献';
|
|
1872
|
+
section.append(heading);
|
|
1873
|
+
if (!bibliography.sources.length) {
|
|
1874
|
+
const empty = document1.createElement('p');
|
|
1875
|
+
empty.dataset.bibliographyEmpty = 'true';
|
|
1876
|
+
empty.textContent = '尚无文献源';
|
|
1877
|
+
section.append(empty);
|
|
1878
|
+
return section;
|
|
1633
1879
|
}
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
root: prepared.root
|
|
1640
|
-
};
|
|
1641
|
-
recordLazyDocumentMeasure('a3s-office.document.lazy-editor-source', startedAt, lazyDocumentNow(), {
|
|
1642
|
-
cacheHit
|
|
1880
|
+
bibliography.sources.forEach((source, index)=>{
|
|
1881
|
+
const paragraph = document1.createElement('p');
|
|
1882
|
+
paragraph.dataset.bibliographyEntry = source.tag;
|
|
1883
|
+
paragraph.textContent = documentBibliographyEntry(source, bibliography, index);
|
|
1884
|
+
section.append(paragraph);
|
|
1643
1885
|
});
|
|
1644
|
-
return
|
|
1886
|
+
return section;
|
|
1645
1887
|
}
|
|
1646
|
-
function
|
|
1647
|
-
|
|
1888
|
+
function apaCitation(sources, suppressAuthor, suppressYear) {
|
|
1889
|
+
const items = sources.map((source)=>{
|
|
1890
|
+
const author = suppressAuthor ? '' : citationAuthor(source, '&');
|
|
1891
|
+
const year = suppressYear ? '' : source.year?.trim() || 'n.d.';
|
|
1892
|
+
return [
|
|
1893
|
+
author,
|
|
1894
|
+
year
|
|
1895
|
+
].filter(Boolean).join(', ');
|
|
1896
|
+
});
|
|
1897
|
+
return `(${items.join('; ')})`;
|
|
1648
1898
|
}
|
|
1649
|
-
function
|
|
1650
|
-
|
|
1651
|
-
const prepared = preparedModels.get(model);
|
|
1652
|
-
if (prepared) prepared.htmlProjection = null;
|
|
1653
|
-
}
|
|
1899
|
+
function mlaCitation(sources, suppressAuthor) {
|
|
1900
|
+
return `(${sources.map((source)=>suppressAuthor ? source.year?.trim() || 'n.d.' : citationAuthor(source, 'and')).join('; ')})`;
|
|
1654
1901
|
}
|
|
1655
|
-
function
|
|
1656
|
-
|
|
1657
|
-
|
|
1902
|
+
function chicagoCitation(sources, suppressAuthor, suppressYear) {
|
|
1903
|
+
return `(${sources.map((source)=>[
|
|
1904
|
+
suppressAuthor ? '' : citationAuthor(source, 'and'),
|
|
1905
|
+
suppressYear ? '' : source.year?.trim() || 'n.d.'
|
|
1906
|
+
].filter(Boolean).join(' ')).join('; ')})`;
|
|
1658
1907
|
}
|
|
1659
|
-
function
|
|
1660
|
-
const
|
|
1661
|
-
|
|
1662
|
-
const visit = (node)=>{
|
|
1663
|
-
if ('documentChunk' === node.type && node.attrs?.windowContainer !== true) {
|
|
1664
|
-
const id = documentChunkId(node);
|
|
1665
|
-
if (!id) return node;
|
|
1666
|
-
if (documentChunkIsLazy(node)) {
|
|
1667
|
-
const payload = prepared.payloads.get(id);
|
|
1668
|
-
if (!payload) throw new Error(`The lazy document chunk payload "${id}" is missing.`);
|
|
1669
|
-
return {
|
|
1670
|
-
...node,
|
|
1671
|
-
content: [
|
|
1672
|
-
...payload
|
|
1673
|
-
]
|
|
1674
|
-
};
|
|
1675
|
-
}
|
|
1676
|
-
if (node.content?.length) prepared.payloads.set(id, node.content);
|
|
1677
|
-
return node;
|
|
1678
|
-
}
|
|
1679
|
-
if (!node.content?.length) return node;
|
|
1680
|
-
let changed = false;
|
|
1681
|
-
const content = node.content.map((child)=>{
|
|
1682
|
-
const next = visit(child);
|
|
1683
|
-
if (next !== child) changed = true;
|
|
1684
|
-
return next;
|
|
1685
|
-
});
|
|
1686
|
-
return changed ? {
|
|
1687
|
-
...node,
|
|
1688
|
-
content
|
|
1689
|
-
} : node;
|
|
1690
|
-
};
|
|
1691
|
-
return visit(root);
|
|
1908
|
+
function ieeeCitation(sources, allSources) {
|
|
1909
|
+
const indexes = sources.map((source)=>allSources.findIndex((candidate)=>candidate.id === source.id || candidate.tag === source.tag) + 1).filter((index)=>index > 0);
|
|
1910
|
+
return `[${indexes.join(', ')}]`;
|
|
1692
1911
|
}
|
|
1693
|
-
function
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
root: null
|
|
1702
|
-
});
|
|
1912
|
+
function citationAuthor(source, conjunction) {
|
|
1913
|
+
const contributor = primaryCitationContributor(source);
|
|
1914
|
+
if (contributor?.corporate?.trim()) return contributor.corporate.trim();
|
|
1915
|
+
const names = (contributor?.people ?? []).map((person)=>person.last.trim() || person.first.trim()).filter(Boolean);
|
|
1916
|
+
if (!names.length) return source.title.trim() || source.tag;
|
|
1917
|
+
if (1 === names.length) return names[0];
|
|
1918
|
+
if (2 === names.length) return `${names[0]} ${conjunction} ${names[1]}`;
|
|
1919
|
+
return `${names[0]} et al.`;
|
|
1703
1920
|
}
|
|
1704
|
-
function
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1921
|
+
function bibliographyPersonName(person, style) {
|
|
1922
|
+
const first = [
|
|
1923
|
+
person.first,
|
|
1924
|
+
person.middle
|
|
1925
|
+
].filter(Boolean).join(' ').trim();
|
|
1926
|
+
const suffix = person.suffix?.trim();
|
|
1927
|
+
if ('ieee' === style) {
|
|
1928
|
+
const initials = [
|
|
1929
|
+
person.first,
|
|
1930
|
+
person.middle
|
|
1931
|
+
].filter(Boolean).map((value)=>`${Array.from(value ?? '')[0] ?? ''}.`).join(' ');
|
|
1932
|
+
return [
|
|
1933
|
+
initials,
|
|
1934
|
+
person.last,
|
|
1935
|
+
suffix
|
|
1936
|
+
].filter(Boolean).join(' ');
|
|
1712
1937
|
}
|
|
1713
|
-
return
|
|
1938
|
+
return [
|
|
1939
|
+
person.last,
|
|
1940
|
+
first ? `, ${first}` : '',
|
|
1941
|
+
suffix ? `, ${suffix}` : ''
|
|
1942
|
+
].join('');
|
|
1714
1943
|
}
|
|
1715
|
-
function
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
if (!placeholder) {
|
|
1734
|
-
unsupported = true;
|
|
1735
|
-
return node;
|
|
1736
|
-
}
|
|
1737
|
-
lazyChunkCount += 1;
|
|
1738
|
-
return {
|
|
1739
|
-
...node,
|
|
1740
|
-
content: [
|
|
1741
|
-
placeholder
|
|
1742
|
-
]
|
|
1743
|
-
};
|
|
1944
|
+
function citationContainer(source) {
|
|
1945
|
+
return source.journalName?.trim() || source.publisher?.trim() || source.conferenceName?.trim() || source.institution?.trim() || '';
|
|
1946
|
+
}
|
|
1947
|
+
function citationSwitch(instruction, name) {
|
|
1948
|
+
const expression = new RegExp(`\\\\${name}\\s+"([^"]*)"`, 'i');
|
|
1949
|
+
return expression.exec(instruction)?.[1] ?? '';
|
|
1950
|
+
}
|
|
1951
|
+
function citationTagInstructionValue(tag) {
|
|
1952
|
+
return /^[A-Za-z0-9_:.+-]+$/.test(tag) ? tag : `"${tag.replaceAll('"', '')}"`;
|
|
1953
|
+
}
|
|
1954
|
+
function uniqueCitationTags(tags) {
|
|
1955
|
+
const result = [];
|
|
1956
|
+
const seen = new Set();
|
|
1957
|
+
for (const source of tags){
|
|
1958
|
+
const tag = source.trim();
|
|
1959
|
+
if (!(!tag || seen.has(tag))) {
|
|
1960
|
+
seen.add(tag);
|
|
1961
|
+
result.push(tag);
|
|
1744
1962
|
}
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
return
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
}
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1963
|
+
}
|
|
1964
|
+
return result;
|
|
1965
|
+
}
|
|
1966
|
+
function uniqueCitationId(source, index, usedIds) {
|
|
1967
|
+
const candidate = source?.trim();
|
|
1968
|
+
if (candidate && !usedIds.has(candidate)) {
|
|
1969
|
+
usedIds.add(candidate);
|
|
1970
|
+
return candidate;
|
|
1971
|
+
}
|
|
1972
|
+
let suffix = index;
|
|
1973
|
+
while(usedIds.has(`document-citation-${suffix}`))suffix += 1;
|
|
1974
|
+
const id = `document-citation-${suffix}`;
|
|
1975
|
+
usedIds.add(id);
|
|
1976
|
+
return id;
|
|
1977
|
+
}
|
|
1978
|
+
const DEFAULT_DOCUMENT_COLUMNS = {
|
|
1979
|
+
count: 1,
|
|
1980
|
+
spacing: 12,
|
|
1981
|
+
separator: false
|
|
1982
|
+
};
|
|
1983
|
+
const MAX_COLUMNS = 6;
|
|
1984
|
+
const MIN_COLUMN_PERCENT = 5;
|
|
1985
|
+
function normalizeDocumentColumns(columns) {
|
|
1986
|
+
const customCount = Array.isArray(columns?.custom) ? columns.custom.length : 0;
|
|
1987
|
+
const count = clampInteger(columns?.count, customCount || DEFAULT_DOCUMENT_COLUMNS.count, 1, MAX_COLUMNS);
|
|
1988
|
+
const spacing = clampNumber(columns?.spacing, DEFAULT_DOCUMENT_COLUMNS.spacing, 0, 30);
|
|
1989
|
+
const normalized = {
|
|
1990
|
+
count,
|
|
1991
|
+
spacing: roundOne(spacing),
|
|
1992
|
+
separator: Boolean(columns?.separator)
|
|
1764
1993
|
};
|
|
1994
|
+
if (count < 2 || !customCount) return normalized;
|
|
1995
|
+
const source = columns?.custom ?? [];
|
|
1996
|
+
const widths = normalizedPercentages(Array.from({
|
|
1997
|
+
length: count
|
|
1998
|
+
}, (_, index)=>finiteNumber(source[index]?.widthPercent, 100 / count)), 100, MIN_COLUMN_PERCENT);
|
|
1999
|
+
normalized.custom = Array.from({
|
|
2000
|
+
length: count
|
|
2001
|
+
}, (_, index)=>({
|
|
2002
|
+
widthPercent: widths[index],
|
|
2003
|
+
spacing: index === count - 1 ? 0 : roundOne(clampNumber(source[index]?.spacing, normalized.spacing, 0, 30))
|
|
2004
|
+
}));
|
|
2005
|
+
return normalized;
|
|
2006
|
+
}
|
|
2007
|
+
function serializeDocumentColumns(columns) {
|
|
2008
|
+
return JSON.stringify(normalizeDocumentColumns(columns));
|
|
2009
|
+
}
|
|
2010
|
+
function parseDocumentColumns(source, legacy = {}, fallback) {
|
|
2011
|
+
if (source?.trim()) try {
|
|
2012
|
+
return normalizeDocumentColumns(JSON.parse(source));
|
|
2013
|
+
} catch {}
|
|
2014
|
+
if (void 0 !== legacy.count || void 0 !== legacy.spacing || void 0 !== legacy.separator) return normalizeDocumentColumns(legacy);
|
|
2015
|
+
return normalizeDocumentColumns(fallback);
|
|
1765
2016
|
}
|
|
1766
|
-
function
|
|
1767
|
-
const
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
2017
|
+
function setCustomDocumentColumns(columns, enabled) {
|
|
2018
|
+
const normalized = normalizeDocumentColumns(columns);
|
|
2019
|
+
if (!enabled || normalized.count < 2) return {
|
|
2020
|
+
...normalized,
|
|
2021
|
+
custom: void 0
|
|
1771
2022
|
};
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
2023
|
+
if (normalized.custom) return normalized;
|
|
2024
|
+
return normalizeDocumentColumns({
|
|
2025
|
+
...normalized,
|
|
2026
|
+
custom: Array.from({
|
|
2027
|
+
length: normalized.count
|
|
2028
|
+
}, (_, index)=>({
|
|
2029
|
+
widthPercent: 100 / normalized.count,
|
|
2030
|
+
spacing: index === normalized.count - 1 ? 0 : normalized.spacing
|
|
2031
|
+
}))
|
|
2032
|
+
});
|
|
2033
|
+
}
|
|
2034
|
+
function updateDocumentColumnWidth(columns, index, widthPercent) {
|
|
2035
|
+
const normalized = setCustomDocumentColumns(columns, true);
|
|
2036
|
+
if (!normalized.custom?.[index]) return normalized;
|
|
2037
|
+
const maximum = 100 - MIN_COLUMN_PERCENT * (normalized.custom.length - 1);
|
|
2038
|
+
const target = Math.min(maximum, Math.max(MIN_COLUMN_PERCENT, finiteNumber(widthPercent, 100 / normalized.count)));
|
|
2039
|
+
const otherIndexes = normalized.custom.map((_, itemIndex)=>itemIndex).filter((itemIndex)=>itemIndex !== index);
|
|
2040
|
+
const otherWidths = normalizedPercentages(otherIndexes.map((itemIndex)=>normalized.custom?.[itemIndex].widthPercent ?? 1), 100 - target, MIN_COLUMN_PERCENT);
|
|
2041
|
+
const custom = normalized.custom.map((column, itemIndex)=>{
|
|
2042
|
+
const otherIndex = otherIndexes.indexOf(itemIndex);
|
|
2043
|
+
return {
|
|
2044
|
+
...column,
|
|
2045
|
+
widthPercent: itemIndex === index ? roundOne(target) : otherWidths[otherIndex]
|
|
2046
|
+
};
|
|
2047
|
+
});
|
|
1777
2048
|
return {
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
chunkId,
|
|
1781
|
-
contentSize: statistics.contentSize,
|
|
1782
|
-
paragraphCount: statistics.paragraphCount
|
|
1783
|
-
},
|
|
1784
|
-
...filler ? {
|
|
1785
|
-
content: [
|
|
1786
|
-
{
|
|
1787
|
-
type: 'text',
|
|
1788
|
-
text: filler
|
|
1789
|
-
}
|
|
1790
|
-
]
|
|
1791
|
-
} : {
|
|
1792
|
-
content: []
|
|
1793
|
-
}
|
|
2049
|
+
...normalized,
|
|
2050
|
+
custom
|
|
1794
2051
|
};
|
|
1795
2052
|
}
|
|
1796
|
-
function
|
|
1797
|
-
if (
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
2053
|
+
function normalizedPercentages(values, total, minimum) {
|
|
2054
|
+
if (!values.length) return [];
|
|
2055
|
+
const result = Array(values.length).fill(0);
|
|
2056
|
+
const remaining = new Set(values.map((_, index)=>index));
|
|
2057
|
+
let remainingTotal = total;
|
|
2058
|
+
while(remaining.size){
|
|
2059
|
+
const sourceTotal = Array.from(remaining).reduce((sum, index)=>sum + Math.max(0.001, finiteNumber(values[index], 1)), 0);
|
|
2060
|
+
const belowMinimum = Array.from(remaining).filter((index)=>Math.max(0.001, finiteNumber(values[index], 1)) / sourceTotal * remainingTotal < minimum);
|
|
2061
|
+
if (!belowMinimum.length) {
|
|
2062
|
+
for (const index of remaining)result[index] = Math.max(0.001, finiteNumber(values[index], 1)) / sourceTotal * remainingTotal;
|
|
2063
|
+
break;
|
|
2064
|
+
}
|
|
2065
|
+
for (const index of belowMinimum){
|
|
2066
|
+
result[index] = minimum;
|
|
2067
|
+
remaining.delete(index);
|
|
2068
|
+
remainingTotal -= minimum;
|
|
2069
|
+
}
|
|
1802
2070
|
}
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
for (const child of node.content ?? [])if (!appendDocumentNodePositionTape(child, parts, statistics)) return false;
|
|
1808
|
-
parts.push(DOCUMENT_LAZY_POSITION_BOUNDARY);
|
|
1809
|
-
return true;
|
|
2071
|
+
const rounded = result.map(roundOne);
|
|
2072
|
+
const adjustmentIndex = rounded.indexOf(Math.max(...rounded));
|
|
2073
|
+
rounded[adjustmentIndex] = roundOne(rounded[adjustmentIndex] + total - rounded.reduce((sum, value)=>sum + value, 0));
|
|
2074
|
+
return rounded;
|
|
1810
2075
|
}
|
|
1811
|
-
function
|
|
1812
|
-
return
|
|
2076
|
+
function clampInteger(value, fallback, minimum, maximum) {
|
|
2077
|
+
return Math.min(maximum, Math.max(minimum, Math.round(finiteNumber(value, fallback))));
|
|
1813
2078
|
}
|
|
1814
|
-
function
|
|
1815
|
-
|
|
1816
|
-
return 'string' == typeof id && id ? id : null;
|
|
2079
|
+
function clampNumber(value, fallback, minimum, maximum) {
|
|
2080
|
+
return Math.min(maximum, Math.max(minimum, finiteNumber(value, fallback)));
|
|
1817
2081
|
}
|
|
1818
|
-
function
|
|
1819
|
-
return
|
|
2082
|
+
function finiteNumber(value, fallback) {
|
|
2083
|
+
return Number.isFinite(value) ? Number(value) : fallback;
|
|
1820
2084
|
}
|
|
1821
|
-
function
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
2085
|
+
function roundOne(value) {
|
|
2086
|
+
return Math.round(10 * value) / 10;
|
|
2087
|
+
}
|
|
2088
|
+
const DEFAULT_DOCUMENT_MARGINS = {
|
|
2089
|
+
top: 25,
|
|
2090
|
+
right: 23,
|
|
2091
|
+
bottom: 25,
|
|
2092
|
+
left: 23
|
|
2093
|
+
};
|
|
2094
|
+
function documentMargins(content) {
|
|
2095
|
+
return {
|
|
2096
|
+
top: validMargin(content.margins?.top, DEFAULT_DOCUMENT_MARGINS.top),
|
|
2097
|
+
right: validMargin(content.margins?.right, DEFAULT_DOCUMENT_MARGINS.right),
|
|
2098
|
+
bottom: validMargin(content.margins?.bottom, DEFAULT_DOCUMENT_MARGINS.bottom),
|
|
2099
|
+
left: validMargin(content.margins?.left, DEFAULT_DOCUMENT_MARGINS.left)
|
|
2100
|
+
};
|
|
2101
|
+
}
|
|
2102
|
+
function clampDocumentMargin(value) {
|
|
2103
|
+
return Math.min(60, Math.max(5, Math.round(10 * value) / 10));
|
|
2104
|
+
}
|
|
2105
|
+
function millimetersToPixels(value) {
|
|
2106
|
+
return 96 * value / 25.4;
|
|
2107
|
+
}
|
|
2108
|
+
function validMargin(value, fallback) {
|
|
2109
|
+
return Number.isFinite(value) ? clampDocumentMargin(value) : fallback;
|
|
1829
2110
|
}
|
|
1830
2111
|
const DOCUMENT_MODEL_SCHEMA = 'a3s.office.document';
|
|
1831
2112
|
const DOCUMENT_MODEL_VERSION = 1;
|
|
@@ -1853,7 +2134,7 @@ function work_document_model_createSchemaValidatedWorkDocumentModel(html, root,
|
|
|
1853
2134
|
schemaValidatedDocumentModels.set(model, {
|
|
1854
2135
|
html,
|
|
1855
2136
|
htmlFingerprint: model.htmlFingerprint,
|
|
1856
|
-
initialIntegrityFeatures:
|
|
2137
|
+
initialIntegrityFeatures: work_document_model_nonNegativeInteger(options.initialIntegrityFeatures),
|
|
1857
2138
|
root
|
|
1858
2139
|
});
|
|
1859
2140
|
return model;
|
|
@@ -1902,7 +2183,7 @@ function nextRevision(previous) {
|
|
|
1902
2183
|
const revision = previous?.schema === DOCUMENT_MODEL_SCHEMA && previous.version === DOCUMENT_MODEL_VERSION && Number.isSafeInteger(previous.revision) && previous.revision > 0 ? previous.revision : 0;
|
|
1903
2184
|
return revision >= Number.MAX_SAFE_INTEGER ? 1 : revision + 1;
|
|
1904
2185
|
}
|
|
1905
|
-
function
|
|
2186
|
+
function work_document_model_nonNegativeInteger(value) {
|
|
1906
2187
|
const number = Number(value);
|
|
1907
2188
|
return Number.isSafeInteger(number) && number >= 0 ? number : null;
|
|
1908
2189
|
}
|
|
@@ -10843,168 +11124,44 @@ function bindLazyDocumentChildren(node, parent, firstPosition) {
|
|
|
10843
11124
|
if (parent.children.length !== children.length) return null;
|
|
10844
11125
|
let size = 0;
|
|
10845
11126
|
for(let index = 0; index < children.length; index += 1){
|
|
10846
|
-
const child = children[index];
|
|
10847
|
-
const element = parent.children.item(index);
|
|
10848
|
-
if (!child || !(element instanceof HTMLElement)) return null;
|
|
10849
|
-
const childSize = bindLazyDocumentNode(child, element, firstPosition + size);
|
|
10850
|
-
if (null === childSize) return null;
|
|
10851
|
-
size += childSize;
|
|
10852
|
-
}
|
|
10853
|
-
return size;
|
|
10854
|
-
}
|
|
10855
|
-
function bindLazyDocumentTableAttributes(table, node) {
|
|
10856
|
-
setBooleanDataset(table, 'officeTableImported', node.attrs?.officeImported === true);
|
|
10857
|
-
setStringDataset(table, 'documentVirtualTableId', node.attrs?.virtualTableId);
|
|
10858
|
-
setNumberDataset(table, 'documentVirtualTableIndex', node.attrs?.virtualTableIndex);
|
|
10859
|
-
setNumberDataset(table, 'documentVirtualTableCount', node.attrs?.virtualTableCount);
|
|
10860
|
-
}
|
|
10861
|
-
function lazyDocumentPreviewShape(content) {
|
|
10862
|
-
const parts = [];
|
|
10863
|
-
for (const node of content)appendLazyDocumentPreviewShape(node, parts);
|
|
10864
|
-
return parts.join('');
|
|
10865
|
-
}
|
|
10866
|
-
function appendLazyDocumentPreviewShape(node, parts) {
|
|
10867
|
-
const children = node.content ?? [];
|
|
10868
|
-
parts.push(node.type, '[', String(children.length), '](');
|
|
10869
|
-
for (const child of children)appendLazyDocumentPreviewShape(child, parts);
|
|
10870
|
-
parts.push(')');
|
|
10871
|
-
}
|
|
10872
|
-
function setBooleanDataset(element, name, value) {
|
|
10873
|
-
if (value) element.dataset[name] = 'true';
|
|
10874
|
-
else delete element.dataset[name];
|
|
10875
|
-
}
|
|
10876
|
-
function setStringDataset(element, name, value) {
|
|
10877
|
-
if ('string' == typeof value && value) element.dataset[name] = value;
|
|
10878
|
-
else delete element.dataset[name];
|
|
10879
|
-
}
|
|
10880
|
-
function setNumberDataset(element, name, value) {
|
|
10881
|
-
const number = Number(value);
|
|
10882
|
-
if (Number.isSafeInteger(number) && number >= 0) element.dataset[name] = String(number);
|
|
10883
|
-
else delete element.dataset[name];
|
|
10884
|
-
}
|
|
10885
|
-
const statisticsByDocument = new WeakMap();
|
|
10886
|
-
function documentWordCount(value) {
|
|
10887
|
-
let asciiCount = 0;
|
|
10888
|
-
let inAsciiWord = false;
|
|
10889
|
-
for(let index = 0; index < value.length; index += 1){
|
|
10890
|
-
const code = value.charCodeAt(index);
|
|
10891
|
-
const asciiLetterOrNumber = code >= 0x30 && code <= 0x39 || code >= 0x41 && code <= 0x5a || code >= 0x61 && code <= 0x7a;
|
|
10892
|
-
if (asciiLetterOrNumber) {
|
|
10893
|
-
if (!inAsciiWord) asciiCount += 1;
|
|
10894
|
-
inAsciiWord = true;
|
|
10895
|
-
continue;
|
|
10896
|
-
}
|
|
10897
|
-
inAsciiWord = false;
|
|
10898
|
-
if (!(code <= 0x7f) && 0xfffc !== code) return unicodeDocumentWordCount(value);
|
|
10899
|
-
}
|
|
10900
|
-
return asciiCount;
|
|
10901
|
-
}
|
|
10902
|
-
function unicodeDocumentWordCount(value) {
|
|
10903
|
-
let count = 0;
|
|
10904
|
-
for (const _match of value.matchAll(/[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]|[\p{L}\p{N}]+/gu))count += 1;
|
|
10905
|
-
return count;
|
|
10906
|
-
}
|
|
10907
|
-
function documentTextStatistics(editor) {
|
|
10908
|
-
const document1 = editor.state.doc;
|
|
10909
|
-
const cached = statisticsByDocument.get(document1);
|
|
10910
|
-
if (cached) return cached;
|
|
10911
|
-
const source = editor.getText({
|
|
10912
|
-
blockSeparator: '\n'
|
|
10913
|
-
});
|
|
10914
|
-
let characterCountWithSpaces = 0;
|
|
10915
|
-
let characterCountWithoutSpaces = 0;
|
|
10916
|
-
for(let index = 0; index < source.length; index += 1){
|
|
10917
|
-
const codePoint = source.codePointAt(index);
|
|
10918
|
-
if (void 0 !== codePoint) {
|
|
10919
|
-
if (codePoint > 0xffff) index += 1;
|
|
10920
|
-
if (codePoint !== "".codePointAt(0) && 0x0a !== codePoint && 0x0d !== codePoint) {
|
|
10921
|
-
characterCountWithSpaces += 1;
|
|
10922
|
-
if (!isEcmaScriptWhitespace(codePoint)) characterCountWithoutSpaces += 1;
|
|
10923
|
-
}
|
|
10924
|
-
}
|
|
10925
|
-
}
|
|
10926
|
-
let paragraphCount = 0;
|
|
10927
|
-
document1.descendants((node)=>{
|
|
10928
|
-
if (node.type.name === DOCUMENT_LAZY_BLOCK_NODE) {
|
|
10929
|
-
const logicalParagraphs = Number(node.attrs.paragraphCount);
|
|
10930
|
-
paragraphCount += Number.isSafeInteger(logicalParagraphs) && logicalParagraphs >= 0 ? logicalParagraphs : 0;
|
|
10931
|
-
return false;
|
|
10932
|
-
}
|
|
10933
|
-
if (node.isTextblock) paragraphCount += 1;
|
|
10934
|
-
return true;
|
|
10935
|
-
});
|
|
10936
|
-
const statistics = {
|
|
10937
|
-
characterCountWithSpaces,
|
|
10938
|
-
characterCountWithoutSpaces,
|
|
10939
|
-
paragraphCount,
|
|
10940
|
-
wordCount: documentWordCount(source)
|
|
10941
|
-
};
|
|
10942
|
-
statisticsByDocument.set(document1, statistics);
|
|
10943
|
-
return statistics;
|
|
10944
|
-
}
|
|
10945
|
-
function transferDocumentTextStatistics(previous, next) {
|
|
10946
|
-
const statistics = statisticsByDocument.get(previous);
|
|
10947
|
-
if (statistics) statisticsByDocument.set(next, statistics);
|
|
10948
|
-
}
|
|
10949
|
-
function transferChangedDocumentTextStatistics(previous, next, changes) {
|
|
10950
|
-
const cached = statisticsByDocument.get(previous);
|
|
10951
|
-
if (!cached || !changes.length) return false;
|
|
10952
|
-
const statistics = {
|
|
10953
|
-
...cached
|
|
10954
|
-
};
|
|
10955
|
-
for (const { after, before } of changes){
|
|
10956
|
-
applyDocumentTextStatisticsDelta(statistics, simpleDocumentSubtreeStatistics(before), -1);
|
|
10957
|
-
applyDocumentTextStatisticsDelta(statistics, simpleDocumentSubtreeStatistics(after), 1);
|
|
11127
|
+
const child = children[index];
|
|
11128
|
+
const element = parent.children.item(index);
|
|
11129
|
+
if (!child || !(element instanceof HTMLElement)) return null;
|
|
11130
|
+
const childSize = bindLazyDocumentNode(child, element, firstPosition + size);
|
|
11131
|
+
if (null === childSize) return null;
|
|
11132
|
+
size += childSize;
|
|
10958
11133
|
}
|
|
10959
|
-
|
|
10960
|
-
statisticsByDocument.set(next, statistics);
|
|
10961
|
-
return true;
|
|
11134
|
+
return size;
|
|
10962
11135
|
}
|
|
10963
|
-
function
|
|
10964
|
-
|
|
10965
|
-
|
|
10966
|
-
|
|
10967
|
-
|
|
10968
|
-
wordCount: 0
|
|
10969
|
-
};
|
|
10970
|
-
const visit = (node)=>{
|
|
10971
|
-
if (node.type.name === DOCUMENT_LAZY_BLOCK_NODE) {
|
|
10972
|
-
accumulateDocumentTextStatistics(statistics, node.textContent);
|
|
10973
|
-
const logicalParagraphs = Number(node.attrs.paragraphCount);
|
|
10974
|
-
statistics.paragraphCount += Number.isSafeInteger(logicalParagraphs) && logicalParagraphs >= 0 ? logicalParagraphs : 0;
|
|
10975
|
-
return;
|
|
10976
|
-
}
|
|
10977
|
-
if (node.isTextblock) {
|
|
10978
|
-
accumulateDocumentTextStatistics(statistics, node.textContent);
|
|
10979
|
-
statistics.paragraphCount += 1;
|
|
10980
|
-
return;
|
|
10981
|
-
}
|
|
10982
|
-
node.forEach(visit);
|
|
10983
|
-
};
|
|
10984
|
-
visit(root);
|
|
10985
|
-
return statistics;
|
|
11136
|
+
function bindLazyDocumentTableAttributes(table, node) {
|
|
11137
|
+
setBooleanDataset(table, 'officeTableImported', node.attrs?.officeImported === true);
|
|
11138
|
+
setStringDataset(table, 'documentVirtualTableId', node.attrs?.virtualTableId);
|
|
11139
|
+
setNumberDataset(table, 'documentVirtualTableIndex', node.attrs?.virtualTableIndex);
|
|
11140
|
+
setNumberDataset(table, 'documentVirtualTableCount', node.attrs?.virtualTableCount);
|
|
10986
11141
|
}
|
|
10987
|
-
function
|
|
10988
|
-
|
|
10989
|
-
|
|
10990
|
-
|
|
10991
|
-
if (codePoint > 0xffff) index += 1;
|
|
10992
|
-
if (codePoint !== "".codePointAt(0) && 0x0a !== codePoint && 0x0d !== codePoint) {
|
|
10993
|
-
statistics.characterCountWithSpaces += 1;
|
|
10994
|
-
if (!isEcmaScriptWhitespace(codePoint)) statistics.characterCountWithoutSpaces += 1;
|
|
10995
|
-
}
|
|
10996
|
-
}
|
|
10997
|
-
}
|
|
10998
|
-
statistics.wordCount += documentWordCount(source);
|
|
11142
|
+
function lazyDocumentPreviewShape(content) {
|
|
11143
|
+
const parts = [];
|
|
11144
|
+
for (const node of content)appendLazyDocumentPreviewShape(node, parts);
|
|
11145
|
+
return parts.join('');
|
|
10999
11146
|
}
|
|
11000
|
-
function
|
|
11001
|
-
|
|
11002
|
-
|
|
11003
|
-
|
|
11004
|
-
|
|
11147
|
+
function appendLazyDocumentPreviewShape(node, parts) {
|
|
11148
|
+
const children = node.content ?? [];
|
|
11149
|
+
parts.push(node.type, '[', String(children.length), '](');
|
|
11150
|
+
for (const child of children)appendLazyDocumentPreviewShape(child, parts);
|
|
11151
|
+
parts.push(')');
|
|
11005
11152
|
}
|
|
11006
|
-
function
|
|
11007
|
-
|
|
11153
|
+
function setBooleanDataset(element, name, value) {
|
|
11154
|
+
if (value) element.dataset[name] = 'true';
|
|
11155
|
+
else delete element.dataset[name];
|
|
11156
|
+
}
|
|
11157
|
+
function setStringDataset(element, name, value) {
|
|
11158
|
+
if ('string' == typeof value && value) element.dataset[name] = value;
|
|
11159
|
+
else delete element.dataset[name];
|
|
11160
|
+
}
|
|
11161
|
+
function setNumberDataset(element, name, value) {
|
|
11162
|
+
const number = Number(value);
|
|
11163
|
+
if (Number.isSafeInteger(number) && number >= 0) element.dataset[name] = String(number);
|
|
11164
|
+
else delete element.dataset[name];
|
|
11008
11165
|
}
|
|
11009
11166
|
const INITIAL_DOCUMENT_CHUNK_WINDOW_SIZE = 2;
|
|
11010
11167
|
const DOCUMENT_CHUNK_WINDOW_ROOT_MARGIN = '0px';
|
|
@@ -12348,15 +12505,33 @@ function resolveDocumentPageFields(pages, sections) {
|
|
|
12348
12505
|
]));
|
|
12349
12506
|
const sectionPages = new Map();
|
|
12350
12507
|
for (const page of pages)for (const sectionId of new Set(page.segments.map((segment)=>segment.sectionId)))sectionPages.set(sectionId, (sectionPages.get(sectionId) ?? 0) + 1);
|
|
12508
|
+
const statistics = documentFieldStatisticsFromHtml(sections.map((section)=>section.html).join('\n'));
|
|
12509
|
+
const bookmarkPages = documentBookmarkPageNumbers(pages);
|
|
12351
12510
|
const now = new Date();
|
|
12352
12511
|
for (const page of pages)for (const segment of page.segments)segment.html = resolveDocumentFieldsHtml(segment.html, {
|
|
12353
12512
|
pageNumber: page.pageNumber,
|
|
12354
12513
|
totalPages: pages.length,
|
|
12355
12514
|
sectionNumber: sectionNumbers.get(segment.sectionId) ?? 1,
|
|
12356
12515
|
sectionPages: sectionPages.get(segment.sectionId) ?? 1,
|
|
12516
|
+
wordCount: statistics.wordCount,
|
|
12517
|
+
characterCount: statistics.characterCount,
|
|
12518
|
+
bookmarkPageNumbers: bookmarkPages,
|
|
12357
12519
|
now
|
|
12358
12520
|
});
|
|
12359
12521
|
}
|
|
12522
|
+
function documentBookmarkPageNumbers(pages) {
|
|
12523
|
+
const values = new Map();
|
|
12524
|
+
for (const page of pages)for (const segment of page.segments){
|
|
12525
|
+
const document1 = new DOMParser().parseFromString(segment.html, 'text/html');
|
|
12526
|
+
for (const boundary of Array.from(document1.body.querySelectorAll('[data-document-bookmark-boundary][data-bookmark-kind="start"]'))){
|
|
12527
|
+
const id = boundary.dataset.bookmarkId?.trim();
|
|
12528
|
+
const name = boundary.dataset.bookmarkName?.trim();
|
|
12529
|
+
if (id && !values.has(`id:${id}`)) values.set(`id:${id}`, page.pageNumber);
|
|
12530
|
+
if (name && !values.has(`name:${name.toLowerCase()}`)) values.set(`name:${name.toLowerCase()}`, page.pageNumber);
|
|
12531
|
+
}
|
|
12532
|
+
}
|
|
12533
|
+
return values;
|
|
12534
|
+
}
|
|
12360
12535
|
function samePhysicalPageLayout(current, next) {
|
|
12361
12536
|
return current.pageSize === next.pageSize && current.orientation === next.orientation && JSON.stringify(current.pageGeometry) === JSON.stringify(next.pageGeometry) && current.margins.top === next.margins.top && current.margins.right === next.margins.right && current.margins.bottom === next.margins.bottom && current.margins.left === next.margins.left && JSON.stringify(current.pageMargins) === JSON.stringify(next.pageMargins);
|
|
12362
12537
|
}
|
|
@@ -12447,7 +12622,7 @@ const DocumentField = core_Node.create({
|
|
|
12447
12622
|
},
|
|
12448
12623
|
addCommands () {
|
|
12449
12624
|
return {
|
|
12450
|
-
insertDocumentField: (kind)=>(props)=>insertDocumentFieldCommand(props, kind),
|
|
12625
|
+
insertDocumentField: (kind, options = {})=>(props)=>insertDocumentFieldCommand(props, kind, options),
|
|
12451
12626
|
refreshDocumentFields: (content, options)=>(props)=>refreshDocumentFieldsCommand(props, content, options)
|
|
12452
12627
|
};
|
|
12453
12628
|
},
|
|
@@ -12456,7 +12631,10 @@ const DocumentField = core_Node.create({
|
|
|
12456
12631
|
id: work_document_field_node_hiddenAttribute(''),
|
|
12457
12632
|
kind: work_document_field_node_hiddenAttribute('page'),
|
|
12458
12633
|
instruction: work_document_field_node_hiddenAttribute('PAGE'),
|
|
12459
|
-
display: work_document_field_node_hiddenAttribute('1')
|
|
12634
|
+
display: work_document_field_node_hiddenAttribute('1'),
|
|
12635
|
+
targetId: work_document_field_node_hiddenAttribute(''),
|
|
12636
|
+
targetName: work_document_field_node_hiddenAttribute(''),
|
|
12637
|
+
orphaned: work_document_field_node_hiddenAttribute(false)
|
|
12460
12638
|
};
|
|
12461
12639
|
},
|
|
12462
12640
|
parseHTML () {
|
|
@@ -12467,11 +12645,15 @@ const DocumentField = core_Node.create({
|
|
|
12467
12645
|
if (!(node instanceof HTMLElement)) return false;
|
|
12468
12646
|
const instruction = node.dataset.fieldInstruction?.trim() ?? '';
|
|
12469
12647
|
const kind = documentFieldKind(node.dataset.fieldKind) ?? docxDocumentFieldKind(instruction) ?? 'page';
|
|
12648
|
+
const targetName = node.dataset.fieldTargetName ?? docxDocumentFieldTarget(instruction) ?? '';
|
|
12470
12649
|
return {
|
|
12471
12650
|
id: node.dataset.fieldId ?? '',
|
|
12472
12651
|
kind,
|
|
12473
|
-
instruction: instruction || documentFieldInstruction(kind),
|
|
12474
|
-
display: node.dataset.fieldDisplay?.trim() || node.textContent?.trim() || documentFieldLabel(kind)
|
|
12652
|
+
instruction: 'pageReference' === kind && targetName ? documentPageReferenceInstruction(targetName, instruction) : instruction || documentFieldInstruction(kind),
|
|
12653
|
+
display: node.dataset.fieldDisplay?.trim() || node.textContent?.trim() || documentFieldLabel(kind),
|
|
12654
|
+
targetId: node.dataset.fieldTargetId ?? '',
|
|
12655
|
+
targetName,
|
|
12656
|
+
orphaned: 'true' === node.dataset.fieldOrphaned
|
|
12475
12657
|
};
|
|
12476
12658
|
}
|
|
12477
12659
|
}
|
|
@@ -12481,14 +12663,23 @@ const DocumentField = core_Node.create({
|
|
|
12481
12663
|
const instruction = 'string' == typeof node.attrs.instruction ? node.attrs.instruction.trim() : '';
|
|
12482
12664
|
const kind = documentFieldKind(node.attrs.kind) ?? docxDocumentFieldKind(instruction) ?? 'page';
|
|
12483
12665
|
const display = 'string' == typeof node.attrs.display && node.attrs.display.trim() ? node.attrs.display.trim() : documentFieldLabel(kind);
|
|
12666
|
+
const targetName = 'string' == typeof node.attrs.targetName ? node.attrs.targetName : '';
|
|
12667
|
+
const normalizedInstruction = 'pageReference' === kind && targetName ? documentPageReferenceInstruction(targetName, instruction) : instruction || documentFieldInstruction(kind);
|
|
12484
12668
|
return [
|
|
12485
12669
|
'span',
|
|
12486
12670
|
mergeAttributes(HTMLAttributes, {
|
|
12487
12671
|
'data-document-field': 'true',
|
|
12488
12672
|
'data-field-id': 'string' == typeof node.attrs.id ? node.attrs.id : '',
|
|
12489
12673
|
'data-field-kind': kind,
|
|
12490
|
-
'data-field-instruction':
|
|
12674
|
+
'data-field-instruction': normalizedInstruction,
|
|
12491
12675
|
'data-field-display': display,
|
|
12676
|
+
...'pageReference' === kind && 'string' == typeof node.attrs.targetId && node.attrs.targetId ? {
|
|
12677
|
+
'data-field-target-id': node.attrs.targetId
|
|
12678
|
+
} : {},
|
|
12679
|
+
...'pageReference' === kind && 'string' == typeof node.attrs.targetName && node.attrs.targetName ? {
|
|
12680
|
+
'data-field-target-name': node.attrs.targetName
|
|
12681
|
+
} : {},
|
|
12682
|
+
'data-field-orphaned': node.attrs.orphaned ? 'true' : void 0,
|
|
12492
12683
|
class: 'work-document-field',
|
|
12493
12684
|
title: documentFieldLabel(kind)
|
|
12494
12685
|
}),
|
|
@@ -12500,16 +12691,26 @@ const DocumentField = core_Node.create({
|
|
|
12500
12691
|
return 'string' == typeof node.attrs.display && node.attrs.display.trim() ? node.attrs.display.trim() : documentFieldLabel(kind);
|
|
12501
12692
|
}
|
|
12502
12693
|
});
|
|
12503
|
-
function insertDocumentFieldCommand({ dispatch, editor, state, tr }, kind) {
|
|
12694
|
+
function insertDocumentFieldCommand({ dispatch, editor, state, tr }, kind, options) {
|
|
12504
12695
|
const fieldType = editor.schema.nodes.documentField;
|
|
12505
12696
|
if (!fieldType) return false;
|
|
12697
|
+
const targetName = 'string' == typeof options.targetName ? options.targetName.trim() : '';
|
|
12698
|
+
if ('pageReference' === kind && !targetName) return false;
|
|
12506
12699
|
if (!dispatch) return true;
|
|
12507
|
-
const instruction = documentFieldInstruction(kind);
|
|
12700
|
+
const instruction = documentFieldInstruction(kind, options);
|
|
12701
|
+
const statistics = documentFieldStatisticsFromText(state.doc.textBetween(0, state.doc.content.size, '\n', '\uFFFC'));
|
|
12702
|
+
const context = {
|
|
12703
|
+
...fallbackContext(state),
|
|
12704
|
+
...statistics
|
|
12705
|
+
};
|
|
12508
12706
|
tr.replaceSelectionWith(fieldType.create({
|
|
12509
12707
|
id: createWorkId('field'),
|
|
12510
12708
|
kind,
|
|
12511
12709
|
instruction,
|
|
12512
|
-
display: documentFieldDisplay(kind,
|
|
12710
|
+
display: documentFieldDisplay(kind, context, instruction),
|
|
12711
|
+
targetId: options.targetId?.trim() ?? '',
|
|
12712
|
+
targetName,
|
|
12713
|
+
orphaned: 'pageReference' === kind && !documentBookmarkExists(state, options)
|
|
12513
12714
|
}), false);
|
|
12514
12715
|
tr.scrollIntoView();
|
|
12515
12716
|
return true;
|
|
@@ -12529,6 +12730,7 @@ function refreshDocumentFieldsCommand({ editor, state, tr }, content, options =
|
|
|
12529
12730
|
]
|
|
12530
12731
|
] : []));
|
|
12531
12732
|
const now = work_document_field_node_validDate(options.now) ?? new Date();
|
|
12733
|
+
const statistics = documentFieldStatisticsFromText(state.doc.textBetween(0, state.doc.content.size, '\n', '\uFFFC'));
|
|
12532
12734
|
let fieldIndex = 0;
|
|
12533
12735
|
state.doc.descendants((node, position)=>{
|
|
12534
12736
|
if ('documentField' !== node.type.name) return;
|
|
@@ -12540,12 +12742,20 @@ function refreshDocumentFieldsCommand({ editor, state, tr }, content, options =
|
|
|
12540
12742
|
const context = options.resolveContext?.(position);
|
|
12541
12743
|
const display = context ? documentFieldDisplay(kind, {
|
|
12542
12744
|
...context,
|
|
12745
|
+
wordCount: context.wordCount ?? statistics.wordCount,
|
|
12746
|
+
characterCount: context.characterCount ?? statistics.characterCount,
|
|
12747
|
+
referencePageNumber: 'pageReference' === kind ? resolveBookmarkPageNumber(state, node, options.resolveContext) : context.referencePageNumber,
|
|
12543
12748
|
now: work_document_field_node_validDate(context.now) ?? now
|
|
12544
12749
|
}, work_document_field_node_stringAttribute(node.attrs.instruction), work_document_field_node_stringAttribute(node.attrs.display)) : fallbackById.get(work_document_field_node_stringAttribute(node.attrs.id)) ?? fallback;
|
|
12545
|
-
if (!display
|
|
12750
|
+
if (!display) return;
|
|
12751
|
+
const targetName = work_document_field_node_stringAttribute(node.attrs.targetName) || docxDocumentFieldTarget(work_document_field_node_stringAttribute(node.attrs.instruction)) || '';
|
|
12752
|
+
const orphaned = 'pageReference' === kind ? !bookmarkBoundaryForField(state, node, targetName) : false;
|
|
12753
|
+
if (node.attrs.display === display && node.attrs.targetName === targetName && node.attrs.orphaned === orphaned) return;
|
|
12546
12754
|
tr.setNodeMarkup(position, void 0, {
|
|
12547
12755
|
...node.attrs,
|
|
12548
|
-
display
|
|
12756
|
+
display,
|
|
12757
|
+
targetName,
|
|
12758
|
+
orphaned
|
|
12549
12759
|
});
|
|
12550
12760
|
});
|
|
12551
12761
|
if (tr.docChanged && false === options.addToHistory) tr.setMeta('addToHistory', false);
|
|
@@ -12605,6 +12815,48 @@ function work_document_field_node_validDate(value) {
|
|
|
12605
12815
|
function work_document_field_node_stringAttribute(value) {
|
|
12606
12816
|
return 'string' == typeof value ? value.trim() : '';
|
|
12607
12817
|
}
|
|
12818
|
+
function documentBookmarkExists(state, options) {
|
|
12819
|
+
const targetId = work_document_field_node_stringAttribute(options.targetId);
|
|
12820
|
+
const targetName = work_document_field_node_stringAttribute(options.targetName).toLowerCase();
|
|
12821
|
+
let found = false;
|
|
12822
|
+
state.doc.descendants((node)=>{
|
|
12823
|
+
if ('documentBookmarkBoundary' === node.type.name && 'start' === node.attrs.kind && (targetId && work_document_field_node_stringAttribute(node.attrs.id) === targetId || targetName && work_document_field_node_stringAttribute(node.attrs.name).toLowerCase() === targetName)) {
|
|
12824
|
+
found = true;
|
|
12825
|
+
return false;
|
|
12826
|
+
}
|
|
12827
|
+
return !found;
|
|
12828
|
+
});
|
|
12829
|
+
return found;
|
|
12830
|
+
}
|
|
12831
|
+
function bookmarkBoundaryForField(state, node, targetName) {
|
|
12832
|
+
const targetId = work_document_field_node_stringAttribute(node.attrs.targetId);
|
|
12833
|
+
const normalizedName = targetName.toLowerCase();
|
|
12834
|
+
let found = null;
|
|
12835
|
+
state.doc.descendants((candidate)=>{
|
|
12836
|
+
if (found || 'documentBookmarkBoundary' !== candidate.type.name || 'start' !== candidate.attrs.kind) return null === found;
|
|
12837
|
+
if (targetId && work_document_field_node_stringAttribute(candidate.attrs.id) === targetId || normalizedName && work_document_field_node_stringAttribute(candidate.attrs.name).toLowerCase() === normalizedName) {
|
|
12838
|
+
found = candidate;
|
|
12839
|
+
return false;
|
|
12840
|
+
}
|
|
12841
|
+
return true;
|
|
12842
|
+
});
|
|
12843
|
+
return found;
|
|
12844
|
+
}
|
|
12845
|
+
function resolveBookmarkPageNumber(state, node, resolveContext) {
|
|
12846
|
+
if (!resolveContext) return null;
|
|
12847
|
+
const targetId = work_document_field_node_stringAttribute(node.attrs.targetId);
|
|
12848
|
+
const targetName = work_document_field_node_stringAttribute(node.attrs.targetName).toLowerCase() || (docxDocumentFieldTarget(work_document_field_node_stringAttribute(node.attrs.instruction)) ?? '').toLowerCase();
|
|
12849
|
+
let page = null;
|
|
12850
|
+
state.doc.descendants((candidate, position)=>{
|
|
12851
|
+
if (null !== page || 'documentBookmarkBoundary' !== candidate.type.name || 'start' !== candidate.attrs.kind) return null === page;
|
|
12852
|
+
if (targetId && work_document_field_node_stringAttribute(candidate.attrs.id) === targetId || targetName && work_document_field_node_stringAttribute(candidate.attrs.name).toLowerCase() === targetName) {
|
|
12853
|
+
page = resolveContext(position)?.pageNumber ?? null;
|
|
12854
|
+
return false;
|
|
12855
|
+
}
|
|
12856
|
+
return true;
|
|
12857
|
+
});
|
|
12858
|
+
return page;
|
|
12859
|
+
}
|
|
12608
12860
|
const DEFAULT_WRAP_SIDE = 'bothSides';
|
|
12609
12861
|
const WRAP_COORDINATE_SIZE = 21600;
|
|
12610
12862
|
const MAXIMUM_WRAP_COORDINATE = 2147483647;
|
|
@@ -14956,7 +15208,7 @@ function measuredDocumentBlock({ block, element, from, to }) {
|
|
|
14956
15208
|
};
|
|
14957
15209
|
}
|
|
14958
15210
|
function shouldKeepDocumentBlockTogether(node) {
|
|
14959
|
-
return 'table' === node.type.name || 'blockquote' === node.type.name || 'codeBlock' === node.type.name || 'image' === node.type.name || 'documentNote' === node.type.name;
|
|
15211
|
+
return 'table' === node.type.name || 'blockquote' === node.type.name || 'codeBlock' === node.type.name || 'image' === node.type.name || 'documentTextBox' === node.type.name || 'documentNote' === node.type.name;
|
|
14960
15212
|
}
|
|
14961
15213
|
function documentBlockId(sectionPosition, index, position) {
|
|
14962
15214
|
return `section-${sectionPosition}-block-${index}-${position}`;
|
|
@@ -18093,6 +18345,402 @@ function work_document_table_of_contents_node_hiddenAttribute(defaultValue) {
|
|
|
18093
18345
|
function work_document_table_of_contents_node_stringAttribute(value) {
|
|
18094
18346
|
return 'string' == typeof value ? value.trim() : '';
|
|
18095
18347
|
}
|
|
18348
|
+
const DOCUMENT_TEXT_BOX_DEFAULTS = {
|
|
18349
|
+
id: '',
|
|
18350
|
+
width: 120,
|
|
18351
|
+
height: 45,
|
|
18352
|
+
layout: 'inline',
|
|
18353
|
+
horizontalOffset: null,
|
|
18354
|
+
verticalOffset: null,
|
|
18355
|
+
horizontalReference: 'column',
|
|
18356
|
+
verticalReference: 'paragraph',
|
|
18357
|
+
fill: '#fff2cc',
|
|
18358
|
+
borderColor: '#4472c4',
|
|
18359
|
+
borderWidth: 0.35,
|
|
18360
|
+
padding: 3,
|
|
18361
|
+
verticalAlign: 'top',
|
|
18362
|
+
docPropertiesId: null
|
|
18363
|
+
};
|
|
18364
|
+
const DOCUMENT_TEXT_BOX_LIMITS = {
|
|
18365
|
+
width: {
|
|
18366
|
+
min: 20,
|
|
18367
|
+
max: 558.7
|
|
18368
|
+
},
|
|
18369
|
+
height: {
|
|
18370
|
+
min: 10,
|
|
18371
|
+
max: 558.7
|
|
18372
|
+
},
|
|
18373
|
+
offset: {
|
|
18374
|
+
min: -558.7,
|
|
18375
|
+
max: 558.7
|
|
18376
|
+
},
|
|
18377
|
+
borderWidth: {
|
|
18378
|
+
min: 0,
|
|
18379
|
+
max: 10
|
|
18380
|
+
},
|
|
18381
|
+
padding: {
|
|
18382
|
+
min: 0,
|
|
18383
|
+
max: 25
|
|
18384
|
+
}
|
|
18385
|
+
};
|
|
18386
|
+
const TEXT_BOX_ID_MAX_LENGTH = 160;
|
|
18387
|
+
const TEXT_BOX_COLOR_PATTERN = /^#[0-9a-f]{6}$/i;
|
|
18388
|
+
const TEXT_BOX_MARKER_ATTRIBUTES = [
|
|
18389
|
+
'id',
|
|
18390
|
+
'width',
|
|
18391
|
+
'height',
|
|
18392
|
+
'layout',
|
|
18393
|
+
'horizontalOffset',
|
|
18394
|
+
'verticalOffset',
|
|
18395
|
+
'horizontalReference',
|
|
18396
|
+
'verticalReference',
|
|
18397
|
+
'fill',
|
|
18398
|
+
'borderColor',
|
|
18399
|
+
'borderWidth',
|
|
18400
|
+
'padding',
|
|
18401
|
+
'verticalAlign',
|
|
18402
|
+
'docPropertiesId'
|
|
18403
|
+
];
|
|
18404
|
+
const DocumentTextBox = core_Node.create({
|
|
18405
|
+
name: 'documentTextBox',
|
|
18406
|
+
group: 'block',
|
|
18407
|
+
content: 'inline*',
|
|
18408
|
+
defining: true,
|
|
18409
|
+
isolating: true,
|
|
18410
|
+
selectable: true,
|
|
18411
|
+
addAttributes () {
|
|
18412
|
+
return {
|
|
18413
|
+
id: dataAttribute(''),
|
|
18414
|
+
width: dataAttribute(DOCUMENT_TEXT_BOX_DEFAULTS.width),
|
|
18415
|
+
height: dataAttribute(DOCUMENT_TEXT_BOX_DEFAULTS.height),
|
|
18416
|
+
layout: dataAttribute(DOCUMENT_TEXT_BOX_DEFAULTS.layout),
|
|
18417
|
+
horizontalOffset: nullableDataAttribute(),
|
|
18418
|
+
verticalOffset: nullableDataAttribute(),
|
|
18419
|
+
horizontalReference: dataAttribute(DOCUMENT_TEXT_BOX_DEFAULTS.horizontalReference),
|
|
18420
|
+
verticalReference: dataAttribute(DOCUMENT_TEXT_BOX_DEFAULTS.verticalReference),
|
|
18421
|
+
fill: dataAttribute(DOCUMENT_TEXT_BOX_DEFAULTS.fill),
|
|
18422
|
+
borderColor: dataAttribute(DOCUMENT_TEXT_BOX_DEFAULTS.borderColor),
|
|
18423
|
+
borderWidth: dataAttribute(DOCUMENT_TEXT_BOX_DEFAULTS.borderWidth),
|
|
18424
|
+
padding: dataAttribute(DOCUMENT_TEXT_BOX_DEFAULTS.padding),
|
|
18425
|
+
verticalAlign: dataAttribute(DOCUMENT_TEXT_BOX_DEFAULTS.verticalAlign),
|
|
18426
|
+
docPropertiesId: nullableDataAttribute()
|
|
18427
|
+
};
|
|
18428
|
+
},
|
|
18429
|
+
parseHTML () {
|
|
18430
|
+
return [
|
|
18431
|
+
{
|
|
18432
|
+
tag: 'div[data-document-text-box]',
|
|
18433
|
+
getAttrs: (element)=>{
|
|
18434
|
+
if (!(element instanceof HTMLElement)) return false;
|
|
18435
|
+
return textBoxAttributesFromElement(element);
|
|
18436
|
+
}
|
|
18437
|
+
}
|
|
18438
|
+
];
|
|
18439
|
+
},
|
|
18440
|
+
renderHTML ({ node, HTMLAttributes }) {
|
|
18441
|
+
const properties = normalizeDocumentTextBoxProperties(node.attrs);
|
|
18442
|
+
return [
|
|
18443
|
+
'div',
|
|
18444
|
+
mergeAttributes(HTMLAttributes, textBoxDomAttributes(properties), {
|
|
18445
|
+
class: 'work-document-text-box',
|
|
18446
|
+
contenteditable: void 0,
|
|
18447
|
+
style: textBoxCss(properties),
|
|
18448
|
+
role: 'textbox',
|
|
18449
|
+
'aria-label': '文本框'
|
|
18450
|
+
}),
|
|
18451
|
+
0
|
|
18452
|
+
];
|
|
18453
|
+
},
|
|
18454
|
+
renderText ({ node }) {
|
|
18455
|
+
return node.textContent;
|
|
18456
|
+
},
|
|
18457
|
+
addCommands () {
|
|
18458
|
+
return {
|
|
18459
|
+
insertDocumentTextBox: (text = '', options = {})=>({ dispatch, editor, state, tr })=>insertDocumentTextBoxCommand({
|
|
18460
|
+
dispatch,
|
|
18461
|
+
editor,
|
|
18462
|
+
state,
|
|
18463
|
+
tr
|
|
18464
|
+
}, text, options),
|
|
18465
|
+
setDocumentTextBoxProperties: (value, options = {})=>({ chain, state, tr })=>{
|
|
18466
|
+
if (!selectedDocumentTextBox(state)) return false;
|
|
18467
|
+
const attributes = textBoxAttributesForChanges(value);
|
|
18468
|
+
if (!Object.keys(attributes).length) return false;
|
|
18469
|
+
closeHistory(tr);
|
|
18470
|
+
let commandChain = chain();
|
|
18471
|
+
if (false !== options.restoreFocus) commandChain = commandChain.focus();
|
|
18472
|
+
return commandChain.updateAttributes(this.name, attributes).run();
|
|
18473
|
+
},
|
|
18474
|
+
deleteDocumentTextBox: (options = {})=>({ dispatch, editor, state, tr })=>{
|
|
18475
|
+
const selected = selectedDocumentTextBox(state);
|
|
18476
|
+
if (!selected) return false;
|
|
18477
|
+
if (!dispatch) return true;
|
|
18478
|
+
closeHistory(tr);
|
|
18479
|
+
tr.delete(selected.position, selected.position + selected.node.nodeSize);
|
|
18480
|
+
tr.setSelection(TextSelection.near(tr.doc.resolve(Math.min(selected.position, tr.doc.content.size)), -1));
|
|
18481
|
+
dispatch(tr.scrollIntoView());
|
|
18482
|
+
if (false !== options.restoreFocus) editor.view.focus();
|
|
18483
|
+
return true;
|
|
18484
|
+
}
|
|
18485
|
+
};
|
|
18486
|
+
},
|
|
18487
|
+
addKeyboardShortcuts () {
|
|
18488
|
+
return {
|
|
18489
|
+
Backspace: ()=>deleteEmptyDocumentTextBox(this.editor),
|
|
18490
|
+
Delete: ()=>deleteEmptyDocumentTextBox(this.editor)
|
|
18491
|
+
};
|
|
18492
|
+
},
|
|
18493
|
+
addProseMirrorPlugins () {
|
|
18494
|
+
return [
|
|
18495
|
+
new Plugin({
|
|
18496
|
+
appendTransaction: (transactions, _oldState, state)=>{
|
|
18497
|
+
if (!transactions.some((transaction)=>transaction.docChanged)) return null;
|
|
18498
|
+
const seen = new Set();
|
|
18499
|
+
const updates = [];
|
|
18500
|
+
state.doc.descendants((node, position)=>{
|
|
18501
|
+
if (node.type.name !== this.name) return;
|
|
18502
|
+
const current = normalizeDocumentTextBoxId(node.attrs.id);
|
|
18503
|
+
const id = current && !seen.has(current) ? current : createWorkId('text-box');
|
|
18504
|
+
seen.add(id);
|
|
18505
|
+
if (id !== node.attrs.id) updates.push({
|
|
18506
|
+
position,
|
|
18507
|
+
id
|
|
18508
|
+
});
|
|
18509
|
+
});
|
|
18510
|
+
if (!updates.length) return null;
|
|
18511
|
+
const transaction = state.tr;
|
|
18512
|
+
for (const update of updates){
|
|
18513
|
+
const node = state.doc.nodeAt(update.position);
|
|
18514
|
+
if (node) transaction.setNodeMarkup(update.position, void 0, {
|
|
18515
|
+
...node.attrs,
|
|
18516
|
+
id: update.id
|
|
18517
|
+
});
|
|
18518
|
+
}
|
|
18519
|
+
transaction.setMeta('addToHistory', false);
|
|
18520
|
+
return transaction;
|
|
18521
|
+
}
|
|
18522
|
+
})
|
|
18523
|
+
];
|
|
18524
|
+
}
|
|
18525
|
+
});
|
|
18526
|
+
function documentTextBoxProperties(editor) {
|
|
18527
|
+
return normalizeDocumentTextBoxProperties(editor.getAttributes('documentTextBox'));
|
|
18528
|
+
}
|
|
18529
|
+
function normalizeDocumentTextBoxProperties(value) {
|
|
18530
|
+
return {
|
|
18531
|
+
id: normalizeDocumentTextBoxId(value.id),
|
|
18532
|
+
width: boundedNumber(value.width, DOCUMENT_TEXT_BOX_DEFAULTS.width, DOCUMENT_TEXT_BOX_LIMITS.width.min, DOCUMENT_TEXT_BOX_LIMITS.width.max),
|
|
18533
|
+
height: boundedNumber(value.height, DOCUMENT_TEXT_BOX_DEFAULTS.height, DOCUMENT_TEXT_BOX_LIMITS.height.min, DOCUMENT_TEXT_BOX_LIMITS.height.max),
|
|
18534
|
+
layout: 'floating' === value.layout ? 'floating' : 'inline',
|
|
18535
|
+
horizontalOffset: nullableBoundedNumber(value.horizontalOffset, DOCUMENT_TEXT_BOX_LIMITS.offset.min, DOCUMENT_TEXT_BOX_LIMITS.offset.max),
|
|
18536
|
+
verticalOffset: nullableBoundedNumber(value.verticalOffset, DOCUMENT_TEXT_BOX_LIMITS.offset.min, DOCUMENT_TEXT_BOX_LIMITS.offset.max),
|
|
18537
|
+
horizontalReference: textBoxHorizontalReference(value.horizontalReference),
|
|
18538
|
+
verticalReference: textBoxVerticalReference(value.verticalReference),
|
|
18539
|
+
fill: normalizeTextBoxFill(value.fill),
|
|
18540
|
+
borderColor: normalizeTextBoxBorderColor(value.borderColor),
|
|
18541
|
+
borderWidth: boundedNumber(value.borderWidth, DOCUMENT_TEXT_BOX_DEFAULTS.borderWidth, DOCUMENT_TEXT_BOX_LIMITS.borderWidth.min, DOCUMENT_TEXT_BOX_LIMITS.borderWidth.max),
|
|
18542
|
+
padding: boundedNumber(value.padding, DOCUMENT_TEXT_BOX_DEFAULTS.padding, DOCUMENT_TEXT_BOX_LIMITS.padding.min, DOCUMENT_TEXT_BOX_LIMITS.padding.max),
|
|
18543
|
+
verticalAlign: textBoxVerticalAlign(value.verticalAlign),
|
|
18544
|
+
docPropertiesId: nullableInteger(value.docPropertiesId, 0, 0xffffffff)
|
|
18545
|
+
};
|
|
18546
|
+
}
|
|
18547
|
+
function textBoxCss(value) {
|
|
18548
|
+
const properties = normalizeDocumentTextBoxProperties(value);
|
|
18549
|
+
return [
|
|
18550
|
+
`--work-document-text-box-width:${work_document_text_box_formatNumber(properties.width)}mm`,
|
|
18551
|
+
`--work-document-text-box-height:${work_document_text_box_formatNumber(properties.height)}mm`,
|
|
18552
|
+
`--work-document-text-box-padding:${work_document_text_box_formatNumber(properties.padding)}mm`,
|
|
18553
|
+
`--work-document-text-box-fill:${properties.fill}`,
|
|
18554
|
+
`--work-document-text-box-border-color:${'none' === properties.borderColor ? 'transparent' : properties.borderColor}`,
|
|
18555
|
+
`--work-document-text-box-border-width:${work_document_text_box_formatNumber(properties.borderWidth)}mm`,
|
|
18556
|
+
`--work-document-text-box-vertical-align:${properties.verticalAlign}`,
|
|
18557
|
+
...'floating' === properties.layout ? [
|
|
18558
|
+
`--work-document-text-box-horizontal-offset:${formatNullableNumber(properties.horizontalOffset)}mm`,
|
|
18559
|
+
`--work-document-text-box-vertical-offset:${formatNullableNumber(properties.verticalOffset)}mm`
|
|
18560
|
+
] : []
|
|
18561
|
+
].join(';');
|
|
18562
|
+
}
|
|
18563
|
+
function textBoxDomAttributes(value) {
|
|
18564
|
+
const properties = normalizeDocumentTextBoxProperties(value);
|
|
18565
|
+
return {
|
|
18566
|
+
'data-document-text-box': 'true',
|
|
18567
|
+
'data-text-box-id': properties.id || void 0,
|
|
18568
|
+
'data-text-box-width': work_document_text_box_formatNumber(properties.width),
|
|
18569
|
+
'data-text-box-height': work_document_text_box_formatNumber(properties.height),
|
|
18570
|
+
'data-text-box-layout': properties.layout,
|
|
18571
|
+
'data-text-box-horizontal-offset': null === properties.horizontalOffset ? void 0 : work_document_text_box_formatNumber(properties.horizontalOffset),
|
|
18572
|
+
'data-text-box-vertical-offset': null === properties.verticalOffset ? void 0 : work_document_text_box_formatNumber(properties.verticalOffset),
|
|
18573
|
+
'data-text-box-horizontal-reference': properties.horizontalReference,
|
|
18574
|
+
'data-text-box-vertical-reference': properties.verticalReference,
|
|
18575
|
+
'data-text-box-fill': properties.fill,
|
|
18576
|
+
'data-text-box-border-color': properties.borderColor,
|
|
18577
|
+
'data-text-box-border-width': work_document_text_box_formatNumber(properties.borderWidth),
|
|
18578
|
+
'data-text-box-padding': work_document_text_box_formatNumber(properties.padding),
|
|
18579
|
+
'data-text-box-vertical-align': properties.verticalAlign,
|
|
18580
|
+
'data-text-box-doc-properties-id': null === properties.docPropertiesId ? void 0 : String(properties.docPropertiesId)
|
|
18581
|
+
};
|
|
18582
|
+
}
|
|
18583
|
+
function insertDocumentTextBoxCommand({ dispatch, editor, state, tr }, text, options) {
|
|
18584
|
+
const section = activeDocumentSectionFromState(state);
|
|
18585
|
+
const textBoxType = editor.schema.nodes.documentTextBox;
|
|
18586
|
+
const paragraphType = editor.schema.nodes.paragraph;
|
|
18587
|
+
if (!section || !textBoxType || !paragraphType) return false;
|
|
18588
|
+
const child = work_document_text_box_activeSectionChild(section, state.selection.from);
|
|
18589
|
+
if (!child) return false;
|
|
18590
|
+
if (!dispatch) return true;
|
|
18591
|
+
const properties = normalizeDocumentTextBoxProperties({
|
|
18592
|
+
...DOCUMENT_TEXT_BOX_DEFAULTS,
|
|
18593
|
+
...options,
|
|
18594
|
+
id: options.id || createWorkId('text-box')
|
|
18595
|
+
});
|
|
18596
|
+
const content = text ? editor.schema.text(text) : void 0;
|
|
18597
|
+
const textBox = textBoxType.create(properties, content);
|
|
18598
|
+
const insertPosition = section.position + 1 + child.offset + child.nodeSize;
|
|
18599
|
+
tr.insert(insertPosition, textBox);
|
|
18600
|
+
const selectionPosition = insertPosition + 1;
|
|
18601
|
+
if (child.index === section.node.childCount - 1) {
|
|
18602
|
+
const paragraphPosition = insertPosition + textBox.nodeSize;
|
|
18603
|
+
tr.insert(paragraphPosition, paragraphType.create());
|
|
18604
|
+
}
|
|
18605
|
+
tr.setSelection(TextSelection.near(tr.doc.resolve(selectionPosition)));
|
|
18606
|
+
tr.scrollIntoView();
|
|
18607
|
+
return true;
|
|
18608
|
+
}
|
|
18609
|
+
function selectedDocumentTextBox(state) {
|
|
18610
|
+
const { $from } = state.selection;
|
|
18611
|
+
for(let depth = $from.depth; depth > 0; depth -= 1){
|
|
18612
|
+
const node = $from.node(depth);
|
|
18613
|
+
if ('documentTextBox' === node.type.name) return {
|
|
18614
|
+
node,
|
|
18615
|
+
position: $from.before(depth)
|
|
18616
|
+
};
|
|
18617
|
+
}
|
|
18618
|
+
if (state.selection instanceof NodeSelection && 'documentTextBox' === state.selection.node.type.name) return {
|
|
18619
|
+
node: state.selection.node,
|
|
18620
|
+
position: state.selection.from
|
|
18621
|
+
};
|
|
18622
|
+
return null;
|
|
18623
|
+
}
|
|
18624
|
+
function deleteEmptyDocumentTextBox(editor) {
|
|
18625
|
+
const selected = selectedDocumentTextBox(editor.state);
|
|
18626
|
+
if (!selected || selected.node.content.size > 0) return false;
|
|
18627
|
+
return editor.commands.deleteDocumentTextBox();
|
|
18628
|
+
}
|
|
18629
|
+
function textBoxAttributesForChanges(value) {
|
|
18630
|
+
const attributes = {};
|
|
18631
|
+
for (const name of TEXT_BOX_MARKER_ATTRIBUTES)if (name in value) attributes[name] = normalizeDocumentTextBoxProperties({
|
|
18632
|
+
...DOCUMENT_TEXT_BOX_DEFAULTS,
|
|
18633
|
+
...value
|
|
18634
|
+
})[name];
|
|
18635
|
+
return attributes;
|
|
18636
|
+
}
|
|
18637
|
+
function textBoxAttributesFromElement(element) {
|
|
18638
|
+
return {
|
|
18639
|
+
id: element.dataset.textBoxId ?? '',
|
|
18640
|
+
width: element.dataset.textBoxWidth,
|
|
18641
|
+
height: element.dataset.textBoxHeight,
|
|
18642
|
+
layout: element.dataset.textBoxLayout,
|
|
18643
|
+
horizontalOffset: element.dataset.textBoxHorizontalOffset,
|
|
18644
|
+
verticalOffset: element.dataset.textBoxVerticalOffset,
|
|
18645
|
+
horizontalReference: element.dataset.textBoxHorizontalReference,
|
|
18646
|
+
verticalReference: element.dataset.textBoxVerticalReference,
|
|
18647
|
+
fill: element.dataset.textBoxFill,
|
|
18648
|
+
borderColor: element.dataset.textBoxBorderColor,
|
|
18649
|
+
borderWidth: element.dataset.textBoxBorderWidth,
|
|
18650
|
+
padding: element.dataset.textBoxPadding,
|
|
18651
|
+
verticalAlign: element.dataset.textBoxVerticalAlign,
|
|
18652
|
+
docPropertiesId: element.dataset.textBoxDocPropertiesId
|
|
18653
|
+
};
|
|
18654
|
+
}
|
|
18655
|
+
function documentTextBoxPropertiesFromElement(element) {
|
|
18656
|
+
return normalizeDocumentTextBoxProperties({
|
|
18657
|
+
id: element.getAttribute('data-text-box-id'),
|
|
18658
|
+
width: element.getAttribute('data-text-box-width'),
|
|
18659
|
+
height: element.getAttribute('data-text-box-height'),
|
|
18660
|
+
layout: element.getAttribute('data-text-box-layout'),
|
|
18661
|
+
horizontalOffset: element.getAttribute('data-text-box-horizontal-offset'),
|
|
18662
|
+
verticalOffset: element.getAttribute('data-text-box-vertical-offset'),
|
|
18663
|
+
horizontalReference: element.getAttribute('data-text-box-horizontal-reference'),
|
|
18664
|
+
verticalReference: element.getAttribute('data-text-box-vertical-reference'),
|
|
18665
|
+
fill: element.getAttribute('data-text-box-fill'),
|
|
18666
|
+
borderColor: element.getAttribute('data-text-box-border-color'),
|
|
18667
|
+
borderWidth: element.getAttribute('data-text-box-border-width'),
|
|
18668
|
+
padding: element.getAttribute('data-text-box-padding'),
|
|
18669
|
+
verticalAlign: element.getAttribute('data-text-box-vertical-align'),
|
|
18670
|
+
docPropertiesId: element.getAttribute('data-text-box-doc-properties-id')
|
|
18671
|
+
});
|
|
18672
|
+
}
|
|
18673
|
+
function dataAttribute(defaultValue) {
|
|
18674
|
+
return {
|
|
18675
|
+
default: defaultValue,
|
|
18676
|
+
parseHTML: ()=>defaultValue,
|
|
18677
|
+
rendered: false
|
|
18678
|
+
};
|
|
18679
|
+
}
|
|
18680
|
+
function nullableDataAttribute() {
|
|
18681
|
+
return {
|
|
18682
|
+
default: null,
|
|
18683
|
+
parseHTML: ()=>null,
|
|
18684
|
+
rendered: false
|
|
18685
|
+
};
|
|
18686
|
+
}
|
|
18687
|
+
function normalizeDocumentTextBoxId(value) {
|
|
18688
|
+
return 'string' == typeof value ? value.trim().slice(0, TEXT_BOX_ID_MAX_LENGTH) : '';
|
|
18689
|
+
}
|
|
18690
|
+
function normalizeTextBoxFill(value) {
|
|
18691
|
+
if ('transparent' === value) return 'transparent';
|
|
18692
|
+
return normalizeTextBoxColor(value, DOCUMENT_TEXT_BOX_DEFAULTS.fill);
|
|
18693
|
+
}
|
|
18694
|
+
function normalizeTextBoxBorderColor(value) {
|
|
18695
|
+
if ('none' === value) return 'none';
|
|
18696
|
+
return normalizeTextBoxColor(value, DOCUMENT_TEXT_BOX_DEFAULTS.borderColor);
|
|
18697
|
+
}
|
|
18698
|
+
function normalizeTextBoxColor(value, fallback) {
|
|
18699
|
+
if ('string' != typeof value) return fallback;
|
|
18700
|
+
const normalized = value.trim().toLowerCase();
|
|
18701
|
+
return TEXT_BOX_COLOR_PATTERN.test(normalized) ? normalized : fallback;
|
|
18702
|
+
}
|
|
18703
|
+
function textBoxHorizontalReference(value) {
|
|
18704
|
+
return 'margin' === value || 'page' === value ? value : 'column';
|
|
18705
|
+
}
|
|
18706
|
+
function textBoxVerticalReference(value) {
|
|
18707
|
+
return 'margin' === value || 'page' === value ? value : 'paragraph';
|
|
18708
|
+
}
|
|
18709
|
+
function textBoxVerticalAlign(value) {
|
|
18710
|
+
return 'center' === value || 'bottom' === value ? value : 'top';
|
|
18711
|
+
}
|
|
18712
|
+
function boundedNumber(value, fallback, min, max) {
|
|
18713
|
+
const number = 'number' == typeof value ? value : Number(value);
|
|
18714
|
+
if (!Number.isFinite(number)) return fallback;
|
|
18715
|
+
return Number(Math.min(max, Math.max(min, number)).toFixed(2));
|
|
18716
|
+
}
|
|
18717
|
+
function nullableBoundedNumber(value, min, max) {
|
|
18718
|
+
if (null == value || '' === value) return null;
|
|
18719
|
+
return boundedNumber(value, 0, min, max);
|
|
18720
|
+
}
|
|
18721
|
+
function nullableInteger(value, min, max) {
|
|
18722
|
+
if (null == value || '' === value) return null;
|
|
18723
|
+
const number = 'number' == typeof value ? value : Number(value);
|
|
18724
|
+
return Number.isSafeInteger(number) ? Math.min(max, Math.max(min, number)) : null;
|
|
18725
|
+
}
|
|
18726
|
+
function work_document_text_box_formatNumber(value) {
|
|
18727
|
+
return Number(value.toFixed(2)).toString();
|
|
18728
|
+
}
|
|
18729
|
+
function formatNullableNumber(value) {
|
|
18730
|
+
return null === value ? '0' : work_document_text_box_formatNumber(value);
|
|
18731
|
+
}
|
|
18732
|
+
function work_document_text_box_activeSectionChild(section, selectionPosition) {
|
|
18733
|
+
const relativePosition = Math.max(0, selectionPosition - section.position - 1);
|
|
18734
|
+
let active = null;
|
|
18735
|
+
section.node.forEach((node, offset, index)=>{
|
|
18736
|
+
if (relativePosition >= offset) active = {
|
|
18737
|
+
index,
|
|
18738
|
+
offset,
|
|
18739
|
+
nodeSize: node.nodeSize
|
|
18740
|
+
};
|
|
18741
|
+
});
|
|
18742
|
+
return active;
|
|
18743
|
+
}
|
|
18096
18744
|
const BORDER_EDGES = [
|
|
18097
18745
|
'top',
|
|
18098
18746
|
'right',
|
|
@@ -20021,6 +20669,7 @@ function createWorkDocumentExtensions(options = {}) {
|
|
|
20021
20669
|
minHeight: 40
|
|
20022
20670
|
}
|
|
20023
20671
|
}),
|
|
20672
|
+
DocumentTextBox,
|
|
20024
20673
|
TableKit.configure({
|
|
20025
20674
|
table: false,
|
|
20026
20675
|
tableCell: false,
|
|
@@ -21913,7 +22562,7 @@ async function importWorkDocumentFile(file, extension, context) {
|
|
|
21913
22562
|
recordDocumentImportMeasure('a3s-office.document.mammoth', mammothStartedAt, documentImportNow());
|
|
21914
22563
|
context?.controller.report('parsing', 0.8);
|
|
21915
22564
|
const markersStartedAt = documentImportNow();
|
|
21916
|
-
html = prepared ? applyDocxSectionsToHtml(result.value, prepared.sections, prepared.captionMarkers, prepared.bookmarkMarkers, prepared.changeMarkers, prepared.commentMarkers, prepared.fieldMarkers, prepared.tableOfContentsMarkers, prepared.indexMarkers, prepared.equationMarkers, prepared.citationMarkers, prepared.listMarkers, prepared.numberingChangeMarkers, prepared.imageLayoutMarkers, prepared.paragraphIdentityMarkers, prepared.paragraphFormattingChangeMarkers, prepared.paragraphAlignmentMarkers, prepared.runFormattingMarkers, prepared.paragraphDirectionMarkers, prepared.paragraphIndentMarkers, prepared.paragraphSpacingMarkers, prepared.paragraphBorderMarkers, prepared.paragraphShadingMarkers, prepared.paragraphPaginationMarkers, prepared.bibliography, prepared.tabStopMarkers, prepared.tableCellMarkers, prepared.tableRowMarkers, prepared.tableSizingMarkers) : result.value;
|
|
22565
|
+
html = prepared ? applyDocxSectionsToHtml(result.value, prepared.sections, prepared.captionMarkers, prepared.bookmarkMarkers, prepared.changeMarkers, prepared.commentMarkers, prepared.fieldMarkers, prepared.tableOfContentsMarkers, prepared.indexMarkers, prepared.equationMarkers, prepared.citationMarkers, prepared.listMarkers, prepared.numberingChangeMarkers, prepared.imageLayoutMarkers, prepared.paragraphIdentityMarkers, prepared.paragraphFormattingChangeMarkers, prepared.paragraphAlignmentMarkers, prepared.runFormattingMarkers, prepared.paragraphDirectionMarkers, prepared.paragraphIndentMarkers, prepared.paragraphSpacingMarkers, prepared.paragraphBorderMarkers, prepared.paragraphShadingMarkers, prepared.paragraphPaginationMarkers, prepared.bibliography, prepared.tabStopMarkers, prepared.tableCellMarkers, prepared.tableRowMarkers, prepared.tableSizingMarkers, prepared.textBoxMarkers) : result.value;
|
|
21917
22566
|
recordDocumentImportMeasure('a3s-office.document.markers', markersStartedAt, documentImportNow());
|
|
21918
22567
|
const layout = prepared ? {
|
|
21919
22568
|
...documentContentLayoutProperties(prepared.sections[0].layout),
|
|
@@ -22111,4 +22760,4 @@ function registerDocumentPageSurfaceGeometry(element, provider) {
|
|
|
22111
22760
|
function documentPageSurfaceGeometryForElement(element) {
|
|
22112
22761
|
return documentPageSurfaceProviders.get(element)?.() ?? null;
|
|
22113
22762
|
}
|
|
22114
|
-
export { DEFAULT_DOCUMENT_TABLE_CELL_FORMAT, DEFAULT_DOCUMENT_TABLE_CELL_MARGINS, DEFAULT_DOCUMENT_TABLE_GEOMETRY, DOCUMENT_BOOKMARK_DUPLICATE_MESSAGE, DOCUMENT_CHUNK_HYDRATION_META, DOCUMENT_CHUNK_PAGINATION_META, DOCUMENT_CHUNK_VISIBLE_IDS_META, DOCUMENT_LEGACY_TEXT_EFFECT_NAMES, DOCUMENT_LEGACY_TEXT_EMBOSS_ATTRIBUTE, DOCUMENT_LEGACY_TEXT_IMPRINT_ATTRIBUTE, DOCUMENT_LEGACY_TEXT_OUTLINE_ATTRIBUTE, DOCUMENT_LEGACY_TEXT_SHADOW_ATTRIBUTE, DOCUMENT_OPEN_TYPE_ATTRIBUTE, DOCUMENT_PAGE_BORDER_EDGES, DOCUMENT_PAGE_MARGIN_KEYS, DOCUMENT_PARAGRAPH_CHANGE_ATTRIBUTES, DOCUMENT_PARAGRAPH_FORMAT_ATTRIBUTES, DOCUMENT_STRIKE_STYLE_ATTRIBUTE, DOCUMENT_TABLE_ROW_ID_ATTRIBUTE, DOCUMENT_TABLE_ROW_TEXT_ID_ATTRIBUTE, DOCUMENT_TABLE_STYLE_OPTIONS, DOCUMENT_UNDERLINE_STYLE_ATTRIBUTE, DocumentCharacterFormatting, DocumentEquation, DocumentFontFamily, DocumentHighlight, DocumentImage, DocumentParagraphFormatting, DocumentScriptFontFormatting, DocumentStrike, DocumentSubscript, DocumentSuperscript, DocumentTableRowIdentity, DocumentTextStyle, DocumentUnderline, MAX_DOCUMENT_IMAGE_RELATIVE_HEIGHT, MAX_DOCUMENT_NUMBERING_START, activeDocumentBookmark, activeDocumentSection, activeDocumentTableStyle, applyDocumentImageCropToElement, applyDocumentImageIdentityToElement, applyDocumentImageLayerToElement, applyDocumentImageTransformToElement, applyDocumentImageWrapContourToElement, applyDocumentPageGeometry, applyDocumentTableGeometryToElement, applyDocumentTableRowIdentityToElement, applyDocumentTextCaseStyle, canChangeDocumentIndent, canInsertDocumentComment, canSetDocumentTableRowRepeatHeader, clampDocumentMargin, collectDocumentChanges, collectDocumentCommentAnchors, collectDocumentNotes, collectDocumentTextLayoutParagraphs, createDocumentBibliography, createDocumentEquationElement, createDocumentImageIdentityRegistry, createDocumentNoteElement, createSchemaDerivedWorkDocumentModel, createWorkDocumentBlob, createWorkDocumentExtensions, createWorkDocumentModel, createWorkOfficeDocumentCollaborationBinding as createOfficeDocumentCollaborationBinding, defaultDocumentImageTransform, defaultDocumentImageWrapContour, documentAutoLineHeight, documentBookmarkNameExists, documentBookmarkReferenceInstruction, documentBulletListStyle, documentCaptionKind, documentCaptionLabel, documentCharacterPositionDomAttributes, documentCharacterPositionHalfPointsFromElement, documentCharacterPositionPoints, documentCharacterScaleDomAttributes, documentCharacterScalePercentFromElement, documentCharacterSpacingDomAttributes, documentCharacterSpacingPoints, documentCharacterSpacingTwipsFromElement, documentChunkMountedIds, documentCitationCount, documentCitationInstruction, documentCitationStyle, documentCitationStyleDetails, documentCitationTags, documentCitationTagsFromInstruction, documentCommentDraftRange, documentCommentViews, documentContentLayoutProperties, documentEmphasisMarkDomAttributes, documentEmphasisMarkFromElement, documentEquationFromElement, documentEquationText, documentHasIndex, documentHasTableOfContents, documentHiddenTextDomAttributes, documentHiddenTextFromElement, documentHiddenTextKeyboardShortcut, documentImageCropFromElement, documentImageIdentityFromElement, documentImageLayerFromElement, documentImageLayoutFromElement, documentImageLayoutOptions, documentImagePositionFromElement, documentImageProperties, documentImageTransformFromElement, documentImageWrapContourFromElement, documentInitialSectionLayout, documentKerningDomAttributes, documentKerningIsEffective, documentKerningThresholdHalfPointsFromElement, documentKerningThresholdPoints, documentLazyHtmlChunkFragment, documentLazyHtmlProjection, documentLazyHtmlProjectionFingerprint, documentLegacyTextEffectsConflict, documentLegacyTextEffectsCss, documentLegacyTextEffectsDomAttributes, documentLegacyTextEffectsFromElement, documentLegacyTextEffectsFromTextStyleAttributes, documentModelForContent, documentModelForHtml, documentModelHasTrustedInitialIntegrityFeatures, documentModelUsesWindowing, documentNoteKey, documentNoteKind, documentOpenTypeCssProperties, documentOpenTypeDomAttributes, documentOpenTypeFeaturesFromElement, documentOrderedListState, documentPageBordersVisible, documentPageChromeLegacyFields, documentPageGeometryForLayout, documentPageHorizontalMarginTwips, documentPageMarginBody, documentPageMarginsForLayout, documentPageMetrics, documentPageSurfaceGeometryForElement, documentPaperSizeForGeometry, documentParagraphDirection, documentParagraphIndent, documentParagraphPagination, documentParagraphSpacing, documentParagraphTabStops, documentSectionById, documentSectionDomAttributes, documentSections, documentStrikeDomAttributes, documentStrikeFormattingFromElement, documentStrikeStyle, documentTabLeaderLabel, documentTableBordersFromElement, documentTableCellFormat, documentTableCellMarginOverridesFromElement, documentTableColumnPercentagesFromElement, documentTableGeometryFromElement, documentTableHorizontalAlignment, documentTableRowIdentityFromElement, documentTableRowOptions, documentTableSizing, documentTextCaseFromWordFlags, documentTextCaseKeyboardShortcuts, documentTextLayoutBatches, documentTextStatistics, documentTransactionsOnlyHydrateChunks, documentUnderlineColor, documentUnderlineDomAttributes, documentUnderlineFormattingFromElement, documentUnderlineKeyboardShortcuts, documentUnderlineStyle, documentWordLineHeightFactor, docxBookmarkReferenceTarget, docxDocumentFieldKind, editorDocumentBookmarkReferenceTargets, editorDocumentCaptionTargets, fileNameWithoutExtension, forgetWorkSourceBlob as forgetSourceBlob, importWorkDocumentFile, importedDocumentCharacterFormatting, initializeWorkOfficeDocumentCollaboration as initializeOfficeDocumentCollaboration, invalidateDocumentLazyHtmlProjection, isContourImageLayout, isDocumentCharacterFormatMark, isDocumentOpenTypeFeaturePatch, isValidDocumentCitationTag, materializeLazyDocumentEditorRoot, measureDocumentLayoutBlocksIncrementally, millimetersToPixels, mountWorkLiveDocumentCapture, moveWorkSourceBlob, nextDocumentTabAlignment, normalizeDocumentBookmarkName, normalizeDocumentBookmarkNativeId, normalizeDocumentBookmarkReferencesHtml, normalizeDocumentBookmarksHtml, normalizeDocumentCaptionsHtml, normalizeDocumentCharacterPositionHalfPoints, normalizeDocumentCharacterScalePercent, normalizeDocumentCharacterSpacingTwips, normalizeDocumentCitationsHtml, normalizeDocumentColumns, normalizeDocumentEmphasisMark, normalizeDocumentEquation, normalizeDocumentFieldsHtml, normalizeDocumentHiddenText, normalizeDocumentHtml, normalizeDocumentImageAlignment, normalizeDocumentImageCrop, normalizeDocumentImageIdentity, normalizeDocumentImageLayer, normalizeDocumentImageLayoutOptions, normalizeDocumentImagePosition, normalizeDocumentImageTransform, normalizeDocumentImageWrapContour, normalizeDocumentImageWrapSide, normalizeDocumentKerningThresholdHalfPoints, normalizeDocumentLegacyTextEffect, normalizeDocumentLegacyTextEffects, normalizeDocumentNotesHtml, normalizeDocumentOpenTypeFeatures, normalizeDocumentOpenTypeLigatures, normalizeDocumentOpenTypeNumberForm, normalizeDocumentOpenTypeNumberSpacing, normalizeDocumentOpenTypeStylisticSets, normalizeDocumentPageBorders, normalizeDocumentPageChrome, normalizeDocumentPageGeometry, normalizeDocumentPageMargins, normalizeDocumentPaperSource, normalizeDocumentParagraphIndent, normalizeDocumentStrikeStyle, normalizeDocumentTabStops, normalizeDocumentTableBorderStyle, normalizeDocumentTableBorderWidth, normalizeDocumentTableRowHeightRule, normalizeDocumentTableRowIdentity, normalizeDocumentTableVerticalAlign, normalizeDocumentTextCase, normalizeDocumentUnderlineColor, normalizeDocumentUnderlineStyle, normalizeTableColor, normalizedTabPosition, numberingTypeFromFormat, pageTwipsToMillimeters, parseDocumentCharacterFormatting, parseDocumentNumberingChange, parseDocumentOpenTypeFeatures, parseDocumentParagraphFormatting, patchDocumentLazyHtmlProjection, patchDocumentOpenTypeFeatures, positionWorkLiveDocumentCapture, readWorkOfficeDocumentCollaboration as readOfficeDocumentCollaboration, readWorkSourceBlob as readSourceBlob, registerDocumentPageSurfaceGeometry, rememberWorkSourceBlob as registerSourceBlob, renderDocumentAutoLineHeight, renderDocumentTableBorders, renderDocumentTableCellMarginOverrides, resolveAllDocumentChanges, resolveDocumentPageBorders, resolveDocumentPageChrome, resolveDocumentPageMargins, resolveDocumentPageSize, resolveWorkDocumentEditorInput, retainAnchoredDocumentComments, sanitizeDocumentPageChromeHtml, selectedDocumentChunkId, selectedDocumentIndexDraft, selectedDocumentIndexEntry, selectedDocumentIndexOptions, selectedDocumentTableOfContentsOptions, serializeDocumentCharacterFormatting, serializeDocumentNumberingChange, serializeDocumentOpenTypeFeatures, serializeDocumentParagraphFormatting, serializeDocumentTabStops, serializeWorkDocumentNode, setCustomDocumentColumns, supportedDocxBookmarkReferenceInstruction, syncDocumentContentFromHtml, transferChangedDocumentTextStatistics, uniqueDocumentImageIdentity, updateDocumentColumnWidth, updateDocumentCustomPageMillimeters, updateDocumentGutterPosition, updateDocumentMirrorMargins, updateDocumentPageChromeVariant, updateDocumentPageMarginMillimeters, updateDocumentPageMarginMode, updateDocumentPageOrientation, updateDocumentPaperSizePreset, validateDocumentBookmarkName, windowDocumentModel, workDocumentSchema, workOfficeDocumentCollaborationFragment as officeDocumentCollaborationFragment, work_document_model_codec_createWorkDocumentModelFromContent as createWorkDocumentModelFromContent, work_document_model_codec_materializeWorkDocumentContent as materializeWorkDocumentContent, work_document_model_createSchemaValidatedWorkDocumentModel as createSchemaValidatedWorkDocumentModel, work_document_page_margins_twipsToMillimeters, work_file_download_downloadBlob, work_file_download_safeFileName, wrapsBesideImage };
|
|
22763
|
+
export { DEFAULT_DOCUMENT_TABLE_CELL_FORMAT, DEFAULT_DOCUMENT_TABLE_CELL_MARGINS, DEFAULT_DOCUMENT_TABLE_GEOMETRY, DOCUMENT_BOOKMARK_DUPLICATE_MESSAGE, DOCUMENT_CHUNK_HYDRATION_META, DOCUMENT_CHUNK_PAGINATION_META, DOCUMENT_CHUNK_VISIBLE_IDS_META, DOCUMENT_LEGACY_TEXT_EFFECT_NAMES, DOCUMENT_LEGACY_TEXT_EMBOSS_ATTRIBUTE, DOCUMENT_LEGACY_TEXT_IMPRINT_ATTRIBUTE, DOCUMENT_LEGACY_TEXT_OUTLINE_ATTRIBUTE, DOCUMENT_LEGACY_TEXT_SHADOW_ATTRIBUTE, DOCUMENT_OPEN_TYPE_ATTRIBUTE, DOCUMENT_PAGE_BORDER_EDGES, DOCUMENT_PAGE_MARGIN_KEYS, DOCUMENT_PARAGRAPH_CHANGE_ATTRIBUTES, DOCUMENT_PARAGRAPH_FORMAT_ATTRIBUTES, DOCUMENT_STRIKE_STYLE_ATTRIBUTE, DOCUMENT_TABLE_ROW_ID_ATTRIBUTE, DOCUMENT_TABLE_ROW_TEXT_ID_ATTRIBUTE, DOCUMENT_TABLE_STYLE_OPTIONS, DOCUMENT_TEXT_BOX_DEFAULTS, DOCUMENT_TEXT_BOX_LIMITS, DOCUMENT_UNDERLINE_STYLE_ATTRIBUTE, DocumentCharacterFormatting, DocumentEquation, DocumentFontFamily, DocumentHighlight, DocumentImage, DocumentParagraphFormatting, DocumentScriptFontFormatting, DocumentStrike, DocumentSubscript, DocumentSuperscript, DocumentTableRowIdentity, DocumentTextStyle, DocumentUnderline, MAX_DOCUMENT_IMAGE_RELATIVE_HEIGHT, MAX_DOCUMENT_NUMBERING_START, activeDocumentBookmark, activeDocumentSection, activeDocumentTableStyle, applyDocumentImageCropToElement, applyDocumentImageIdentityToElement, applyDocumentImageLayerToElement, applyDocumentImageTransformToElement, applyDocumentImageWrapContourToElement, applyDocumentPageGeometry, applyDocumentTableGeometryToElement, applyDocumentTableRowIdentityToElement, applyDocumentTextCaseStyle, canChangeDocumentIndent, canInsertDocumentComment, canSetDocumentTableRowRepeatHeader, clampDocumentMargin, collectDocumentChanges, collectDocumentCommentAnchors, collectDocumentNotes, collectDocumentTextLayoutParagraphs, createDocumentBibliography, createDocumentEquationElement, createDocumentImageIdentityRegistry, createDocumentNoteElement, createSchemaDerivedWorkDocumentModel, createWorkDocumentBlob, createWorkDocumentExtensions, createWorkDocumentModel, createWorkOfficeDocumentCollaborationBinding as createOfficeDocumentCollaborationBinding, defaultDocumentImageTransform, defaultDocumentImageWrapContour, documentAutoLineHeight, documentBookmarkNameExists, documentBookmarkReferenceInstruction, documentBulletListStyle, documentCaptionKind, documentCaptionLabel, documentCharacterPositionDomAttributes, documentCharacterPositionHalfPointsFromElement, documentCharacterPositionPoints, documentCharacterScaleDomAttributes, documentCharacterScalePercentFromElement, documentCharacterSpacingDomAttributes, documentCharacterSpacingPoints, documentCharacterSpacingTwipsFromElement, documentChunkMountedIds, documentCitationCount, documentCitationInstruction, documentCitationStyle, documentCitationStyleDetails, documentCitationTags, documentCitationTagsFromInstruction, documentCommentDraftRange, documentCommentViews, documentContentLayoutProperties, documentEmphasisMarkDomAttributes, documentEmphasisMarkFromElement, documentEquationFromElement, documentEquationText, documentHasIndex, documentHasTableOfContents, documentHiddenTextDomAttributes, documentHiddenTextFromElement, documentHiddenTextKeyboardShortcut, documentImageCropFromElement, documentImageIdentityFromElement, documentImageLayerFromElement, documentImageLayoutFromElement, documentImageLayoutOptions, documentImagePositionFromElement, documentImageProperties, documentImageTransformFromElement, documentImageWrapContourFromElement, documentInitialSectionLayout, documentKerningDomAttributes, documentKerningIsEffective, documentKerningThresholdHalfPointsFromElement, documentKerningThresholdPoints, documentLazyHtmlChunkFragment, documentLazyHtmlProjection, documentLazyHtmlProjectionFingerprint, documentLegacyTextEffectsConflict, documentLegacyTextEffectsCss, documentLegacyTextEffectsDomAttributes, documentLegacyTextEffectsFromElement, documentLegacyTextEffectsFromTextStyleAttributes, documentModelForContent, documentModelForHtml, documentModelHasTrustedInitialIntegrityFeatures, documentModelUsesWindowing, documentNoteKey, documentNoteKind, documentOpenTypeCssProperties, documentOpenTypeDomAttributes, documentOpenTypeFeaturesFromElement, documentOrderedListState, documentPageBordersVisible, documentPageChromeLegacyFields, documentPageGeometryForLayout, documentPageHorizontalMarginTwips, documentPageMarginBody, documentPageMarginsForLayout, documentPageMetrics, documentPageSurfaceGeometryForElement, documentPaperSizeForGeometry, documentParagraphDirection, documentParagraphIndent, documentParagraphPagination, documentParagraphSpacing, documentParagraphTabStops, documentSectionById, documentSectionDomAttributes, documentSections, documentStrikeDomAttributes, documentStrikeFormattingFromElement, documentStrikeStyle, documentTabLeaderLabel, documentTableBordersFromElement, documentTableCellFormat, documentTableCellMarginOverridesFromElement, documentTableColumnPercentagesFromElement, documentTableGeometryFromElement, documentTableHorizontalAlignment, documentTableRowIdentityFromElement, documentTableRowOptions, documentTableSizing, documentTextBoxProperties, documentTextBoxPropertiesFromElement, documentTextCaseFromWordFlags, documentTextCaseKeyboardShortcuts, documentTextLayoutBatches, documentTextStatistics, documentTransactionsOnlyHydrateChunks, documentUnderlineColor, documentUnderlineDomAttributes, documentUnderlineFormattingFromElement, documentUnderlineKeyboardShortcuts, documentUnderlineStyle, documentWordLineHeightFactor, docxBookmarkReferenceTarget, docxDocumentFieldKind, docxDocumentFieldTarget, editorDocumentBookmarkReferenceTargets, editorDocumentCaptionTargets, fileNameWithoutExtension, forgetWorkSourceBlob as forgetSourceBlob, importWorkDocumentFile, importedDocumentCharacterFormatting, initializeWorkOfficeDocumentCollaboration as initializeOfficeDocumentCollaboration, invalidateDocumentLazyHtmlProjection, isContourImageLayout, isDocumentCharacterFormatMark, isDocumentOpenTypeFeaturePatch, isValidDocumentCitationTag, materializeLazyDocumentEditorRoot, measureDocumentLayoutBlocksIncrementally, millimetersToPixels, mountWorkLiveDocumentCapture, moveWorkSourceBlob, nextDocumentTabAlignment, normalizeDocumentBookmarkName, normalizeDocumentBookmarkNativeId, normalizeDocumentBookmarkReferencesHtml, normalizeDocumentBookmarksHtml, normalizeDocumentCaptionsHtml, normalizeDocumentCharacterPositionHalfPoints, normalizeDocumentCharacterScalePercent, normalizeDocumentCharacterSpacingTwips, normalizeDocumentCitationsHtml, normalizeDocumentColumns, normalizeDocumentEmphasisMark, normalizeDocumentEquation, normalizeDocumentFieldsHtml, normalizeDocumentHiddenText, normalizeDocumentHtml, normalizeDocumentImageAlignment, normalizeDocumentImageCrop, normalizeDocumentImageIdentity, normalizeDocumentImageLayer, normalizeDocumentImageLayoutOptions, normalizeDocumentImagePosition, normalizeDocumentImageTransform, normalizeDocumentImageWrapContour, normalizeDocumentImageWrapSide, normalizeDocumentKerningThresholdHalfPoints, normalizeDocumentLegacyTextEffect, normalizeDocumentLegacyTextEffects, normalizeDocumentNotesHtml, normalizeDocumentOpenTypeFeatures, normalizeDocumentOpenTypeLigatures, normalizeDocumentOpenTypeNumberForm, normalizeDocumentOpenTypeNumberSpacing, normalizeDocumentOpenTypeStylisticSets, normalizeDocumentPageBorders, normalizeDocumentPageChrome, normalizeDocumentPageGeometry, normalizeDocumentPageMargins, normalizeDocumentPaperSource, normalizeDocumentParagraphIndent, normalizeDocumentStrikeStyle, normalizeDocumentTabStops, normalizeDocumentTableBorderStyle, normalizeDocumentTableBorderWidth, normalizeDocumentTableRowHeightRule, normalizeDocumentTableRowIdentity, normalizeDocumentTableVerticalAlign, normalizeDocumentTextBoxProperties, normalizeDocumentTextCase, normalizeDocumentUnderlineColor, normalizeDocumentUnderlineStyle, normalizeTableColor, normalizedTabPosition, numberingTypeFromFormat, pageTwipsToMillimeters, parseDocumentCharacterFormatting, parseDocumentNumberingChange, parseDocumentOpenTypeFeatures, parseDocumentParagraphFormatting, patchDocumentLazyHtmlProjection, patchDocumentOpenTypeFeatures, positionWorkLiveDocumentCapture, readWorkOfficeDocumentCollaboration as readOfficeDocumentCollaboration, readWorkSourceBlob as readSourceBlob, registerDocumentPageSurfaceGeometry, rememberWorkSourceBlob as registerSourceBlob, renderDocumentAutoLineHeight, renderDocumentTableBorders, renderDocumentTableCellMarginOverrides, resolveAllDocumentChanges, resolveDocumentPageBorders, resolveDocumentPageChrome, resolveDocumentPageMargins, resolveDocumentPageSize, resolveWorkDocumentEditorInput, retainAnchoredDocumentComments, sanitizeDocumentPageChromeHtml, selectedDocumentChunkId, selectedDocumentIndexDraft, selectedDocumentIndexEntry, selectedDocumentIndexOptions, selectedDocumentTableOfContentsOptions, serializeDocumentCharacterFormatting, serializeDocumentNumberingChange, serializeDocumentOpenTypeFeatures, serializeDocumentParagraphFormatting, serializeDocumentTabStops, serializeWorkDocumentNode, setCustomDocumentColumns, supportedDocxBookmarkReferenceInstruction, supportedDocxDocumentFieldInstruction, syncDocumentContentFromHtml, textBoxCss, textBoxDomAttributes, transferChangedDocumentTextStatistics, uniqueDocumentImageIdentity, updateDocumentColumnWidth, updateDocumentCustomPageMillimeters, updateDocumentGutterPosition, updateDocumentMirrorMargins, updateDocumentPageChromeVariant, updateDocumentPageMarginMillimeters, updateDocumentPageMarginMode, updateDocumentPageOrientation, updateDocumentPaperSizePreset, validateDocumentBookmarkName, windowDocumentModel, workDocumentSchema, workOfficeDocumentCollaborationFragment as officeDocumentCollaborationFragment, work_document_model_codec_createWorkDocumentModelFromContent as createWorkDocumentModelFromContent, work_document_model_codec_materializeWorkDocumentContent as materializeWorkDocumentContent, work_document_model_createSchemaValidatedWorkDocumentModel as createSchemaValidatedWorkDocumentModel, work_document_page_margins_twipsToMillimeters, work_file_download_downloadBlob, work_file_download_safeFileName, wrapsBesideImage };
|