@a3s-lab/office 0.48.1 → 0.49.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.
@@ -1172,6 +1172,7 @@ function documentChangeKindLabel(kind) {
1172
1172
  if ('formatting' === kind) return '格式';
1173
1173
  if ('paragraph-formatting' === kind) return '段落格式';
1174
1174
  if ('numbering' === kind) return '编号格式';
1175
+ if ('move' === kind) return '移动';
1175
1176
  return '删除';
1176
1177
  }
1177
1178
  function documentChangeWindowKey(change) {
@@ -19872,7 +19873,10 @@ function createDocumentPaginationRunCoordinator({ cancelFrame, onAbort, onCoales
19872
19873
  };
19873
19874
  }
19874
19875
  const MAX_DOCUMENT_BLOCK_RESIZE_OBSERVATIONS = 4096;
19875
- function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, page, selectionVersion, wasmUrl, layoutFonts, loadedLayoutFontIds }) {
19876
+ function neverComposing() {
19877
+ return false;
19878
+ }
19879
+ function useDocumentPagination({ compositionRevision = 0, editor, documentRevision, enabled, isComposing = neverComposing, layoutKey, page, selectionVersion, wasmUrl, layoutFonts, loadedLayoutFontIds }) {
19876
19880
  const client = useOfficeKernelClient(wasmUrl, layoutFonts);
19877
19881
  const editorMounted = useEditorMounted(editor);
19878
19882
  const revision = useRef(0);
@@ -20011,6 +20015,7 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
20011
20015
  for (const element of observedElements)observer?.observe(element);
20012
20016
  };
20013
20017
  const run = async (signal)=>{
20018
+ if (isComposing()) return void measurementRange.ensureDirty();
20014
20019
  stopObservingBlocks();
20015
20020
  const nextRevision = ++revision.current;
20016
20021
  editor.commands.clearDocumentPagination(nextRevision);
@@ -20040,7 +20045,7 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
20040
20045
  documentRevision,
20041
20046
  paragraphs
20042
20047
  }, signal);
20043
- if (disposed || signal.aborted || nextRevision !== revision.current || editor.isDestroyed) return;
20048
+ if (disposed || signal.aborted || nextRevision !== revision.current || editor.isDestroyed || isComposing()) return;
20044
20049
  textLayoutEngine ||= textLayout.engine;
20045
20050
  unsupportedTextLayoutCount += textLayout.unsupportedParagraphIds.length + textLayout.layouts.filter((layout)=>layout.missingGlyphCount > 0).length;
