docxmlater 10.3.4 → 10.3.6

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.
@@ -403,39 +403,91 @@ export class DocumentTrackingContext implements TrackingContext {
403
403
  }
404
404
 
405
405
  // Apply tcPrChange to each TableCell
406
+ // Per ECMA-376 §17.13.5.37, tcPrChange must contain FULL previous tcPr,
407
+ // not just the delta of changed properties.
406
408
  for (const [cell, changes] of cellChanges) {
407
- this.applyElementPrChange(changes, (prevProps, getNextId, date) => {
408
- const existing = cell.getTcPrChange();
409
- if (existing) {
410
- const merged = { ...(existing.previousProperties || {}), ...prevProps };
411
- cell.setTcPrChange({ ...existing, previousProperties: merged });
409
+ // Build full snapshot: start from current formatting, roll back changed properties
410
+ const currentFormatting = cell.getFormatting();
411
+ const fullPrevProps: Record<string, unknown> = {};
412
+
413
+ for (const [key, value] of Object.entries(currentFormatting)) {
414
+ if (value !== undefined) {
415
+ fullPrevProps[key] = value;
416
+ }
417
+ }
418
+
419
+ // Roll back changed properties to their previous values
420
+ let latestTimestamp = 0;
421
+ for (const change of changes) {
422
+ if (change.previousValue !== undefined) {
423
+ fullPrevProps[change.property] = change.previousValue;
412
424
  } else {
413
- cell.setTcPrChange({
414
- author: this.author,
415
- date,
416
- id: String(getNextId()),
417
- previousProperties: prevProps,
418
- });
425
+ delete fullPrevProps[change.property];
419
426
  }
420
- });
427
+ if (change.timestamp > latestTimestamp) {
428
+ latestTimestamp = change.timestamp;
429
+ }
430
+ }
431
+
432
+ const date = formatDateForXml(new Date(latestTimestamp));
433
+
434
+ const existing = cell.getTcPrChange();
435
+ if (existing) {
436
+ // Merge: existing previous state takes precedence (it's the ORIGINAL baseline)
437
+ const merged = { ...fullPrevProps, ...(existing.previousProperties || {}) };
438
+ cell.setTcPrChange({ ...existing, previousProperties: merged });
439
+ } else {
440
+ cell.setTcPrChange({
441
+ author: this.author,
442
+ date,
443
+ id: String(this.revisionManager.consumeNextId()),
444
+ previousProperties: fullPrevProps,
445
+ });
446
+ }
421
447
  }
422
448
 
423
449
  // Apply sectPrChange to each Section
450
+ // Per ECMA-376 §17.13.5.32, sectPrChange must contain FULL previous sectPr,
451
+ // not just the delta of changed properties.
424
452
  for (const [section, changes] of sectionChanges) {
425
- this.applyElementPrChange(changes, (prevProps, getNextId, date) => {
426
- const existing = section.getSectPrChange();
427
- if (existing) {
428
- const merged = { ...(existing.previousProperties || {}), ...prevProps };
429
- section.setSectPrChange({ ...existing, previousProperties: merged });
453
+ // Build full snapshot: start from current properties, roll back changed properties
454
+ const currentProps = section.getProperties();
455
+ const fullPrevProps: Record<string, unknown> = {};
456
+
457
+ for (const [key, value] of Object.entries(currentProps)) {
458
+ if (value !== undefined) {
459
+ fullPrevProps[key] = value;
460
+ }
461
+ }
462
+
463
+ // Roll back changed properties to their previous values
464
+ let latestTimestamp = 0;
465
+ for (const change of changes) {
466
+ if (change.previousValue !== undefined) {
467
+ fullPrevProps[change.property] = change.previousValue;
430
468
  } else {
431
- section.setSectPrChange({
432
- author: this.author,
433
- date,
434
- id: String(getNextId()),
435
- previousProperties: prevProps,
436
- });
469
+ delete fullPrevProps[change.property];
437
470
  }
438
- });
471
+ if (change.timestamp > latestTimestamp) {
472
+ latestTimestamp = change.timestamp;
473
+ }
474
+ }
475
+
476
+ const date = formatDateForXml(new Date(latestTimestamp));
477
+
478
+ const existing = section.getSectPrChange();
479
+ if (existing) {
480
+ // Merge: existing previous state takes precedence (it's the ORIGINAL baseline)
481
+ const merged = { ...fullPrevProps, ...(existing.previousProperties || {}) };
482
+ section.setSectPrChange({ ...existing, previousProperties: merged });
483
+ } else {
484
+ section.setSectPrChange({
485
+ author: this.author,
486
+ date,
487
+ id: String(this.revisionManager.consumeNextId()),
488
+ previousProperties: fullPrevProps,
489
+ });
490
+ }
439
491
  }
440
492
 
441
493
  // Apply rPrChange to each Run that has property changes