@a3s-lab/office 0.46.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 +11 -0
- package/dist/0~2133.js +748 -748
- package/dist/0~document-editor.js +3877 -3847
- package/dist/0~work-docx-export.js +2 -2
- package/dist/0~work-docx-import.js +41 -5
- package/dist/0~work-office-diagnostics.js +21 -6
- package/dist/4174.js +1817 -1565
- 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-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 +1 -1
- package/package.json +1 -1
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;
|
|
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
|
+
};
|
|
310
231
|
}
|
|
311
|
-
function
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
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;
|
|
315
244
|
}
|
|
316
|
-
function
|
|
317
|
-
|
|
318
|
-
const number = 'number' == typeof value ? value : Number(value);
|
|
319
|
-
return Number.isSafeInteger(number) && number >= 0 && number <= MAX_BOOKMARK_NATIVE_ID ? number : null;
|
|
245
|
+
function documentHtmlFingerprintForSegment(segment) {
|
|
246
|
+
return `${DOCUMENT_HTML_FINGERPRINT_VERSION}:${segment.length.toString(36)}:${segment.hash.toString(36)}`;
|
|
320
247
|
}
|
|
321
|
-
function
|
|
322
|
-
return
|
|
323
|
-
id,
|
|
324
|
-
name,
|
|
325
|
-
nativeId,
|
|
326
|
-
from,
|
|
327
|
-
to
|
|
328
|
-
}));
|
|
248
|
+
function documentHtmlFingerprint(html) {
|
|
249
|
+
return documentHtmlFingerprintForSegment(createDocumentHtmlFingerprintSegment(html));
|
|
329
250
|
}
|
|
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
|
-
});
|
|
251
|
+
function documentHtmlFingerprintMatches(html, candidate) {
|
|
252
|
+
return candidate.startsWith(`${DOCUMENT_HTML_FINGERPRINT_VERSION}:`) ? candidate === documentHtmlFingerprint(html) : candidate === legacyDocumentHtmlFingerprint(html);
|
|
342
253
|
}
|
|
343
|
-
function
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
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);
|
|
259
|
+
}
|
|
260
|
+
return `${html.length.toString(36)}:${(hash >>> 0).toString(36)}`;
|
|
347
261
|
}
|
|
348
|
-
function
|
|
349
|
-
|
|
350
|
-
|
|
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;
|
|
351
272
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
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;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
const range = {
|
|
300
|
+
from,
|
|
301
|
+
id,
|
|
302
|
+
tablePart,
|
|
303
|
+
to: cursor
|
|
362
304
|
};
|
|
363
|
-
|
|
364
|
-
|
|
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);
|
|
305
|
+
orderedRanges.push(range);
|
|
306
|
+
ranges.set(id, range);
|
|
367
307
|
}
|
|
368
|
-
|
|
369
|
-
return
|
|
308
|
+
if (cursor !== html.length - SECTION_CLOSE.length) return null;
|
|
309
|
+
return {
|
|
310
|
+
html,
|
|
311
|
+
orderedRanges,
|
|
312
|
+
ranges
|
|
313
|
+
};
|
|
370
314
|
}
|
|
371
|
-
function
|
|
372
|
-
|
|
373
|
-
const
|
|
374
|
-
const
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
const
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
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;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
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;
|
|
398
352
|
}
|
|
399
|
-
function
|
|
400
|
-
|
|
401
|
-
if (!bookmark) return false;
|
|
402
|
-
if (!dispatch) return true;
|
|
403
|
-
tr.delete(bookmark.to, bookmark.to + bookmark.end.node.nodeSize);
|
|
404
|
-
tr.delete(bookmark.from, bookmark.from + bookmark.start.node.nodeSize);
|
|
405
|
-
tr.setSelection(TextSelection.near(tr.doc.resolve(bookmark.from)));
|
|
406
|
-
dispatch(tr.scrollIntoView());
|
|
407
|
-
return true;
|
|
353
|
+
function documentLazyHtmlProjectionFingerprint(projection) {
|
|
354
|
+
return projectionFingerprints.get(projection)?.fingerprint ?? null;
|
|
408
355
|
}
|
|
409
|
-
function
|
|
410
|
-
return
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
},
|
|
419
|
-
appendTransaction (transactions, oldState, newState) {
|
|
420
|
-
if (!transactions.some((transaction)=>transaction.docChanged)) return null;
|
|
421
|
-
return normalizeDocumentBookmarks(newState, boundaryNodeName, oldState, transactions);
|
|
422
|
-
}
|
|
423
|
-
});
|
|
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);
|
|
424
365
|
}
|
|
425
|
-
function
|
|
426
|
-
|
|
427
|
-
const
|
|
428
|
-
|
|
429
|
-
const ordered = [
|
|
430
|
-
...collection.pairs.filter((pair)=>retained.has(pairPositionKey(pair))),
|
|
431
|
-
...collection.pairs.filter((pair)=>!retained.has(pairPositionKey(pair)))
|
|
366
|
+
function lazyDocumentLeafChunks(root) {
|
|
367
|
+
const chunks = [];
|
|
368
|
+
const pending = [
|
|
369
|
+
root
|
|
432
370
|
];
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
if (
|
|
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
|
-
});
|
|
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);
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
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);
|
|
450
381
|
}
|
|
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
|
-
});
|
|
463
382
|
}
|
|
464
|
-
|
|
465
|
-
synchronizeDocumentBookmarkReferenceNodes(state, tr, effectivePairs, renames);
|
|
466
|
-
for (const orphan of [
|
|
467
|
-
...collection.orphans
|
|
468
|
-
].sort((left, right)=>right.position - left.position))tr.delete(orphan.position, orphan.position + orphan.node.nodeSize);
|
|
469
|
-
return tr.docChanged ? tr : null;
|
|
383
|
+
return chunks;
|
|
470
384
|
}
|
|
471
|
-
function
|
|
472
|
-
const
|
|
473
|
-
|
|
474
|
-
const
|
|
475
|
-
const
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
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
|
|
407
|
+
};
|
|
408
|
+
projectionFingerprints.set(projection, state);
|
|
409
|
+
return state;
|
|
410
|
+
}
|
|
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
|
+
};
|
|
480
419
|
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
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;
|
|
491
430
|
}
|
|
492
|
-
|
|
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
|
+
};
|
|
493
446
|
}
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
if (
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
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);
|
|
476
|
+
}
|
|
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
|
|
483
|
+
};
|
|
484
|
+
recordLazyDocumentMeasure('a3s-office.document.lazy-editor-source', startedAt, lazyDocumentNow(), {
|
|
485
|
+
cacheHit
|
|
515
486
|
});
|
|
487
|
+
return result;
|
|
516
488
|
}
|
|
517
|
-
function
|
|
518
|
-
|
|
519
|
-
tr.addMark(position, position + node.nodeSize, link.type.create(attributes));
|
|
489
|
+
function documentLazyHtmlProjection(model) {
|
|
490
|
+
return model ? preparedModels.get(model)?.htmlProjection ?? null : null;
|
|
520
491
|
}
|
|
521
|
-
function
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
const orphans = [];
|
|
526
|
-
for (const boundary of boundaries){
|
|
527
|
-
const key = bookmarkBoundaryPairKey(boundary.node.attrs);
|
|
528
|
-
if ('start' === boundary.kind) {
|
|
529
|
-
const stack = open.get(key) ?? [];
|
|
530
|
-
stack.push(boundary);
|
|
531
|
-
open.set(key, stack);
|
|
532
|
-
continue;
|
|
533
|
-
}
|
|
534
|
-
const stack = open.get(key);
|
|
535
|
-
const start = stack?.pop();
|
|
536
|
-
if (!start) {
|
|
537
|
-
orphans.push(boundary);
|
|
538
|
-
continue;
|
|
539
|
-
}
|
|
540
|
-
pairs.push(bookmarkPair(start, boundary));
|
|
492
|
+
function invalidateDocumentLazyHtmlProjection(model) {
|
|
493
|
+
if (model) {
|
|
494
|
+
const prepared = preparedModels.get(model);
|
|
495
|
+
if (prepared) prepared.htmlProjection = null;
|
|
541
496
|
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
return
|
|
545
|
-
|
|
546
|
-
|
|
497
|
+
}
|
|
498
|
+
function documentLazyChunkContent(model, chunkId) {
|
|
499
|
+
if (!model || !chunkId) return null;
|
|
500
|
+
return preparedModels.get(model)?.payloads.get(chunkId) ?? null;
|
|
501
|
+
}
|
|
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;
|
|
547
533
|
};
|
|
534
|
+
return visit(root);
|
|
548
535
|
}
|
|
549
|
-
function
|
|
550
|
-
if (!
|
|
551
|
-
const
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
});
|
|
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
|
|
559
545
|
});
|
|
560
|
-
return boundaries;
|
|
561
|
-
}
|
|
562
|
-
function bookmarkPair(start, end) {
|
|
563
|
-
return {
|
|
564
|
-
id: bookmarkInternalId(start.node.attrs.id),
|
|
565
|
-
name: normalizeDocumentBookmarkName(start.node.attrs.name) ?? '',
|
|
566
|
-
nativeId: normalizeDocumentBookmarkNativeId(start.node.attrs.nativeId) ?? -1,
|
|
567
|
-
from: start.position,
|
|
568
|
-
to: end.position,
|
|
569
|
-
start,
|
|
570
|
-
end
|
|
571
|
-
};
|
|
572
546
|
}
|
|
573
|
-
function
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
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;
|
|
578
555
|
}
|
|
579
|
-
return
|
|
556
|
+
return size;
|
|
580
557
|
}
|
|
581
|
-
function
|
|
582
|
-
const
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
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
|
|
592
607
|
};
|
|
593
|
-
reserveBookmarkIdentity(identity, registry);
|
|
594
|
-
return identity;
|
|
595
|
-
}
|
|
596
|
-
function bookmarkIdentity(source) {
|
|
597
|
-
const id = bookmarkInternalId(source.id);
|
|
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;
|
|
605
|
-
}
|
|
606
|
-
function bookmarkIdentityConflicts(identity, registry) {
|
|
607
|
-
return registry.ids.has(identity.id) || registry.names.has(identity.name.toLowerCase()) || registry.nativeIds.has(identity.nativeId);
|
|
608
|
-
}
|
|
609
|
-
function reserveBookmarkIdentity(identity, registry) {
|
|
610
|
-
registry.ids.add(identity.id);
|
|
611
|
-
registry.names.add(identity.name.toLowerCase());
|
|
612
|
-
registry.nativeIds.add(identity.nativeId);
|
|
613
608
|
}
|
|
614
|
-
function
|
|
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('');
|
|
615
620
|
return {
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
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
|
+
}
|
|
619
637
|
};
|
|
620
638
|
}
|
|
621
|
-
function
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
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;
|
|
625
645
|
}
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
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;
|
|
629
653
|
}
|
|
630
|
-
function
|
|
631
|
-
|
|
632
|
-
let suffix = 2;
|
|
633
|
-
while(suffix <= MAX_BOOKMARK_NATIVE_ID){
|
|
634
|
-
const ending = `_${suffix}`;
|
|
635
|
-
const prefix = Array.from(base).slice(0, MAX_BOOKMARK_NAME_LENGTH - ending.length).join('');
|
|
636
|
-
const candidate = `${prefix}${ending}`;
|
|
637
|
-
if (!names.has(candidate.toLowerCase())) return candidate;
|
|
638
|
-
suffix += 1;
|
|
639
|
-
}
|
|
640
|
-
throw new Error('No unique Word bookmark name is available.');
|
|
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;
|
|
641
656
|
}
|
|
642
|
-
function
|
|
643
|
-
|
|
644
|
-
|
|
657
|
+
function documentChunkId(node) {
|
|
658
|
+
const id = node.attrs?.id;
|
|
659
|
+
return 'string' == typeof id && id ? id : null;
|
|
645
660
|
}
|
|
646
|
-
function
|
|
647
|
-
return
|
|
661
|
+
function lazyDocumentNow() {
|
|
662
|
+
return globalThis.performance?.now?.() ?? Date.now();
|
|
648
663
|
}
|
|
649
|
-
function
|
|
650
|
-
|
|
664
|
+
function recordLazyDocumentMeasure(name, start, end, detail) {
|
|
665
|
+
try {
|
|
666
|
+
globalThis.performance?.measure(name, {
|
|
667
|
+
detail,
|
|
668
|
+
end,
|
|
669
|
+
start
|
|
670
|
+
});
|
|
671
|
+
} catch {}
|
|
651
672
|
}
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
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;
|
|
683
|
+
continue;
|
|
684
|
+
}
|
|
685
|
+
inAsciiWord = false;
|
|
686
|
+
if (!(code <= 0x7f) && 0xfffc !== code) return unicodeDocumentWordCount(value);
|
|
687
|
+
}
|
|
688
|
+
return asciiCount;
|
|
656
689
|
}
|
|
657
|
-
function
|
|
658
|
-
|
|
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
|
+
}
|
|
712
|
+
}
|
|
713
|
+
}
|
|
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)
|
|
729
|
+
};
|
|
730
|
+
statisticsByDocument.set(document1, statistics);
|
|
731
|
+
return statistics;
|
|
659
732
|
}
|
|
660
|
-
function
|
|
661
|
-
const
|
|
662
|
-
|
|
663
|
-
return mapping;
|
|
733
|
+
function transferDocumentTextStatistics(previous, next) {
|
|
734
|
+
const statistics = statisticsByDocument.get(previous);
|
|
735
|
+
if (statistics) statisticsByDocument.set(next, statistics);
|
|
664
736
|
}
|
|
665
|
-
function
|
|
666
|
-
|
|
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;
|
|
667
750
|
}
|
|
668
|
-
function
|
|
669
|
-
const
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
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;
|
|
679
764
|
}
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
765
|
+
if (node.isTextblock) {
|
|
766
|
+
accumulateDocumentTextStatistics(statistics, node.textContent);
|
|
767
|
+
statistics.paragraphCount += 1;
|
|
768
|
+
return;
|
|
684
769
|
}
|
|
685
|
-
|
|
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
|
-
}
|
|
693
|
-
for (const stack of open.values())orphans.push(...stack);
|
|
694
|
-
return {
|
|
695
|
-
pairs,
|
|
696
|
-
orphans
|
|
770
|
+
node.forEach(visit);
|
|
697
771
|
};
|
|
772
|
+
visit(root);
|
|
773
|
+
return statistics;
|
|
698
774
|
}
|
|
699
|
-
function
|
|
700
|
-
|
|
701
|
-
|
|
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
|
+
}
|
|
785
|
+
}
|
|
786
|
+
statistics.wordCount += documentWordCount(source);
|
|
702
787
|
}
|
|
703
|
-
function
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
element.dataset.officeBookmarkId = String(identity.nativeId);
|
|
709
|
-
element.classList.add('work-document-bookmark-boundary', kind);
|
|
710
|
-
element.contentEditable = 'false';
|
|
711
|
-
element.setAttribute('aria-hidden', 'true');
|
|
712
|
-
if ('start' === kind) element.id = identity.name;
|
|
713
|
-
else element.removeAttribute('id');
|
|
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;
|
|
714
793
|
}
|
|
715
|
-
function
|
|
716
|
-
|
|
717
|
-
const target = (link.getAttribute('href') ?? '').slice(1).toLowerCase();
|
|
718
|
-
link.classList.toggle(MISSING_LINK_CLASS, !names.has(target));
|
|
719
|
-
if (!link.className) link.removeAttribute('class');
|
|
720
|
-
}
|
|
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;
|
|
721
796
|
}
|
|
722
|
-
|
|
723
|
-
|
|
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;
|
|
724
824
|
}
|
|
725
|
-
function
|
|
726
|
-
const
|
|
727
|
-
if (
|
|
728
|
-
|
|
729
|
-
|
|
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;
|
|
730
837
|
}
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
const document1 = new DOMParser().parseFromString(source, 'text/html');
|
|
735
|
-
const targets = normalizeCaptions(document1);
|
|
736
|
-
normalizeReferences(document1, new Map(targets.map((target)=>[
|
|
737
|
-
target.id,
|
|
738
|
-
target
|
|
739
|
-
])));
|
|
740
|
-
return document1.body.innerHTML;
|
|
838
|
+
function documentFieldInstruction(kind, options = {}) {
|
|
839
|
+
if ('pageReference' === kind) return documentPageReferenceInstruction(options.targetName, '', true);
|
|
840
|
+
return FIELD_COMMANDS[kind];
|
|
741
841
|
}
|
|
742
|
-
function
|
|
743
|
-
|
|
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(' ')}` : ''}`;
|
|
744
850
|
}
|
|
745
|
-
function
|
|
746
|
-
return
|
|
851
|
+
function documentFieldLabel(kind) {
|
|
852
|
+
return FIELD_LABELS[kind];
|
|
747
853
|
}
|
|
748
|
-
function
|
|
749
|
-
|
|
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);
|
|
750
871
|
}
|
|
751
|
-
function
|
|
752
|
-
const
|
|
753
|
-
figure: 0,
|
|
754
|
-
table: 0
|
|
755
|
-
};
|
|
872
|
+
function normalizeDocumentFieldsHtml(source) {
|
|
873
|
+
const document1 = new DOMParser().parseFromString(source, 'text/html');
|
|
756
874
|
const usedIds = new Set();
|
|
757
|
-
|
|
758
|
-
const
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
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
|
-
});
|
|
781
|
-
}
|
|
782
|
-
function normalizeReferences(document1, targets) {
|
|
783
|
-
for (const element of Array.from(document1.body.querySelectorAll(REFERENCE_SELECTOR))){
|
|
784
|
-
if ('bookmark' === element.dataset.referenceTargetType) continue;
|
|
785
|
-
const id = element.dataset.referenceTargetId?.trim() ?? '';
|
|
786
|
-
const target = targets.get(id);
|
|
787
|
-
element.dataset.documentCrossReference = 'true';
|
|
788
|
-
element.dataset.referenceTargetId = id;
|
|
789
|
-
element.classList.add('work-document-cross-reference');
|
|
790
|
-
if (!target) {
|
|
791
|
-
element.dataset.referenceOrphaned = 'true';
|
|
792
|
-
element.textContent = '引用缺失';
|
|
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;
|
|
901
|
+
}
|
|
902
|
+
return document1.body.innerHTML;
|
|
903
|
+
}
|
|
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;
|
|
800
916
|
}
|
|
917
|
+
return document1.body.innerHTML;
|
|
801
918
|
}
|
|
802
|
-
function
|
|
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
|
}
|
|
814
|
-
function
|
|
815
|
-
|
|
816
|
-
return Number.isSafeInteger(number) && number > 0 ? number : 1;
|
|
931
|
+
function dateFormatSwitch(instruction) {
|
|
932
|
+
return /\\@\s+"([^"]+)"/i.exec(instruction)?.[1] ?? null;
|
|
817
933
|
}
|
|
818
|
-
|
|
819
|
-
const
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
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
|
+
}
|
|
836
977
|
}
|
|
837
|
-
};
|
|
838
|
-
function createDocumentBibliography(style = 'apa') {
|
|
839
978
|
return {
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
selectedStyle: STYLE_DETAILS[style].selectedStyle,
|
|
843
|
-
sources: []
|
|
979
|
+
wordCount: documentWordCount(normalized),
|
|
980
|
+
characterCount
|
|
844
981
|
};
|
|
845
982
|
}
|
|
846
|
-
function
|
|
847
|
-
|
|
848
|
-
|
|
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 ?? '');
|
|
849
987
|
}
|
|
850
|
-
function
|
|
851
|
-
|
|
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);
|
|
852
1021
|
}
|
|
853
|
-
function
|
|
854
|
-
|
|
855
|
-
if (!primary) return [];
|
|
856
|
-
const tags = [
|
|
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);
|
|
1022
|
+
function positiveInteger(value) {
|
|
1023
|
+
return Number.isSafeInteger(value) && value > 0 ? value : 1;
|
|
862
1024
|
}
|
|
863
|
-
function
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
return
|
|
867
|
-
'CITATION',
|
|
868
|
-
citationTagInstructionValue(normalized[0]),
|
|
869
|
-
...normalized.slice(1).flatMap((tag)=>[
|
|
870
|
-
'\\m',
|
|
871
|
-
citationTagInstructionValue(tag)
|
|
872
|
-
]),
|
|
873
|
-
'\\l',
|
|
874
|
-
'2052'
|
|
875
|
-
].join(' ');
|
|
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;
|
|
876
1029
|
}
|
|
877
|
-
function
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
});
|
|
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;
|
|
882
1034
|
}
|
|
883
|
-
function
|
|
884
|
-
return
|
|
1035
|
+
function validDate(value) {
|
|
1036
|
+
return value && Number.isFinite(value.getTime()) ? value : null;
|
|
885
1037
|
}
|
|
886
|
-
|
|
887
|
-
|
|
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
|
+
};
|
|
1056
|
+
},
|
|
1057
|
+
addProseMirrorPlugins () {
|
|
1058
|
+
return [
|
|
1059
|
+
createDocumentBookmarkPlugin(this.name)
|
|
1060
|
+
];
|
|
1061
|
+
},
|
|
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
|
+
};
|
|
1085
|
+
},
|
|
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 '';
|
|
1125
|
+
}
|
|
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;
|
|
888
1130
|
}
|
|
889
|
-
function
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
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;
|
|
1135
|
+
}
|
|
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;
|
|
1140
|
+
}
|
|
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
|
+
}));
|
|
1149
|
+
}
|
|
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
|
+
};
|
|
909
1161
|
});
|
|
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
|
-
};
|
|
920
1162
|
}
|
|
921
|
-
function
|
|
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;
|
|
1167
|
+
}
|
|
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);
|
|
1171
|
+
}
|
|
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
|
-
|
|
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'
|
|
1209
|
+
});
|
|
1210
|
+
const end = boundaryType.create({
|
|
1211
|
+
...identity,
|
|
1212
|
+
kind: 'end'
|
|
1213
|
+
});
|
|
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;
|
|
955
1221
|
}
|
|
956
|
-
function
|
|
957
|
-
const
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
container ? `${container},` : '',
|
|
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(' ');
|
|
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;
|
|
990
1231
|
}
|
|
991
|
-
function
|
|
992
|
-
return
|
|
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
|
+
});
|
|
993
1247
|
}
|
|
994
|
-
function
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
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
|
+
});
|
|
1009
1278
|
}
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
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;
|
|
1294
|
+
}
|
|
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;
|
|
1317
|
+
}
|
|
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
|
+
});
|
|
1015
1339
|
});
|
|
1016
|
-
return section;
|
|
1017
1340
|
}
|
|
1018
|
-
function
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
const year = suppressYear ? '' : source.year?.trim() || 'n.d.';
|
|
1022
|
-
return [
|
|
1023
|
-
author,
|
|
1024
|
-
year
|
|
1025
|
-
].filter(Boolean).join(', ');
|
|
1026
|
-
});
|
|
1027
|
-
return `(${items.join('; ')})`;
|
|
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));
|
|
1028
1344
|
}
|
|
1029
|
-
function
|
|
1030
|
-
|
|
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;
|
|
1363
|
+
}
|
|
1364
|
+
pairs.push(bookmarkPair(start, boundary));
|
|
1365
|
+
}
|
|
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
|
+
};
|
|
1031
1372
|
}
|
|
1032
|
-
function
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
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;
|
|
1037
1385
|
}
|
|
1038
|
-
function
|
|
1039
|
-
|
|
1040
|
-
|
|
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
|
|
1395
|
+
};
|
|
1041
1396
|
}
|
|
1042
|
-
function
|
|
1043
|
-
const
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
return `${names[0]} et al.`;
|
|
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;
|
|
1050
1404
|
}
|
|
1051
|
-
function
|
|
1052
|
-
const
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
const suffix = person.suffix?.trim();
|
|
1057
|
-
if ('ieee' === style) {
|
|
1058
|
-
const initials = [
|
|
1059
|
-
person.first,
|
|
1060
|
-
person.middle
|
|
1061
|
-
].filter(Boolean).map((value)=>`${Array.from(value ?? '')[0] ?? ''}.`).join(' ');
|
|
1062
|
-
return [
|
|
1063
|
-
initials,
|
|
1064
|
-
person.last,
|
|
1065
|
-
suffix
|
|
1066
|
-
].filter(Boolean).join(' ');
|
|
1405
|
+
function uniqueDocumentBookmarkIdentity(source, registry) {
|
|
1406
|
+
const preferred = bookmarkIdentity(source);
|
|
1407
|
+
if (preferred && !bookmarkIdentityConflicts(preferred, registry)) {
|
|
1408
|
+
reserveBookmarkIdentity(preferred, registry);
|
|
1409
|
+
return preferred;
|
|
1067
1410
|
}
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
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)
|
|
1416
|
+
};
|
|
1417
|
+
reserveBookmarkIdentity(identity, registry);
|
|
1418
|
+
return identity;
|
|
1073
1419
|
}
|
|
1074
|
-
function
|
|
1075
|
-
|
|
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;
|
|
1076
1429
|
}
|
|
1077
|
-
function
|
|
1078
|
-
|
|
1079
|
-
return expression.exec(instruction)?.[1] ?? '';
|
|
1430
|
+
function bookmarkIdentityConflicts(identity, registry) {
|
|
1431
|
+
return registry.ids.has(identity.id) || registry.names.has(identity.name.toLowerCase()) || registry.nativeIds.has(identity.nativeId);
|
|
1080
1432
|
}
|
|
1081
|
-
function
|
|
1082
|
-
|
|
1433
|
+
function reserveBookmarkIdentity(identity, registry) {
|
|
1434
|
+
registry.ids.add(identity.id);
|
|
1435
|
+
registry.names.add(identity.name.toLowerCase());
|
|
1436
|
+
registry.nativeIds.add(identity.nativeId);
|
|
1083
1437
|
}
|
|
1084
|
-
function
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1438
|
+
function createBookmarkRegistry() {
|
|
1439
|
+
return {
|
|
1440
|
+
ids: new Set(),
|
|
1441
|
+
names: new Set(),
|
|
1442
|
+
nativeIds: new Set()
|
|
1443
|
+
};
|
|
1444
|
+
}
|
|
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;
|
|
1093
1449
|
}
|
|
1094
|
-
|
|
1450
|
+
let suffix = 1;
|
|
1451
|
+
while(ids.has(`bookmark-${suffix}`))suffix += 1;
|
|
1452
|
+
return `bookmark-${suffix}`;
|
|
1095
1453
|
}
|
|
1096
|
-
function
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
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;
|
|
1101
1463
|
}
|
|
1102
|
-
|
|
1103
|
-
while(usedIds.has(`document-citation-${suffix}`))suffix += 1;
|
|
1104
|
-
const id = `document-citation-${suffix}`;
|
|
1105
|
-
usedIds.add(id);
|
|
1106
|
-
return id;
|
|
1464
|
+
throw new Error('No unique Word bookmark name is available.');
|
|
1107
1465
|
}
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
function
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
const
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
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.');
|
|
1469
|
+
}
|
|
1470
|
+
function sameBookmarkIdentity(source, identity) {
|
|
1471
|
+
return bookmarkInternalId(source.id) === identity.id && normalizeDocumentBookmarkName(source.name) === identity.name && normalizeDocumentBookmarkNativeId(source.nativeId) === identity.nativeId;
|
|
1472
|
+
}
|
|
1473
|
+
function bookmarkInternalId(value) {
|
|
1474
|
+
return 'string' == typeof value ? value.trim() : '';
|
|
1475
|
+
}
|
|
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 ?? '')}`;
|
|
1480
|
+
}
|
|
1481
|
+
function documentBookmarkBoundaryKind(value) {
|
|
1482
|
+
return 'end' === value ? 'end' : 'start';
|
|
1483
|
+
}
|
|
1484
|
+
function transactionMapping(transactions) {
|
|
1485
|
+
const mapping = new Mapping();
|
|
1486
|
+
for (const transaction of transactions)mapping.appendMapping(transaction.mapping);
|
|
1487
|
+
return mapping;
|
|
1488
|
+
}
|
|
1489
|
+
function pairPositionKey(pair) {
|
|
1490
|
+
return `${pair.from}:${pair.to}`;
|
|
1491
|
+
}
|
|
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);
|
|
1502
|
+
continue;
|
|
1503
|
+
}
|
|
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
|
+
});
|
|
1516
|
+
}
|
|
1517
|
+
for (const stack of open.values())orphans.push(...stack);
|
|
1518
|
+
return {
|
|
1519
|
+
pairs,
|
|
1520
|
+
orphans
|
|
1123
1521
|
};
|
|
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
1522
|
}
|
|
1137
|
-
function
|
|
1138
|
-
|
|
1523
|
+
function domBookmarkPairKey(element) {
|
|
1524
|
+
const id = element.dataset.bookmarkId?.trim();
|
|
1525
|
+
return id ? `id:${id}` : `legacy:${element.dataset.bookmarkName ?? ''}:${element.dataset.officeBookmarkId ?? ''}`;
|
|
1139
1526
|
}
|
|
1140
|
-
function
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
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');
|
|
1146
1538
|
}
|
|
1147
|
-
function
|
|
1148
|
-
const
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
}
|
|
1153
|
-
if (normalized.custom) return normalized;
|
|
1154
|
-
return normalizeDocumentColumns({
|
|
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
|
-
});
|
|
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
|
+
}
|
|
1163
1545
|
}
|
|
1164
|
-
function
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
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
|
+
});
|
|
1177
1571
|
});
|
|
1178
|
-
return {
|
|
1179
|
-
...normalized,
|
|
1180
|
-
custom
|
|
1181
|
-
};
|
|
1182
1572
|
}
|
|
1183
|
-
function
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
const
|
|
1190
|
-
const
|
|
1191
|
-
if (
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
result[index] = minimum;
|
|
1197
|
-
remaining.delete(index);
|
|
1198
|
-
remainingTotal -= minimum;
|
|
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;
|
|
1199
1586
|
}
|
|
1200
1587
|
}
|
|
1201
|
-
const rounded = result.map(roundOne);
|
|
1202
|
-
const adjustmentIndex = rounded.indexOf(Math.max(...rounded));
|
|
1203
|
-
rounded[adjustmentIndex] = roundOne(rounded[adjustmentIndex] + total - rounded.reduce((sum, value)=>sum + value, 0));
|
|
1204
|
-
return rounded;
|
|
1205
1588
|
}
|
|
1206
|
-
function
|
|
1207
|
-
return
|
|
1208
|
-
}
|
|
1209
|
-
function clampNumber(value, fallback, minimum, maximum) {
|
|
1210
|
-
return Math.min(maximum, Math.max(minimum, finiteNumber(value, fallback)));
|
|
1211
|
-
}
|
|
1212
|
-
function finiteNumber(value, fallback) {
|
|
1213
|
-
return Number.isFinite(value) ? Number(value) : fallback;
|
|
1589
|
+
function normalizedClass(value) {
|
|
1590
|
+
return 'string' == typeof value ? value.trim().split(/\s+/).filter(Boolean).join(' ') : '';
|
|
1214
1591
|
}
|
|
1215
|
-
function
|
|
1216
|
-
|
|
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(' ');
|
|
1217
1597
|
}
|
|
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;
|
|
1598
|
+
function work_document_bookmarks_stringAttribute(value) {
|
|
1599
|
+
return 'string' == typeof value ? value.trim() : '';
|
|
1238
1600
|
}
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
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;
|
|
1248
1611
|
}
|
|
1249
|
-
function
|
|
1250
|
-
return
|
|
1612
|
+
function documentCaptionKind(value) {
|
|
1613
|
+
return 'figure' === value || 'table' === value ? value : null;
|
|
1251
1614
|
}
|
|
1252
|
-
function
|
|
1253
|
-
return
|
|
1615
|
+
function documentCaptionLabel(kind) {
|
|
1616
|
+
return 'table' === kind ? '表' : '图';
|
|
1254
1617
|
}
|
|
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);
|
|
1618
|
+
function documentCaptionDisplay(kind, number) {
|
|
1619
|
+
return `${documentCaptionLabel(kind)} ${work_document_captions_positiveInteger(number)}`;
|
|
1264
1620
|
}
|
|
1265
|
-
function
|
|
1266
|
-
const
|
|
1621
|
+
function normalizeCaptions(document1) {
|
|
1622
|
+
const counters = {
|
|
1623
|
+
figure: 0,
|
|
1624
|
+
table: 0
|
|
1625
|
+
};
|
|
1267
1626
|
const usedIds = new Set();
|
|
1268
|
-
|
|
1269
|
-
const
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
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 {
|
|
1643
|
+
id,
|
|
1644
|
+
kind,
|
|
1645
|
+
number,
|
|
1646
|
+
label,
|
|
1647
|
+
title,
|
|
1648
|
+
display
|
|
1649
|
+
};
|
|
1650
|
+
});
|
|
1651
|
+
}
|
|
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 = '引用缺失';
|
|
1273
1663
|
continue;
|
|
1274
1664
|
}
|
|
1275
|
-
|
|
1276
|
-
element.dataset.
|
|
1277
|
-
element.dataset.
|
|
1278
|
-
element.dataset.
|
|
1279
|
-
element.
|
|
1280
|
-
element.dataset.fieldDisplay = display;
|
|
1281
|
-
element.classList.add('work-document-field');
|
|
1282
|
-
element.textContent = display;
|
|
1283
|
-
}
|
|
1284
|
-
return document1.body.innerHTML;
|
|
1285
|
-
}
|
|
1286
|
-
function resolveDocumentFieldsHtml(source, context) {
|
|
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;
|
|
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;
|
|
1294
1670
|
}
|
|
1295
|
-
return document1.body.innerHTML;
|
|
1296
1671
|
}
|
|
1297
|
-
function
|
|
1672
|
+
function uniqueCaptionId(source, kind, index, usedIds) {
|
|
1298
1673
|
const candidate = source?.trim();
|
|
1299
1674
|
if (candidate && !usedIds.has(candidate)) {
|
|
1300
1675
|
usedIds.add(candidate);
|
|
1301
1676
|
return candidate;
|
|
1302
1677
|
}
|
|
1303
1678
|
let suffix = index;
|
|
1304
|
-
while(usedIds.has(`document-
|
|
1305
|
-
const id = `document-
|
|
1679
|
+
while(usedIds.has(`document-${kind}-caption-${suffix}`))suffix += 1;
|
|
1680
|
+
const id = `document-${kind}-caption-${suffix}`;
|
|
1306
1681
|
usedIds.add(id);
|
|
1307
1682
|
return id;
|
|
1308
1683
|
}
|
|
1309
|
-
function
|
|
1310
|
-
|
|
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())
|
|
1343
|
-
};
|
|
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
|
-
}
|
|
1349
|
-
function validDate(value) {
|
|
1350
|
-
return value && Number.isFinite(value.getTime()) ? value : null;
|
|
1684
|
+
function work_document_captions_positiveInteger(value) {
|
|
1685
|
+
const number = Number(value);
|
|
1686
|
+
return Number.isSafeInteger(number) && number > 0 ? number : 1;
|
|
1351
1687
|
}
|
|
1352
|
-
const
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
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
|
+
}
|
|
1357
1707
|
};
|
|
1358
|
-
function
|
|
1359
|
-
return {
|
|
1360
|
-
top: validMargin(content.margins?.top, DEFAULT_DOCUMENT_MARGINS.top),
|
|
1361
|
-
right: validMargin(content.margins?.right, DEFAULT_DOCUMENT_MARGINS.right),
|
|
1362
|
-
bottom: validMargin(content.margins?.bottom, DEFAULT_DOCUMENT_MARGINS.bottom),
|
|
1363
|
-
left: validMargin(content.margins?.left, DEFAULT_DOCUMENT_MARGINS.left)
|
|
1364
|
-
};
|
|
1365
|
-
}
|
|
1366
|
-
function clampDocumentMargin(value) {
|
|
1367
|
-
return Math.min(60, Math.max(5, Math.round(10 * value) / 10));
|
|
1368
|
-
}
|
|
1369
|
-
function millimetersToPixels(value) {
|
|
1370
|
-
return 96 * value / 25.4;
|
|
1371
|
-
}
|
|
1372
|
-
function validMargin(value, fallback) {
|
|
1373
|
-
return Number.isFinite(value) ? clampDocumentMargin(value) : fallback;
|
|
1374
|
-
}
|
|
1375
|
-
const DOCUMENT_HTML_FINGERPRINT_VERSION = 'p1';
|
|
1376
|
-
const DOCUMENT_HTML_HASH_BASE = 0x01000193;
|
|
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;
|
|
1708
|
+
function createDocumentBibliography(style = 'apa') {
|
|
1383
1709
|
return {
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
}
|
|
1389
|
-
function combineDocumentHtmlFingerprintSegments(segments) {
|
|
1390
|
-
let combined = {
|
|
1391
|
-
hash: 0,
|
|
1392
|
-
length: 0,
|
|
1393
|
-
power: 1
|
|
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
|
|
1710
|
+
style,
|
|
1711
|
+
styleName: STYLE_DETAILS[style].name,
|
|
1712
|
+
selectedStyle: STYLE_DETAILS[style].selectedStyle,
|
|
1713
|
+
sources: []
|
|
1399
1714
|
};
|
|
1400
|
-
return combined;
|
|
1401
|
-
}
|
|
1402
|
-
function documentHtmlFingerprintForSegment(segment) {
|
|
1403
|
-
return `${DOCUMENT_HTML_FINGERPRINT_VERSION}:${segment.length.toString(36)}:${segment.hash.toString(36)}`;
|
|
1404
1715
|
}
|
|
1405
|
-
function
|
|
1406
|
-
|
|
1716
|
+
function documentCitationStyle(value) {
|
|
1717
|
+
if ('mla' === value || 'chicago' === value || 'ieee' === value) return value;
|
|
1718
|
+
return 'apa';
|
|
1407
1719
|
}
|
|
1408
|
-
function
|
|
1409
|
-
return
|
|
1720
|
+
function documentCitationStyleDetails(style) {
|
|
1721
|
+
return STYLE_DETAILS[style];
|
|
1410
1722
|
}
|
|
1411
|
-
function
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
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]
|
|
1728
|
+
];
|
|
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);
|
|
1418
1732
|
}
|
|
1419
|
-
function
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
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(' ');
|
|
1429
1746
|
}
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
const
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
if (!html.startsWith('<section') || !html.endsWith(SECTION_CLOSE)) return null;
|
|
1436
|
-
const sectionOpenEnd = html.indexOf('>') + 1;
|
|
1437
|
-
if (sectionOpenEnd <= 0) return null;
|
|
1438
|
-
let cursor = sectionOpenEnd;
|
|
1439
|
-
const orderedRanges = [];
|
|
1440
|
-
const ranges = new Map();
|
|
1441
|
-
for (const chunk of lazyDocumentLeafChunks(root)){
|
|
1442
|
-
const id = 'string' == typeof chunk.attrs?.id ? chunk.attrs.id : '';
|
|
1443
|
-
if (!id || ranges.has(id)) return null;
|
|
1444
|
-
const from = cursor;
|
|
1445
|
-
let tablePart = null;
|
|
1446
|
-
const content = chunk.content ?? [];
|
|
1447
|
-
for (const node of content){
|
|
1448
|
-
const scanned = scanSimpleDocumentNodeHtml(html, cursor, node);
|
|
1449
|
-
if (!scanned) return null;
|
|
1450
|
-
cursor = scanned.to;
|
|
1451
|
-
if (scanned.tablePart) {
|
|
1452
|
-
if (1 !== content.length || tablePart) return null;
|
|
1453
|
-
tablePart = scanned.tablePart;
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
1456
|
-
const range = {
|
|
1457
|
-
from,
|
|
1458
|
-
id,
|
|
1459
|
-
tablePart,
|
|
1460
|
-
to: cursor
|
|
1461
|
-
};
|
|
1462
|
-
orderedRanges.push(range);
|
|
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
|
-
};
|
|
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
|
+
});
|
|
1471
1752
|
}
|
|
1472
|
-
function
|
|
1473
|
-
|
|
1474
|
-
for (const id of replacements.keys())if (!projection.ranges.has(id)) return null;
|
|
1475
|
-
const fingerprintState = documentLazyHtmlFingerprintState(projection);
|
|
1476
|
-
const parts = [];
|
|
1477
|
-
let cursor = 0;
|
|
1478
|
-
for (const range of projection.orderedRanges){
|
|
1479
|
-
const replacement = replacements.get(range.id);
|
|
1480
|
-
if (void 0 !== replacement) {
|
|
1481
|
-
parts.push(projection.html.slice(cursor, range.from), replacement);
|
|
1482
|
-
fingerprintState.ranges.set(range.id, createDocumentHtmlFingerprintSegment(replacement));
|
|
1483
|
-
cursor = range.to;
|
|
1484
|
-
}
|
|
1485
|
-
}
|
|
1486
|
-
parts.push(projection.html.slice(cursor));
|
|
1487
|
-
const html = parts.join('');
|
|
1488
|
-
let offset = 0;
|
|
1489
|
-
for (const range of projection.orderedRanges){
|
|
1490
|
-
const previousFrom = range.from;
|
|
1491
|
-
const previousLength = range.to - previousFrom;
|
|
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;
|
|
1497
|
-
}
|
|
1498
|
-
projection.html = html;
|
|
1499
|
-
fingerprintState.fingerprint = documentHtmlFingerprintForSegment(combineDocumentHtmlFingerprintSegments([
|
|
1500
|
-
fingerprintState.prefix,
|
|
1501
|
-
...projection.orderedRanges.map((range)=>{
|
|
1502
|
-
const segment = fingerprintState.ranges.get(range.id);
|
|
1503
|
-
if (!segment) throw new Error('The lazy HTML fingerprint segment is missing.');
|
|
1504
|
-
return segment;
|
|
1505
|
-
}),
|
|
1506
|
-
fingerprintState.suffix
|
|
1507
|
-
]));
|
|
1508
|
-
return html;
|
|
1753
|
+
function documentCitationTags(value) {
|
|
1754
|
+
return uniqueCitationTags((value ?? '').split(/\s+/));
|
|
1509
1755
|
}
|
|
1510
|
-
function
|
|
1511
|
-
return
|
|
1756
|
+
function isValidDocumentCitationTag(value) {
|
|
1757
|
+
return /^[A-Za-z0-9_:.+-]{1,80}$/.test(value);
|
|
1512
1758
|
}
|
|
1513
|
-
function
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
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);
|
|
1786
|
+
return {
|
|
1787
|
+
text: `${prefix}${text}${suffix}`.trim() || cachedValue || normalized.join('; '),
|
|
1788
|
+
orphaned: false
|
|
1789
|
+
};
|
|
1522
1790
|
}
|
|
1523
|
-
function
|
|
1524
|
-
const
|
|
1525
|
-
const
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
const
|
|
1530
|
-
if (!
|
|
1531
|
-
|
|
1532
|
-
chunks.push(node);
|
|
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 ?? ''));
|
|
1533
1800
|
continue;
|
|
1534
1801
|
}
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
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;
|
|
1539
1813
|
}
|
|
1540
|
-
|
|
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;
|
|
1541
1820
|
}
|
|
1542
|
-
function
|
|
1543
|
-
const
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
const last = projection.orderedRanges.at(-1);
|
|
1547
|
-
const ranges = new Map();
|
|
1548
|
-
for (const range of projection.orderedRanges)ranges.set(range.id, createDocumentHtmlFingerprintSegment(projection.html, range.from, range.to));
|
|
1549
|
-
const prefix = createDocumentHtmlFingerprintSegment(projection.html, 0, first?.from ?? projection.html.length);
|
|
1550
|
-
const suffix = createDocumentHtmlFingerprintSegment(projection.html, last?.to ?? projection.html.length, projection.html.length);
|
|
1551
|
-
const state = {
|
|
1552
|
-
fingerprint: documentHtmlFingerprintForSegment(combineDocumentHtmlFingerprintSegments([
|
|
1553
|
-
prefix,
|
|
1554
|
-
...projection.orderedRanges.map((range)=>{
|
|
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;
|
|
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;
|
|
1567
1825
|
}
|
|
1568
|
-
function
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
};
|
|
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(' ');
|
|
1603
1860
|
}
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
'
|
|
1609
|
-
'
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
const
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
if (!rebuilt) return null;
|
|
1623
|
-
rebuilt.htmlProjection = htmlProjection;
|
|
1624
|
-
prepared = rebuilt;
|
|
1625
|
-
preparedModels.set(model, rebuilt);
|
|
1626
|
-
}
|
|
1627
|
-
} else {
|
|
1628
|
-
if (!allowCreate) return null;
|
|
1629
|
-
const created = createPreparedLazyDocumentEditorSource(model.root);
|
|
1630
|
-
if (!created) return null;
|
|
1631
|
-
prepared = created;
|
|
1632
|
-
preparedModels.set(model, created);
|
|
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
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
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);
|
|
1885
|
+
});
|
|
1886
|
+
return section;
|
|
1887
|
+
}
|
|
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(', ');
|
|
1643
1896
|
});
|
|
1644
|
-
return
|
|
1897
|
+
return `(${items.join('; ')})`;
|
|
1645
1898
|
}
|
|
1646
|
-
function
|
|
1647
|
-
return
|
|
1899
|
+
function mlaCitation(sources, suppressAuthor) {
|
|
1900
|
+
return `(${sources.map((source)=>suppressAuthor ? source.year?.trim() || 'n.d.' : citationAuthor(source, 'and')).join('; ')})`;
|
|
1648
1901
|
}
|
|
1649
|
-
function
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
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('; ')})`;
|
|
1907
|
+
}
|
|
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(', ')}]`;
|
|
1911
|
+
}
|
|
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.`;
|
|
1920
|
+
}
|
|
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(' ');
|
|
1653
1937
|
}
|
|
1938
|
+
return [
|
|
1939
|
+
person.last,
|
|
1940
|
+
first ? `, ${first}` : '',
|
|
1941
|
+
suffix ? `, ${suffix}` : ''
|
|
1942
|
+
].join('');
|
|
1654
1943
|
}
|
|
1655
|
-
function
|
|
1656
|
-
|
|
1657
|
-
return preparedModels.get(model)?.payloads.get(chunkId) ?? null;
|
|
1944
|
+
function citationContainer(source) {
|
|
1945
|
+
return source.journalName?.trim() || source.publisher?.trim() || source.conferenceName?.trim() || source.institution?.trim() || '';
|
|
1658
1946
|
}
|
|
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);
|
|
1947
|
+
function citationSwitch(instruction, name) {
|
|
1948
|
+
const expression = new RegExp(`\\\\${name}\\s+"([^"]*)"`, 'i');
|
|
1949
|
+
return expression.exec(instruction)?.[1] ?? '';
|
|
1692
1950
|
}
|
|
1693
|
-
function
|
|
1694
|
-
|
|
1695
|
-
const prepared = preparedModels.get(previous);
|
|
1696
|
-
if (!prepared) return;
|
|
1697
|
-
preparedModels.set(next, {
|
|
1698
|
-
htmlProjection: prepared.htmlProjection,
|
|
1699
|
-
lazyChunkCount: prepared.lazyChunkCount,
|
|
1700
|
-
payloads: prepared.payloads,
|
|
1701
|
-
root: null
|
|
1702
|
-
});
|
|
1951
|
+
function citationTagInstructionValue(tag) {
|
|
1952
|
+
return /^[A-Za-z0-9_:.+-]+$/.test(tag) ? tag : `"${tag.replaceAll('"', '')}"`;
|
|
1703
1953
|
}
|
|
1704
|
-
function
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
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);
|
|
1962
|
+
}
|
|
1712
1963
|
}
|
|
1713
|
-
return
|
|
1964
|
+
return result;
|
|
1714
1965
|
}
|
|
1715
|
-
function
|
|
1716
|
-
const
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
]
|
|
1743
|
-
};
|
|
1744
|
-
}
|
|
1745
|
-
if (!node.content?.length) return node;
|
|
1746
|
-
let changed = false;
|
|
1747
|
-
const content = node.content.map((child)=>{
|
|
1748
|
-
const next = visit(child);
|
|
1749
|
-
if (next !== child) changed = true;
|
|
1750
|
-
return next;
|
|
1751
|
-
});
|
|
1752
|
-
return changed ? {
|
|
1753
|
-
...node,
|
|
1754
|
-
content
|
|
1755
|
-
} : node;
|
|
1756
|
-
};
|
|
1757
|
-
const compactRoot = visit(root);
|
|
1758
|
-
if (unsupported || leafIndex <= DOCUMENT_LAZY_INITIAL_CHUNK_COUNT || 0 === lazyChunkCount) return null;
|
|
1759
|
-
return {
|
|
1760
|
-
htmlProjection: null,
|
|
1761
|
-
lazyChunkCount,
|
|
1762
|
-
payloads,
|
|
1763
|
-
root: compactRoot
|
|
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;
|
|
1765
2006
|
}
|
|
1766
|
-
function
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
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);
|
|
2016
|
+
}
|
|
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
|
}
|
|
@@ -10882,130 +11163,6 @@ function setNumberDataset(element, name, value) {
|
|
|
10882
11163
|
if (Number.isSafeInteger(number) && number >= 0) element.dataset[name] = String(number);
|
|
10883
11164
|
else delete element.dataset[name];
|
|
10884
11165
|
}
|
|
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);
|
|
10958
|
-
}
|
|
10959
|
-
if (Object.values(statistics).some((value)=>value < 0)) return false;
|
|
10960
|
-
statisticsByDocument.set(next, statistics);
|
|
10961
|
-
return true;
|
|
10962
|
-
}
|
|
10963
|
-
function simpleDocumentSubtreeStatistics(root) {
|
|
10964
|
-
const statistics = {
|
|
10965
|
-
characterCountWithSpaces: 0,
|
|
10966
|
-
characterCountWithoutSpaces: 0,
|
|
10967
|
-
paragraphCount: 0,
|
|
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;
|
|
10986
|
-
}
|
|
10987
|
-
function accumulateDocumentTextStatistics(statistics, source) {
|
|
10988
|
-
for(let index = 0; index < source.length; index += 1){
|
|
10989
|
-
const codePoint = source.codePointAt(index);
|
|
10990
|
-
if (void 0 !== codePoint) {
|
|
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);
|
|
10999
|
-
}
|
|
11000
|
-
function applyDocumentTextStatisticsDelta(target, value, direction) {
|
|
11001
|
-
target.characterCountWithSpaces += direction * value.characterCountWithSpaces;
|
|
11002
|
-
target.characterCountWithoutSpaces += direction * value.characterCountWithoutSpaces;
|
|
11003
|
-
target.paragraphCount += direction * value.paragraphCount;
|
|
11004
|
-
target.wordCount += direction * value.wordCount;
|
|
11005
|
-
}
|
|
11006
|
-
function isEcmaScriptWhitespace(codePoint) {
|
|
11007
|
-
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;
|
|
11008
|
-
}
|
|
11009
11166
|
const INITIAL_DOCUMENT_CHUNK_WINDOW_SIZE = 2;
|
|
11010
11167
|
const DOCUMENT_CHUNK_WINDOW_ROOT_MARGIN = '0px';
|
|
11011
11168
|
const DOCUMENT_CHUNK_PAGINATION_META = 'documentChunkPaginationGeometry';
|
|
@@ -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;
|
|
@@ -22508,4 +22760,4 @@ function registerDocumentPageSurfaceGeometry(element, provider) {
|
|
|
22508
22760
|
function documentPageSurfaceGeometryForElement(element) {
|
|
22509
22761
|
return documentPageSurfaceProviders.get(element)?.() ?? null;
|
|
22510
22762
|
}
|
|
22511
|
-
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, 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, 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 };
|
|
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 };
|