# insertOoxml Replace across paragraphs

What insertOoxml's Replace does over a range that crosses paragraph marks, table cells or a content control's edge, with tracking off and on.

`insertOoxml(…, 'Replace')` over a range across paragraph marks joins what the range spans or, under tracking, marks it deleted. Under `TrackAll`, replacing a paragraph's `Whole` range with a package marks the old text deleted and keeps the paragraph's mark:

```js
await Word.run(async context => {
  const body = context.document.body;
  body.insertParagraph('Payment is due in 30 days.', 'End');
  body.insertParagraph('Payment is due in 45 days.', 'End');
  await context.sync();
});
await Word.run(async context => {
  const paragraphs = context.document.body.paragraphs;
  paragraphs.load('items');
  await context.sync();
  const [, old, revised] = paragraphs.items;
  const pkg = revised.getOoxml();
  await context.sync();
  context.document.changeTrackingMode = Word.ChangeTrackingMode.trackAll;
  old.getRange('Whole').insertOoxml(pkg.value, 'Replace');
  const changes = context.document.body.getTrackedChanges();
  changes.load('items/type,items/text');
  old.load('text');
  await context.sync();
  // changes.items.map(c => [c.type, c.text]) -> [["Added", "Payment is due in 45 days."], ["Deleted", "Payment is due in 30 days."]]
  // old.text -> "Payment is due in 45 days.Payment is due in 30 days."
});
```

### An `insertOoxml` `Replace` joins what its range spans

With tracking off, `insertOoxml(…, 'Replace')` over a range across paragraph marks takes everything between, a block content control included. It joins the text before the range and the text after it around the package. Under `TrackMineOnly`, where `insertOoxml` tracks nothing, it joins the same way. A range that ends at a paragraph's start joins nothing. A package that would land inside a plain-text content control throws `NotAllowed`.

The joined paragraph is the one whose mark ends the range. Its `Paragraph` object reads the joined text. Every range in it keeps its offsets there, whether a `search` hit from a sync that only read or one that wrote. So a hit on `gggg` at 5 to 9 reads `bbbb` once `aaaa bbbb cccc ` sits before it.

The paragraphs the range starts in and crosses are gone. These throw `ItemNotFound`:

- their `Paragraph` objects and every range in them;
- every range running into them from a paragraph before;
- every tracked change listed in them;
- the body's own `getRange()`, when the range starts in the body's first paragraph.

A package of several paragraphs then splits the joined paragraph, which keeps the part holding its mark.

### Across table cells

With tracking off, or under `TrackMineOnly`, a `Replace` goes through across table cells too, where `delete()` and `insertText` throw `GeneralException`. The first cell the range reaches holds the join, in the paragraph the range ends in. That cell follows the cells before it in its row, and the cells after the range in the row it ends in follow it. The cells and rows between go. A row left shorter than the others skips the rest of the grid with `gridAfter`.

| Range | Result |
|---|---|
| from before a table into it | the paragraph's text joins the table's first cell |
| from a cell out of the table | the cell's text joins the paragraph after |
| over exactly one table, from its first cell's start through its last cell's end | the table goes, and the package's last paragraph joins the paragraph after, which keeps its object |

### Into or out of a block content control

With tracking off, or under `TrackMineOnly`, a `Replace` into or out of a block content control's paragraph joins the same way. The control is left inline around what is left of its text, empty when nothing is. It's gone when the range held its only paragraph from its start.

The package lands inside the control the range began in, past any spaces that ended the control's text. Those spaces leave the control, as they do for an inline control.

A control that keeps other paragraphs stays a block. The text after the range sits apart in the paragraph after it, and the controls around that paragraph stay blocks too. The range the call returns ends at that paragraph's start.

### A tracked `Replace` from a paragraph's start

Under `TrackAll`, a `Replace` across a mark goes through as a tracked edit when its range:

- starts at a paragraph's start, a table cell's included;
- holds less than the body's or the table's whole text;
- crosses no block content control's edge.

It also goes through when every mark it crosses is one an `insertOoxml` put in. Such a tracked edit does this:

- The package lands at the range's start.
- The text up to the range's last paragraph's start is marked deleted, and so are the marks between. A mark an `insertOoxml` put in goes instead.
- The paragraph whose mark ends the range keeps its object.
- The range the call returns, and the one it was called on, run from the package to that paragraph's start while it stands apart.

A tracked `Replace` whose range ends just past a paragraph mark deletes short of that mark, which stays. A paragraph's `Whole` range is such a range, as in the example above.

### A tracked `Replace` that changes nothing

Under `TrackAll`, these throw no error and change nothing:

- a `Replace` from inside a paragraph's text across a mark the document had;
- a `Replace` over the body's whole text, from its first paragraph's start to its last paragraph's text end or past its mark;
- a `Replace` over a whole table.

`paragraphs`, the body's `text` and `getTrackedChanges` read the document as it was. The range the call returns, and the one it was called on, run from the range's start to the start of its last paragraph. Over exactly one table, they run to its end. The one it was called on keeps its offsets. `getOoxml` writes the document as it was.

**Differs from Word for the web:** Word's reads stay as they were, in later runs too, but its `getOoxml` writes a half-applied edit. That edit holds the package's text untracked at the range's start, the range's first paragraph mark deleted and some of its text deleted, which differs from run to run. A later edit lands in that half-applied document without the reads showing it. Once the body's `getOoxml` is read, the paragraphs and the tracked changes show it too, as a document holding that package reads it. Word's reads and its package disagree, so the simulator follows the reads.

---

Source: https://www.rystic.ai/docs/simulators/word/features/ooxml-replace · Markdown: https://www.rystic.ai/docs/simulators/word/features/ooxml-replace.md