20046
20051
  for (const layout of textLayout.layouts)if (0 === layout.missingGlyphCount) {
@@ -20051,7 +20056,7 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
20051
20056
  editorDom.dataset.paginationTextEngine = textLayoutEngine;
20052
20057
  editorDom.dataset.paginationUnsupportedText = String(unsupportedTextLayoutCount);
20053
20058
  } catch (error) {
20054
- if (signal.aborted || error instanceof DOMException && 'AbortError' === error.name) return;
20059
+ if (signal.aborted || isComposing() || error instanceof DOMException && 'AbortError' === error.name) return;
20055
20060
  textLayouts.clear();
20056
20061
  fallbackGlyphCount = 0;
20057
20062
  editorDom.dataset.paginationTextEngine = 'dom';
@@ -20069,6 +20074,7 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
20069
20074
  const snapshot = await measureDocumentLayoutBlocksIncrementally(editor, measurementCache.current, measurementStart, textLayouts, 1000000, {
20070
20075
  signal
20071
20076
  });
20077
+ if (disposed || signal.aborted || nextRevision !== revision.current || editor.isDestroyed || isComposing()) return;
20072
20078
  measurementCache.current = snapshot;
20073
20079
  editorDom.dataset.paginationBlocks = String(snapshot.blocks.length);
20074
20080
  editorDom.dataset.paginationFlows = String(new Set(snapshot.blocks.flatMap((block)=>block.block.flowId ? [
@@ -20098,7 +20104,7 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
20098
20104
  pageStyles: snapshot.pageStyles,
20099
20105
  blocks: layoutPlan.blocks
20100
20106
  }, signal);
20101
- if (disposed || signal.aborted || nextRevision !== revision.current || editor.isDestroyed) return;
20107
+ if (disposed || signal.aborted || nextRevision !== revision.current || editor.isDestroyed || isComposing()) return;
20102
20108
  const layout = previousPagination && layoutPlan.startPageIndex > 0 ? mergeIncrementalDocumentLayout(previousPagination.layout, partialLayout) : partialLayout;
20103
20109
  const blockById = new Map(snapshot.blocks.map((block)=>[
20104
20110
  block.block.id,
@@ -20147,7 +20153,7 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
20147
20153
  measurementRange.commit(measurementPass);
20148
20154
  setPagination(nextPagination);
20149
20155
  } catch (error) {
20150
- if (disposed || signal.aborted || error instanceof DOMException && 'AbortError' === error.name) return;
20156
+ if (disposed || signal.aborted || isComposing() || error instanceof DOMException && 'AbortError' === error.name) return;
20151
20157
  editorDom.dataset.paginationState = 'error';
20152
20158
  editorDom.dataset.paginationError = error instanceof Error ? `${error.name}: ${error.message}` : 'UnknownError';
20153
20159
  editor.commands.clearDocumentPagination(nextRevision);
@@ -20167,7 +20173,7 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
20167
20173
  onCoalescedRequest: ()=>updateDiagnostic('coalescedRequests', 'paginationCoalescedRequests'),
20168
20174
  onError: (error)=>{
20169
20175
  measurementRange.restoreActive();
20170
- if (disposed || editor.isDestroyed) return;
20176
+ if (disposed || editor.isDestroyed || isComposing()) return;
20171
20177
  editorDom.dataset.paginationState = 'error';
20172
20178
  editorDom.dataset.paginationError = error instanceof Error ? `${error.name}: ${error.message}` : 'UnknownError';
20173
20179
  paginationCache.current = null;
@@ -20184,6 +20190,7 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
20184
20190
  run
20185
20191
  });
20186
20192
  const schedule = (invalidateActive = false)=>{
20193
+ if (isComposing()) return;
20187
20194
  coordinator.request({
20188
20195
  invalidateActive
20189
20196
  });
@@ -20200,6 +20207,15 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
20200
20207
  markDirty(earliestChangedPosition(transaction));
20201
20208
  schedule(true);
20202
20209
  };
20210
+ const handleCompositionStart = ()=>{
20211
+ measurementRange.ensureDirty();
20212
+ coordinator.request({
20213
+ invalidateActive: true
20214
+ });
20215
+ };
20216
+ const handleCompositionEnd = ()=>{
20217
+ schedule(true);
20218
+ };
20203
20219
  const handleLoadedAsset = (event)=>{
20204
20220
  updateDiagnostic('assetTriggers', 'paginationAssetTriggers');
20205
20221
  const target = event.target;
@@ -20219,6 +20235,8 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
20219
20235
  };
20220
20236
  const fonts = document.fonts;
20221
20237
  editor.on('update', handleDocumentUpdate);
20238
+ editorDom.addEventListener('compositionstart', handleCompositionStart);
20239
+ editorDom.addEventListener('compositionend', handleCompositionEnd);
20222
20240
  editorDom.addEventListener('load', handleLoadedAsset, true);
20223
20241
  fonts?.addEventListener('loadingdone', handleFontLoading);
20224
20242
  window.addEventListener('resize', handleWindowResize);
@@ -20227,6 +20245,8 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
20227
20245
  disposed = true;
20228
20246
  stopObservingBlocks();
20229
20247
  editor.off('update', handleDocumentUpdate);
20248
+ editorDom.removeEventListener('compositionstart', handleCompositionStart);
20249
+ editorDom.removeEventListener('compositionend', handleCompositionEnd);
20230
20250
  editorDom.removeEventListener('load', handleLoadedAsset, true);
20231
20251
  fonts?.removeEventListener('loadingdone', handleFontLoading);
20232
20252
  window.removeEventListener('resize', handleWindowResize);
@@ -20234,6 +20254,7 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
20234
20254
  };
20235
20255
  }, [
20236
20256
  client,
20257
+ compositionRevision,
20237
20258
  documentRevision,
20238
20259
  editor,
20239
20260
  editorMounted,
@@ -20243,6 +20264,7 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
20243
20264
  layoutFonts,
20244
20265
  loadedLayoutFontKey,
20245
20266
  loadedLayoutFontIds,
20267
+ isComposing,
20246
20268
  pageKey
20247
20269
  ]);
20248
20270
  const resolveFieldContext = useMemo(()=>pagination ? createDocumentFieldPaginationContextResolver(pagination) : null, [
@@ -20929,12 +20951,24 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
20929
20951
  },
20930
20952
  handleDOMEvents: {
20931
20953
  compositionstart: ()=>{
20932
- composition.start();
20954
+ composition.start(editorRef.current);
20955
+ return false;
20956
+ },
20957
+ compositionupdate: ()=>{
20958
+ composition.start(editorRef.current);
20933
20959
  return false;
20934
20960
  },
20935
- compositionend: ()=>{
20961
+ beforeinput: (_view, event)=>{
20962
+ composition.noteInput(event);
20963
+ return false;
20964
+ },
20965
+ input: (_view, event)=>{
20966
+ composition.noteInput(event);
20967
+ return false;
20968
+ },
20969
+ compositionend: (_view, event)=>{
20936
20970
  const current = editorRef.current;
20937
- if (current) composition.end(current, (settled)=>settleCompositionRef.current(settled));
20971
+ if (current) composition.end(current, event.data ?? null, (settled, snapshot)=>settleCompositionRef.current(settled, snapshot));
20938
20972
  return false;
20939
20973
  }
20940
20974
  }
@@ -21010,7 +21044,20 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
21010
21044
  publishDocumentUpdate,
21011
21045
  queueLazyDocumentPublication
21012
21046
  ]);
21013
- settleCompositionRef.current = (current)=>{
21047
+ settleCompositionRef.current = (current, snapshot)=>{
21048
+ if (null !== snapshot.text && snapshot.range && !current.isDestroyed) {
21049
+ const maximum = current.state.doc.content.size;
21050
+ const from = Math.max(0, Math.min(maximum, snapshot.range.from));
21051
+ const to = Math.max(0, Math.min(maximum, snapshot.range.to));
21052
+ const start = Math.min(from, to);
21053
+ const end = Math.max(from, to);
21054
+ const currentText = current.state.doc.textBetween(start, end, '\n', '\n');
21055
+ if (currentText !== snapshot.text) {
21056
+ if (trackChangesRef.current) current.commands.replaceDocumentTextWithTrackedChange(start, end, snapshot.text);
21057
+ else current.view.dispatch(current.state.tr.insertText(snapshot.text, start, end).setMeta('composition', snapshot.id).setMeta('uiEvent', 'input'));
21058
+ current.view.dom.dataset.documentCompositionNormalized = 'true';
21059
+ }
21060
+ }
21014
21061
  const pending = pendingLazyPublicationRef.current;
21015
21062
  if (pending) {
21016
21063
  pending.cancel();
@@ -21065,6 +21112,8 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
21065
21112
  composition.destroy();
21066
21113
  },
21067
21114
  onTransaction: ({ appendedTransactions, editor: current, transaction })=>{
21115
+ composition.recordTransaction(transaction);
21116
+ for (const appended of appendedTransactions ?? [])composition.recordTransaction(appended);
21068
21117
  if (documentTransactionsOnlyHydrateChunks([
21069
21118
  transaction,
21070
21119
  ...appendedTransactions
@@ -21429,10 +21478,16 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
21429
21478
  JSON.stringify(layout.pageMargins),
21430
21479
  layout.pageSize
21431
21480
  ]);
21481
+ const documentCompositionIsActive = useCallback(()=>composition.isBlocking(editor), [
21482
+ composition,
21483
+ editor
21484
+ ]);
21432
21485
  const pagination = useDocumentPagination({
21486
+ compositionRevision,
21433
21487
  editor,
21434
21488
  documentRevision: editorInput.revision,
21435
21489
  enabled: Boolean(editor && 'page' === viewMode),
21490
+ isComposing: documentCompositionIsActive,
21436
21491
  layoutKey: [
21437
21492
  layout.breakAfter,
21438
21493
  layout.columns.count,
@@ -4128,6 +4128,131 @@ function directListItemContentRoot(item) {
4128
4128
  for (const child of item.childNodes)if (!(child instanceof HTMLElement) || 'ol' !== child.tagName.toLowerCase() && 'ul' !== child.tagName.toLowerCase()) root.append(child.cloneNode(true));
4129
4129
  return root;
4130
4130
  }
4131
+ const work_docx_move_revision_export_WORD_NAMESPACE = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
4132
+ const work_docx_move_revision_export_STORY_PATTERN = /^word\/(?:document|header\d*|footer\d*|footnotes|endnotes|comments)\.xml$/i;
4133
+ const MAX_MOVE_REVISION_PATCHES = 65536;
4134
+ const MAX_MOVE_TEXT_LENGTH = 1000000;
4135
+ class DocxMoveRevisionPatchCollector {
4136
+ patches = [];
4137
+ registrations = new WeakMap();
4138
+ nextWireId = -1;
4139
+ register(element, id, revisionDate = work_docx_move_revision_export_normalizedRevisionDate(element.dataset.changeDate)) {
4140
+ if (!element.hasAttribute('data-document-change') || 'move' !== element.dataset.changeKind) return null;
4141
+ const existing = this.registrations.get(element);
4142
+ if (existing) return existing;
4143
+ const role = moveRole(element.dataset.changeMoveRole);
4144
+ const author = element.dataset.changeAuthor?.trim() ?? '';
4145
+ const date = revisionDate;
4146
+ const key = element.dataset.changeId?.trim() ?? '';
4147
+ const text = element.textContent ?? '';
4148
+ if (!role || !key || key.length > 255 || /[\u0000-\u001f\u007f]/.test(key) || !Number.isSafeInteger(id) || id < 0 || !author || author.length > 255 || /[\u0000-\u001f\u007f]/.test(author) || !text || text.length > MAX_MOVE_TEXT_LENGTH || element.querySelector('[data-document-change]') || element.querySelector('[data-document-equation], [data-document-field], [data-document-note-reference], [data-document-content-control], img, br')) throw new Error('Document contains an invalid move revision.');
4149
+ if (this.patches.length >= MAX_MOVE_REVISION_PATCHES) throw new Error('Document exceeds the move revision limit.');
4150
+ const wireId = this.nextWireId;
4151
+ this.nextWireId -= 1;
4152
+ const registration = {
4153
+ kind: 'from' === role ? 'move-from' : 'move-to',
4154
+ wireId,
4155
+ id,
4156
+ author,
4157
+ date
4158
+ };
4159
+ this.registrations.set(element, registration);
4160
+ this.patches.push({
4161
+ wireId,
4162
+ id,
4163
+ role,
4164
+ author,
4165
+ date
4166
+ });
4167
+ return registration;
4168
+ }
4169
+ }
4170
+ async function patchDocxMoveRevisions(buffer, patches) {
4171
+ if (!patches.length) return buffer;
4172
+ if (patches.length > MAX_MOVE_REVISION_PATCHES) throw new Error('Document exceeds the move revision limit.');
4173
+ const archive = await jszip.loadAsync(buffer);
4174
+ const byWireId = new Map();
4175
+ const logicalSides = new Map();
4176
+ for (const patch of patches){
4177
+ if (byWireId.has(patch.wireId)) throw new Error('Generated DOCX move revision wire IDs are duplicated.');
4178
+ byWireId.set(patch.wireId, patch);
4179
+ const logicalKey = `${patch.id}\u0000${patch.author}\u0000${patch.date}`;
4180
+ const sides = logicalSides.get(logicalKey) ?? {
4181
+ from: [],
4182
+ to: []
4183
+ };
4184
+ sides[patch.role].push(patch);
4185
+ logicalSides.set(logicalKey, sides);
4186
+ }
4187
+ for (const sides of logicalSides.values())if (!sides.from.length || !sides.to.length) throw new Error('A DOCX move revision must contain both moveFrom and moveTo sides.');
4188
+ const applied = new Map();
4189
+ const emittedText = new Map();
4190
+ for (const entry of Object.values(archive.files)){
4191
+ if (entry.dir || !work_docx_move_revision_export_STORY_PATTERN.test(entry.name)) continue;
4192
+ const document = parseXml(decodeXmlBytes(await entry.async('uint8array'), `generated DOCX ${entry.name}`), `generated DOCX ${entry.name}`);
4193
+ let changed = false;
4194
+ const wrappers = [
4195
+ ...descendants(document, 'ins'),
4196
+ ...descendants(document, 'del')
4197
+ ];
4198
+ for (const wrapper of wrappers){
4199
+ if (!wrapper.parentNode) continue;
4200
+ if (!DOCX_WORDPROCESSING_NAMESPACES.has(wrapper.namespaceURI ?? '')) continue;
4201
+ const wireId = numericWordAttribute(wrapper, 'id');
4202
+ if (null === wireId) continue;
4203
+ const patch = byWireId.get(wireId);
4204
+ if (!patch) continue;
4205
+ const expectedName = 'from' === patch.role ? 'del' : 'ins';
4206
+ if (wrapper.localName !== expectedName) throw new Error(`Generated DOCX move revision ${patch.wireId} has the wrong wrapper kind.`);
4207
+ const replacement = document.createElementNS(wrapper.namespaceURI, `${xmlNamespacePrefix(wrapper, wrapper.namespaceURI) ?? 'w'}:${'from' === patch.role ? 'moveFrom' : 'moveTo'}`);
4208
+ for (const child of Array.from(wrapper.attributes)){
4209
+ const namespace = xmlAttributeNamespace(wrapper, child);
4210
+ if (namespace) replacement.setAttributeNS(namespace, child.name, child.value);
4211
+ else replacement.setAttribute(child.name, child.value);
4212
+ }
4213
+ work_docx_move_revision_export_setWordAttribute(replacement, 'id', String(patch.id));
4214
+ work_docx_move_revision_export_setWordAttribute(replacement, 'author', patch.author);
4215
+ work_docx_move_revision_export_setWordAttribute(replacement, 'date', patch.date);
4216
+ const text = Array.from(wrapper.querySelectorAll('*')).filter((element)=>'from' === patch.role ? 'delText' === element.localName : 't' === element.localName).map((element)=>element.textContent ?? '').join('');
4217
+ emittedText.set(patch.wireId, `${emittedText.get(patch.wireId) ?? ''}${text}`);
4218
+ while(wrapper.firstChild)replacement.append(wrapper.firstChild);
4219
+ wrapper.replaceWith(replacement);
4220
+ applied.set(patch.wireId, (applied.get(patch.wireId) ?? 0) + 1);
4221
+ changed = true;
4222
+ }
4223
+ if (changed) archive.file(entry.name, serializeUtf8Xml(document));
4224
+ }
4225
+ const missing = patches.filter((patch)=>!applied.has(patch.wireId));
4226
+ if (missing.length) throw new Error(`DOCX move revision markers were not emitted: ${missing.map((patch)=>patch.wireId).join(', ')}.`);
4227
+ for (const sides of logicalSides.values()){
4228
+ const from = sides.from.map((patch)=>emittedText.get(patch.wireId) ?? '').join('');
4229
+ const to = sides.to.map((patch)=>emittedText.get(patch.wireId) ?? '').join('');
4230
+ if (!from || !to || from !== to) throw new Error('A DOCX move revision source and destination must contain the same text.');
4231
+ }
4232
+ return archive.generateAsync({
4233
+ type: 'arraybuffer'
4234
+ });
4235
+ }
4236
+ function moveRole(value) {
4237
+ return 'from' === value || 'to' === value ? value : null;
4238
+ }
4239
+ function numericWordAttribute(element, localName) {
4240
+ const namespace = element.namespaceURI;
4241
+ if (!namespace) return null;
4242
+ const attributes = Array.from(element.attributes).filter((candidate)=>xmlAttributeLocalName(candidate) === localName && xmlAttributeNamespace(element, candidate) === namespace);
4243
+ if (1 !== attributes.length) return null;
4244
+ const value = Number(attributes[0]?.value);
4245
+ return Number.isSafeInteger(value) ? value : null;
4246
+ }
4247
+ function work_docx_move_revision_export_setWordAttribute(element, localName, value) {
4248
+ const namespace = element.namespaceURI ?? work_docx_move_revision_export_WORD_NAMESPACE;
4249
+ const prefix = xmlNamespacePrefix(element, namespace) ?? element.prefix ?? 'w';
4250
+ element.setAttributeNS(namespace, `${prefix}:${localName}`, value);
4251
+ }
4252
+ function work_docx_move_revision_export_normalizedRevisionDate(value) {
4253
+ const time = Date.parse(value ?? '');
4254
+ return Number.isFinite(time) ? new Date(time).toISOString() : new Date().toISOString();
4255
+ }
4131
4256
  const DRAWINGML_NAMESPACES = new Set([
4132
4257
  'http://schemas.openxmlformats.org/drawingml/2006/main',
4133
4258
  'http://purl.oclc.org/ooxml/drawingml/main'
@@ -8526,6 +8651,8 @@ async function createDocxBlob(content, sourcePackage) {
8526
8651
  usedOpenTypeMarkers: new Set(),
8527
8652
  paragraphFormattingChangePatches: new DocxParagraphFormattingChangePatchCollector(),
8528
8653
  numberingChangePatches: new DocxNumberingChangePatchCollector(),
8654
+ moveRevisionPatches: new DocxMoveRevisionPatchCollector(),
8655
+ moveRevisionDefaultDate: new Date().toISOString(),
8529
8656
  tableOfContentsPatches: new DocxTableOfContentsPatchCollector(),
8530
8657
  indexPatches: new DocxIndexPatchCollector(),
8531
8658
  hasExplicitZeroCharacterSpacing: false,
@@ -8606,7 +8733,8 @@ async function createDocxBlob(content, sourcePackage) {
8606
8733
  const indexPatched = await patchDocxIndexes(tableOfContentsPatched, noteContext.indexPatches.patches);
8607
8734
  const paragraphFormattingChangesPatched = await patchDocxParagraphFormattingChanges(indexPatched, noteContext.paragraphFormattingChangePatches.patches);
8608
8735
  const numberingChangesPatched = await patchDocxNumberingChanges(paragraphFormattingChangesPatched, noteContext.numberingChangePatches.patches);
8609
- const equationPatched = await patchDocxEquations(numberingChangesPatched, noteContext.equationPatches.patches);
8736
+ const moveRevisionsPatched = await patchDocxMoveRevisions(numberingChangesPatched, noteContext.moveRevisionPatches.patches);
8737
+ const equationPatched = await patchDocxEquations(moveRevisionsPatched, noteContext.equationPatches.patches);
8610
8738
  const patched = await patchDocxPageColor(equationPatched, normalizedContent.pageColor);
8611
8739
  const contentControlsPatched = await patchDocxContentControls(patched, noteContext.contentControlPatches.patches);
8612
8740
  const preserved = sourcePackage ? await preserveDocxSourcePackage(contentControlsPatched, sourcePackage, {
@@ -8987,19 +9115,19 @@ async function work_docx_export_inlineRuns(root, docx, noteContext) {
8987
9115
  markDocxRunStyleMarkersUsed(inherited.style, noteContext);
8988
9116
  markDocxRunBorderUsed(inherited.border, noteContext);
8989
9117
  markDocxRunShadingUsed(inherited.shading, noteContext);
8990
- if (revision?.kind === 'insertion') return [
9118
+ if (revision?.kind === 'insertion' || revision?.kind === 'move-to') return [
8991
9119
  new docx.InsertedTextRun({
8992
9120
  ...inherited,
8993
- id: revision.id,
9121
+ id: revision.wireId ?? revision.id,
8994
9122
  author: revision.author,
8995
9123
  date: revision.date,
8996
9124
  text: node.textContent
8997
9125
  })
8998
9126
  ];
8999
- if (revision?.kind === 'deletion') return [
9127
+ if (revision?.kind === 'deletion' || revision?.kind === 'move-from') return [
9000
9128
  new docx.DeletedTextRun({
9001
9129
  ...inherited,
9002
- id: revision.id,
9130
+ id: revision.wireId ?? revision.id,
9003
9131
  author: revision.author,
9004
9132
  date: revision.date,
9005
9133
  text: node.textContent
@@ -9050,7 +9178,7 @@ async function work_docx_export_inlineRuns(root, docx, noteContext) {
9050
9178
  for (const child of node.childNodes)children.push(...await visit(child, inherited, revision));
9051
9179
  return docxContentControlRuns(node, docx, noteContext.contentControlPatches, children);
9052
9180
  }
9053
- const textRevisionKind = 'del' === tag ? 'deletion' : 'ins' === tag ? 'insertion' : null;
9181
+ const textRevisionKind = 'del' === tag ? 'move' === node.dataset.changeKind ? 'move-from' : 'deletion' : 'ins' === tag ? 'move' === node.dataset.changeKind ? 'move-to' : 'insertion' : null;
9054
9182
  const change = node.hasAttribute('data-document-change') && textRevisionKind ? docxTextRevision(node, textRevisionKind, noteContext) : revision;
9055
9183
  const formattingChange = node.hasAttribute('data-document-change') && 'formatting' === node.dataset.changeKind ? noteContext.formattingChangePatches.register(node, docxRevisionId(node, noteContext)) : null;
9056
9184
  const commentBoundary = node.hasAttribute('data-document-comment') ? nextDocxCommentBoundary(node.dataset.commentId, noteContext) : null;
@@ -9273,12 +9401,18 @@ function docxTextRevision(element, kind, context) {
9273
9401
  const id = docxRevisionId(element, context);
9274
9402
  const sourceDate = element.dataset.changeDate?.trim() ?? '';
9275
9403
  const time = Date.parse(sourceDate);
9276
- return {
9404
+ const revision = {
9277
9405
  kind,
9278
9406
  id,
9279
9407
  author: element.dataset.changeAuthor?.trim() || 'A3S Work',
9280
- date: Number.isFinite(time) ? new Date(time).toISOString() : new Date().toISOString()
9408
+ date: Number.isFinite(time) ? new Date(time).toISOString() : 'move-from' === kind || 'move-to' === kind ? context.moveRevisionDefaultDate : new Date().toISOString()
9281
9409
  };
9410
+ if ('move-from' === kind || 'move-to' === kind) {
9411
+ const registration = context.moveRevisionPatches.register(element, id, revision.date);
9412
+ if (!registration) throw new Error('Document contains an invalid move revision.');
9413
+ revision.wireId = registration.wireId;
9414
+ }
9415
+ return revision;
9282
9416
  }
9283
9417
  function docxRevisionId(element, context, suffix) {
9284
9418
  const baseKey = element.dataset.changeId?.trim() || `change-${context.nextChangeId}`;
@@ -9293,7 +9427,7 @@ function docxRevisionId(element, context, suffix) {
9293
9427
  }
9294
9428
  function documentHasTrackedChanges(html) {
9295
9429
  const document = new DOMParser().parseFromString(html, 'text/html');
9296
- return Boolean(document.body.querySelector('ins[data-document-change], del[data-document-change], span[data-document-change][data-change-kind="formatting"], [data-document-change][data-change-kind="paragraph-formatting"], [data-document-change][data-change-kind="numbering"]'));
9430
+ return Boolean(document.body.querySelector('ins[data-document-change], del[data-document-change], span[data-document-change][data-change-kind="formatting"], [data-document-change][data-change-kind="paragraph-formatting"], [data-document-change][data-change-kind="numbering"], [data-document-change][data-change-kind="move"]'));
9297
9431
  }
9298
9432
  function anchoredDocumentComments(content) {
9299
9433
  const document = new DOMParser().parseFromString(content.html, 'text/html');
@@ -1,7 +1,7 @@
1
1
  import jszip from "jszip";
2
2
  import { documentRunBorderDomAttributes, contentTypeForPart, bytesToDataUrl, OoxmlPackage, normalizeDocumentIndexesHtml, firstDescendant, normalizeDocumentParagraphId, applyDocumentParagraphIdentityToElement, descendants, documentHighlightDomAttributes, attribute as work_ooxml_package_attribute, documentHighlightFromDocxValue, serializeDocxThemeReference, normalizeDocumentTableOfContentsHtml, directChildren, documentParagraphShadingDomAttributes, documentProofingDomAttributes, documentParagraphBordersDomAttributes, directChild, documentScriptFontSegments, normalizeDocumentParagraphIdentity, documentRunShadingDomAttributes } from "./6968.js";
3
3
  import { normalizeDocumentBookmarkName, renderDocumentTableCellMarginOverrides, applyDocumentImageIdentityToElement, documentCharacterPositionDomAttributes, createDocumentImageIdentityRegistry, normalizeDocumentColumns, documentStrikeDomAttributes, normalizeDocumentImageWrapContour, DOCUMENT_TABLE_ROW_ID_ATTRIBUTE, normalizeDocumentBookmarksHtml, applyDocumentTableRowIdentityToElement, normalizeDocumentCaptionsHtml, documentCharacterSpacingDomAttributes, normalizeDocumentImageAlignment, applyDocumentImageLayerToElement, normalizeDocumentNotesHtml, normalizeDocumentBookmarkReferencesHtml, documentCitationTagsFromInstruction, applyDocumentImageWrapContourToElement, documentUnderlineDomAttributes, documentHiddenTextDomAttributes, normalizeDocumentPageChrome, normalizeDocumentImageLayoutOptions, applyDocumentImageCropToElement, documentPageMarginsForLayout, applyDocumentPageGeometry, createDocumentNoteElement, normalizeDocumentImageLayer, DOCUMENT_TABLE_ROW_TEXT_ID_ATTRIBUTE, documentBookmarkReferenceInstruction, applyDocumentImageTransformToElement, documentInitialSectionLayout, normalizeDocumentFieldsHtml, documentCaptionLabel, documentTableBordersFromElement, isContourImageLayout, normalizeDocumentCitationsHtml, normalizeDocumentImageIdentity, normalizeDocumentImageWrapSide, supportedDocxDocumentFieldInstruction, documentKerningDomAttributes, docxDocumentFieldKind, renderDocumentTableBorders, docxBookmarkReferenceTarget, normalizeDocumentImagePosition, wrapsBesideImage, documentPageChromeLegacyFields, documentCharacterScaleDomAttributes, DEFAULT_DOCUMENT_TABLE_GEOMETRY, documentSectionDomAttributes, DEFAULT_DOCUMENT_TABLE_CELL_MARGINS, documentPageMarginBody, documentLegacyTextEffectsDomAttributes, normalizeDocumentTableRowIdentity, normalizeDocumentBookmarkNativeId, documentOpenTypeDomAttributes, uniqueDocumentImageIdentity, applyDocumentTableGeometryToElement, normalizeDocumentImageCrop, documentContentLayoutProperties, documentEmphasisMarkDomAttributes, docxDocumentFieldTarget } from "./4174.js";
4
- import { hasImportedDocxIndexMarkers, markDocxRunFormattingIntoState, applyImportedDocxParagraphSpacingMarkers, hasImportedDocxParagraphDirectionMarkers, hasImportedDocxParagraphIndentMarkers, resolveDocxParagraphBordersForParagraph, applyImportedDocxTextBoxMarkers, applyImportedDocxNumberingChangeMarkers, applyImportedDocxParagraphShadingMarkers, markDocxParagraphSpacing, docxCaptionBookmark, docxFieldResultText, applyImportedDocxContentControlMarkers, createDocxParagraphStyleResolver, markDocxTextBoxes, docxTableCellStyleLayers, createImportedDocxRunFormattingMarkerState, markDocxContentControls, parseDocxPaperSource, resolveDocxLegacyTextEffects, markDocxTablesOfContents, applyImportedDocxIndexMarkers, docxTablePropertySources, applyImportedDocxTableOfContentsMarkers, markDocxIndexes, parseDirectDocxParagraphShading, markDocxPackageEquations, hasImportedDocxParagraphSpacingMarkers, markDocxParagraphIndents, parseDocxPageMargins, resolveDocxRunBorder, parseDocxPageGeometry, docxCaptionReferenceTarget, applyImportedDocxEquationMarkers, hasImportedDocxParagraphPaginationMarkers, createDocxTableStyleResolver, hasImportedDocxParagraphShadingMarkers, isDocxEquationLikeRoot, importedDocxStrike, docxTableRunPropertySources, hasImportedDocxNumberingChangeMarkers, inspectDocxPageMarginSettings, hasImportedDocxRunFormattingMarkers, hasImportedDocxTableOfContentsMarkers, applyImportedDocxParagraphFormattingChangeMarkers, hasImportedDocxContentControlMarkers, hasImportedDocxParagraphTabStopMarkers, resolveDocxRunShading, docxCaptionSequenceKind, applyImportedDocxRunFormattingMarkers, markDocxParagraphAlignments, markDocxParagraphDirections, hasImportedDocxParagraphBorderMarkers, hasImportedDocxParagraphFormattingChangeMarkers, resolveDocxHiddenText, docxEquationHtml, docxFieldOccurrences, hasImportedDocxParagraphAlignmentMarkers, markDocxParagraphTabStops, applyImportedDocxParagraphIndentMarkers, resolveDocxTableStyleResolver, applyImportedDocxParagraphAlignmentMarkers, hasImportedDocxTextBoxMarkers, markDocxNumberingChanges, importedDocxUnderline, markDocxParagraphBorders, applyImportedDocxParagraphDirectionMarkers, markDocxParagraphPagination, docxFieldOccurrenceIsInlineEditable, applyImportedDocxParagraphBorderMarkers, applyImportedDocxParagraphPaginationMarkers, applyImportedDocxParagraphTabStopMarkers, docxRunPropertySources, markDocxParagraphFormattingChanges, markDocxParagraphShading, parseDocxPageBorders } from "./0~3320.js";
4
+ import { hasImportedDocxIndexMarkers, markDocxRunFormattingIntoState, applyImportedDocxParagraphSpacingMarkers, hasImportedDocxParagraphDirectionMarkers, hasImportedDocxParagraphIndentMarkers, resolveDocxParagraphBordersForParagraph, applyImportedDocxTextBoxMarkers, applyImportedDocxNumberingChangeMarkers, applyImportedDocxParagraphShadingMarkers, applyImportedDocxChangeMarkers, markDocxParagraphSpacing, docxCaptionBookmark, docxFieldResultText, applyImportedDocxContentControlMarkers, createDocxParagraphStyleResolver, markDocxTextBoxes, docxTableCellStyleLayers, markDocxTextChanges, markDocxContentControls, createImportedDocxRunFormattingMarkerState, parseDocxPaperSource, resolveDocxLegacyTextEffects, markDocxTablesOfContents, applyImportedDocxIndexMarkers, docxTablePropertySources, applyImportedDocxTableOfContentsMarkers, markDocxIndexes, parseDirectDocxParagraphShading, markDocxPackageEquations, hasImportedDocxParagraphSpacingMarkers, markDocxParagraphIndents, parseDocxPageMargins, resolveDocxRunBorder, parseDocxPageGeometry, docxCaptionReferenceTarget, applyImportedDocxEquationMarkers, hasImportedDocxParagraphPaginationMarkers, createDocxTableStyleResolver, hasImportedDocxParagraphShadingMarkers, isDocxEquationLikeRoot, importedDocxStrike, docxTableRunPropertySources, hasImportedDocxNumberingChangeMarkers, inspectDocxPageMarginSettings, hasImportedDocxRunFormattingMarkers, hasImportedDocxTableOfContentsMarkers, applyImportedDocxParagraphFormattingChangeMarkers, hasImportedDocxContentControlMarkers, hasImportedDocxParagraphTabStopMarkers, resolveDocxRunShading, docxCaptionSequenceKind, applyImportedDocxRunFormattingMarkers, markDocxParagraphAlignments, markDocxParagraphDirections, hasImportedDocxParagraphBorderMarkers, hasImportedDocxParagraphFormattingChangeMarkers, resolveDocxHiddenText, docxEquationHtml, docxFieldOccurrences, hasImportedDocxParagraphAlignmentMarkers, markDocxParagraphTabStops, applyImportedDocxParagraphIndentMarkers, applyImportedDocxParagraphDirectionMarkers, applyImportedDocxParagraphAlignmentMarkers, resolveDocxTableStyleResolver, hasImportedDocxTextBoxMarkers, importedDocxUnderline, markDocxParagraphBorders, markDocxNumberingChanges, markDocxParagraphPagination, hasImportedDocxChangeMarkers, docxFieldOccurrenceIsInlineEditable, applyImportedDocxParagraphBorderMarkers, applyImportedDocxParagraphPaginationMarkers, applyImportedDocxParagraphTabStopMarkers, docxRunPropertySources, markDocxParagraphFormattingChanges, markDocxParagraphShading, parseDocxPageBorders } from "./0~5600.js";
5
5
  import { readDocxBibliography, resolveDocxProofing, XMLNS_NAMESPACE, docxCharacterScalePercentFromProperties, docxCharacterSpacingTwipsFromProperties, parseBoundedDocxInteger, resolveDocxOpenTypeFeatures, xmlAttributeLocalName, resolveDocxEmphasisMark, createDocxThemeResolver, docxCharacterPositionHalfPointsFromProperties, readDocxImageTransform, docxThemeColor, parseDocxParagraphDefaultCollapsed, resolveDocxKerningThresholdHalfPoints, resolveDocxThemeResolver, DOCX_WORDPROCESSING_NAMESPACES, xmlAttributeNamespace } from "./0~3534.js";
6
6
  import { importDocxPageColor, importedDocumentNoteId } from "./0~4980.js";
7
7
  const WORD_NAMESPACE = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
@@ -428,121 +428,6 @@ function work_docx_caption_import_textNodes(root) {
428
428
  while(walker.nextNode())nodes.push(walker.currentNode);
429
429
  return nodes;
430
430
  }
431
- const work_docx_change_import_WORD_NAMESPACE = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
432
- const work_docx_change_import_XML_NAMESPACE = 'http://www.w3.org/XML/1998/namespace';
433
- function markDocxTextChanges(document) {
434
- const changes = [];
435
- const revisions = [
436
- ...descendants(document, 'ins'),
437
- ...descendants(document, 'del')
438
- ].sort(compareDocumentOrder);
439
- for (const revision of revisions){
440
- if (!revision.parentNode || closestRevision(revision.parentElement)) continue;
441
- const kind = 'del' === revision.localName ? 'deletion' : 'insertion';
442
- if (!revisionText(revision, kind)) continue;
443
- if ('deletion' === kind) convertDeletedText(document, revision);
444
- const index = changes.length + 1;
445
- const sourceId = work_ooxml_package_attribute(revision, 'id')?.trim() ?? '';
446
- const id = uniqueChangeId(sourceId ? `docx-change-${sourceId}` : `docx-change-${index}`, changes);
447
- const marker = {
448
- id,
449
- kind,
450
- author: work_ooxml_package_attribute(revision, 'author')?.trim() || '未知审阅者',
451
- date: normalizeDate(work_ooxml_package_attribute(revision, 'date')),
452
- start: `__A3S_WORK_CHANGE_START_${index}__`,
453
- end: `__A3S_WORK_CHANGE_END_${index}__`
454
- };
455
- unwrapRevision(document, revision, marker.start, marker.end);
456
- changes.push(marker);
457
- }
458
- return {
459
- changes
460
- };
461
- }
462
- function applyImportedDocxChangeMarkers(document, markers) {
463
- for (const marker of markers.changes){
464
- const element = document.createElement('deletion' === marker.kind ? 'del' : 'ins');
465
- element.dataset.documentChange = 'true';
466
- element.dataset.changeKind = marker.kind;
467
- element.dataset.changeId = marker.id;
468
- element.dataset.changeAuthor = marker.author;
469
- element.dataset.changeDate = marker.date;
470
- wrapMarkerRange(document.body, marker.start, marker.end, element);
471
- }
472
- }
473
- function hasImportedDocxChangeMarkers(markers) {
474
- return markers.changes.length > 0;
475
- }
476
- function revisionText(revision, kind) {
477
- const names = 'deletion' === kind ? [
478
- 'delText',
479
- 't'
480
- ] : [
481
- 't'
482
- ];
483
- return names.flatMap((name)=>descendants(revision, name)).map((element)=>element.textContent ?? '').join('');
484
- }
485
- function convertDeletedText(document, revision) {
486
- for (const deleted of descendants(revision, 'delText')){
487
- const text = document.createElementNS(work_docx_change_import_WORD_NAMESPACE, 'w:t');
488
- const preserve = deleted.getAttributeNS(work_docx_change_import_XML_NAMESPACE, 'space') ?? deleted.getAttribute('xml:space');
489
- if (preserve) text.setAttributeNS(work_docx_change_import_XML_NAMESPACE, 'xml:space', preserve);
490
- text.textContent = deleted.textContent;
491
- deleted.replaceWith(text);
492
- }
493
- }
494
- function unwrapRevision(document, revision, start, end) {
495
- const parent = revision.parentNode;
496
- if (!parent) return;
497
- parent.insertBefore(work_docx_change_import_markerRun(document, start), revision);
498
- while(revision.firstChild)parent.insertBefore(revision.firstChild, revision);
499
- parent.insertBefore(work_docx_change_import_markerRun(document, end), revision);
500
- revision.remove();
501
- }
502
- function work_docx_change_import_markerRun(document, value) {
503
- const run = document.createElementNS(work_docx_change_import_WORD_NAMESPACE, 'w:r');
504
- const text = document.createElementNS(work_docx_change_import_WORD_NAMESPACE, 'w:t');
505
- text.setAttributeNS(work_docx_change_import_XML_NAMESPACE, 'xml:space', 'preserve');
506
- text.textContent = value;
507
- run.append(text);
508
- return run;
509
- }
510
- function wrapMarkerRange(root, start, end, wrapper) {
511
- const html = root.innerHTML;
512
- const startIndex = html.indexOf(start);
513
- const endIndex = html.indexOf(end, startIndex + start.length);
514
- if (startIndex < 0 || endIndex < 0) return false;
515
- const closingTag = `</${wrapper.localName}>`;
516
- const serializedWrapper = wrapper.outerHTML;
517
- if (!serializedWrapper.endsWith(closingTag)) return false;
518
- const openingTag = serializedWrapper.slice(0, -closingTag.length);
519
- root.innerHTML = `${html.slice(0, startIndex)}${openingTag}${html.slice(startIndex + start.length, endIndex)}${closingTag}${html.slice(endIndex + end.length)}`;
520
- return true;
521
- }
522
- function closestRevision(element) {
523
- let current = element;
524
- while(current){
525
- if ('ins' === current.localName || 'del' === current.localName) return current;
526
- current = current.parentElement;
527
- }
528
- return null;
529
- }
530
- function uniqueChangeId(base, changes) {
531
- const ids = new Set(changes.map((change)=>change.id));
532
- if (!ids.has(base)) return base;
533
- let suffix = 2;
534
- while(ids.has(`${base}-${suffix}`))suffix += 1;
535
- return `${base}-${suffix}`;
536
- }
537
- function normalizeDate(value) {
538
- if (!value) return '';
539
- const time = Date.parse(value);
540
- return Number.isFinite(time) ? new Date(time).toISOString() : '';
541
- }
542
- function compareDocumentOrder(left, right) {
543
- if (left === right) return 0;
544
- return left.compareDocumentPosition(right) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1;
545
- }
546
431
  const work_docx_citation_import_WORD_NAMESPACE = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
547
432
  const work_docx_citation_import_XML_NAMESPACE = 'http://www.w3.org/XML/1998/namespace';
548
433
  function markDocxCitationFields(document) {
@@ -744,7 +629,7 @@ async function markDocxComments(document, archive) {
744
629
  const workIds = new Map();
745
630
  const ranges = [];
746
631
  const comments = [];
747
- const starts = descendants(document, 'commentRangeStart').sort(work_docx_comment_import_compareDocumentOrder);
632
+ const starts = descendants(document, 'commentRangeStart').sort(compareDocumentOrder);
748
633
  for (const start of starts){
749
634
  const sourceId = work_ooxml_package_attribute(start, 'id')?.trim() ?? '';
750
635
  if (!sourceId) continue;
@@ -794,7 +679,7 @@ async function readCommentDefinitions(archive) {
794
679
  return {
795
680
  sourceId: work_ooxml_package_attribute(comment, 'id')?.trim() ?? '',
796
681
  author: work_ooxml_package_attribute(comment, 'author')?.trim() || '未知审阅者',
797
- date: work_docx_comment_import_normalizeDate(work_ooxml_package_attribute(comment, 'date')),
682
+ date: normalizeDate(work_ooxml_package_attribute(comment, 'date')),
798
683
  text: commentText(comment),
799
684
  paraId,
800
685
  parentParaId: metadata?.parentParaId ?? '',
@@ -922,12 +807,12 @@ function uniqueWorkCommentId(base, comments) {
922
807
  while(ids.has(`${base}-${suffix}`))suffix += 1;
923
808
  return `${base}-${suffix}`;
924
809
  }
925
- function work_docx_comment_import_normalizeDate(value) {
810
+ function normalizeDate(value) {
926
811
  if (!value) return '';
927
812
  const time = Date.parse(value);
928
813
  return Number.isFinite(time) ? new Date(time).toISOString() : '';
929
814
  }
930
- function work_docx_comment_import_compareDocumentOrder(left, right) {
815
+ function compareDocumentOrder(left, right) {
931
816
  if (left === right) return 0;
932
817
  return left.compareDocumentPosition(right) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1;
933
818
  }