diff --git a/wax-prosemirror-services/src/TrackChangeService/track-changes/helpers/addMarkStep.js b/wax-prosemirror-services/src/TrackChangeService/track-changes/helpers/addMarkStep.js
new file mode 100644
index 0000000000000000000000000000000000000000..f5031d00cdf72939c2696a74cec017ace1e5683f
--- /dev/null
+++ b/wax-prosemirror-services/src/TrackChangeService/track-changes/helpers/addMarkStep.js
@@ -0,0 +1,60 @@
+const addMarkStep = (state, tr, step, newTr, map, doc, user, date) => {
+  doc.nodesBetween(step.from, step.to, (node, pos) => {
+    if (!node.isInline) {
+      return true;
+    }
+    if (node.marks.find(mark => mark.type.name === "deletion")) {
+      return false;
+    } else {
+      newTr.addMark(
+        Math.max(step.from, pos),
+        Math.min(step.to, pos + node.nodeSize),
+        step.mark
+      );
+    }
+    if (
+      ["em", "strong", "underline"].includes(step.mark.type.name) &&
+      !node.marks.find(mark => mark.type === step.mark.type)
+    ) {
+      const formatChangeMark = node.marks.find(
+        mark => mark.type.name === "format_change"
+      );
+      let after, before;
+      if (formatChangeMark) {
+        if (formatChangeMark.attrs.before.includes(step.mark.type.name)) {
+          before = formatChangeMark.attrs.before.filter(
+            markName => markName !== step.mark.type.name
+          );
+          after = formatChangeMark.attrs.after;
+        } else {
+          before = formatChangeMark.attrs.before;
+          after = formatChangeMark.attrs.after.concat(step.mark.type.name);
+        }
+      } else {
+        before = [];
+        after = [step.mark.type.name];
+      }
+      if (after.length || before.length) {
+        newTr.addMark(
+          Math.max(step.from, pos),
+          Math.min(step.to, pos + node.nodeSize),
+          state.schema.marks.format_change.create({
+            user: user.userId,
+            username: user.username,
+            date,
+            before,
+            after
+          })
+        );
+      } else if (formatChangeMark) {
+        newTr.removeMark(
+          Math.max(step.from, pos),
+          Math.min(step.to, pos + node.nodeSize),
+          formatChangeMark
+        );
+      }
+    }
+  });
+};
+
+export default addMarkStep;
diff --git a/wax-prosemirror-services/src/TrackChangeService/track-changes/helpers/markDeletion.js b/wax-prosemirror-services/src/TrackChangeService/track-changes/helpers/markDeletion.js
new file mode 100644
index 0000000000000000000000000000000000000000..b4c76ef12c7d93330e415335a38d6245fc0fdd3f
--- /dev/null
+++ b/wax-prosemirror-services/src/TrackChangeService/track-changes/helpers/markDeletion.js
@@ -0,0 +1,102 @@
+import { Selection, TextSelection } from "prosemirror-state";
+import { Slice } from "prosemirror-model";
+import { ReplaceStep, Mapping } from "prosemirror-transform";
+
+const markDeletion = (tr, from, to, user, date) => {
+  const deletionMark = tr.doc.type.schema.marks.deletion.create({
+    user: user.userId,
+    username: user.username,
+    date
+  });
+  let firstTableCellChild = false;
+  const deletionMap = new Mapping();
+  // Add deletion mark to block nodes (figures, text blocks) and find already deleted inline nodes (and leave them alone)
+  tr.doc.nodesBetween(from, to, (node, pos) => {
+    if (pos < from && node.type.name === "table_cell") {
+      firstTableCellChild = true;
+      return true;
+    } else if ((pos < from && node.isBlock) || firstTableCellChild) {
+      firstTableCellChild = false;
+      return true;
+    } else if (["table_row", "table_cell"].includes(node.type.name)) {
+      return false;
+    } else if (
+      node.isInline &&
+      node.marks.find(
+        mark =>
+          mark.type.name === "insertion" && mark.attrs.user === user.userId
+      )
+    ) {
+      const removeStep = new ReplaceStep(
+        deletionMap.map(Math.max(from, pos)),
+        deletionMap.map(Math.min(to, pos + node.nodeSize)),
+        Slice.empty
+      );
+      if (!tr.maybeStep(removeStep).failed) {
+        deletionMap.appendMap(removeStep.getMap());
+      }
+    } else if (
+      node.isInline &&
+      !node.marks.find(mark => mark.type.name === "deletion")
+    ) {
+      tr.addMark(
+        deletionMap.map(Math.max(from, pos)),
+        deletionMap.map(Math.min(to, pos + node.nodeSize)),
+        deletionMark
+      );
+    } else if (
+      node.attrs.track &&
+      !node.attrs.track.find(trackAttr => trackAttr.type === "deletion") &&
+      !["bullet_list", "ordered_list"].includes(node.type.name)
+    ) {
+      if (
+        node.attrs.track.find(
+          trackAttr =>
+            trackAttr.type === "insertion" && trackAttr.user === user.userId
+        )
+      ) {
+        let removeStep;
+        // user has created element. so (s)he is allowed to delete it again.
+        if (node.isTextblock && to < pos + node.nodeSize) {
+          // The node is a textblock. So we need to merge into the last possible position inside the last text block.
+          const selectionBefore = Selection.findFrom(tr.doc.resolve(pos), -1);
+          if (selectionBefore instanceof TextSelection) {
+            removeStep = new ReplaceStep(
+              deletionMap.map(selectionBefore.$anchor.pos),
+              deletionMap.map(to),
+              Slice.empty
+            );
+          }
+        } else {
+          removeStep = new ReplaceStep(
+            deletionMap.map(Math.max(from, pos)),
+            deletionMap.map(Math.min(to, pos + node.nodeSize)),
+            Slice.empty
+          );
+        }
+
+        if (!tr.maybeStep(removeStep).failed) {
+          deletionMap.appendMap(removeStep.getMap());
+        }
+      } else {
+        const track = node.attrs.track.slice();
+        track.push({
+          type: "deletion",
+          user: user.userId,
+          username: user.username,
+          date
+        });
+        tr.setNodeMarkup(
+          deletionMap.map(pos),
+          null,
+          Object.assign({}, node.attrs, { track }),
+          node.marks
+        );
+      }
+    }
+  });
+
+  return deletionMap;
+};
+
+export default markDeletion;
diff --git a/wax-prosemirror-services/src/TrackChangeService/track-changes/helpers/markInsertion.js b/wax-prosemirror-services/src/TrackChangeService/track-changes/helpers/markInsertion.js
new file mode 100644
index 0000000000000000000000000000000000000000..7d06539058e62114dae60b7fd07996bd4c125afb
--- /dev/null
+++ b/wax-prosemirror-services/src/TrackChangeService/track-changes/helpers/markInsertion.js
@@ -0,0 +1,47 @@
+const markInsertion = (tr, from, to, user, date) => {
+  tr.removeMark(from, to, tr.doc.type.schema.marks.deletion);
+  tr.removeMark(from, to, tr.doc.type.schema.marks.insertion);
+  const insertionMark = tr.doc.type.schema.marks.insertion.create({
+    user: user.userId,
+    username: user.username,
+    date
+  });
+  tr.addMark(from, to, insertionMark);
+  // Add insertion mark also to block nodes (figures, text blocks) but not table cells/rows and lists.
+  tr.doc.nodesBetween(from, to, (node, pos) => {
+    if (
+      pos < from ||
+      ["bullet_list", "ordered_list"].includes(node.type.name)
+    ) {
+      return true;
+    } else if (
+      node.isInline ||
+      ["table_row", "table_cell"].includes(node.type.name)
+    ) {
+      return false;
+    }
+    if (node.attrs.track) {
+      const track = [];
+
+      track.push({
+        type: "insertion",
+        user: user.userId,
+        username: user.username,
+        date
+      });
+
+      tr.setNodeMarkup(
+        pos,
+        null,
+        Object.assign({}, node.attrs, { track }),
+        node.marks
+      );
+    }
+    if (node.type.name === "table") {
+      // A table was inserted. We don't add track marks to elements inside of it.
+      return false;
+    }
+  });
+};
+
+export default markInsertion;
diff --git a/wax-prosemirror-services/src/TrackChangeService/track-changes/helpers/markWrapping.js b/wax-prosemirror-services/src/TrackChangeService/track-changes/helpers/markWrapping.js
new file mode 100644
index 0000000000000000000000000000000000000000..248cc97621204705d94cc1d47102c20fdcc1ccdf
--- /dev/null
+++ b/wax-prosemirror-services/src/TrackChangeService/track-changes/helpers/markWrapping.js
@@ -0,0 +1,41 @@
+import { v4 as uuidv4 } from "uuid";
+
+const markWrapping = (tr, pos, oldNode, newNode, user, date) => {
+  let track = oldNode.attrs.track.slice(),
+    blockTrack = track.find(track => track.type === "block_change");
+
+  if (blockTrack) {
+    track = track.filter(track => track !== blockTrack);
+    if (
+      blockTrack.before.type !== newNode.type.name ||
+      blockTrack.before.attrs.level !== newNode.attrs.level
+    ) {
+      blockTrack = {
+        type: "block_change",
+        user: user.id,
+        username: user.username,
+        date,
+        before: blockTrack.before
+      };
+      track.push(blockTrack);
+    }
+  } else {
+    blockTrack = {
+      type: "block_change",
+      user: user.id,
+      username: user.username,
+      date,
+      before: { type: oldNode.type.name, attrs: oldNode.attrs }
+    };
+    if (blockTrack.before.attrs.id) {
+      delete blockTrack.before.attrs.id;
+    }
+    if (blockTrack.before.attrs.track) {
+      delete blockTrack.before.attrs.track;
+    }
+    track.push(blockTrack);
+  }
+  tr.setNodeMarkup(pos, null, Object.assign({}, newNode.attrs, { track }));
+};
+
+export default markWrapping;
diff --git a/wax-prosemirror-services/src/TrackChangeService/track-changes/helpers/removeMarkStep.js b/wax-prosemirror-services/src/TrackChangeService/track-changes/helpers/removeMarkStep.js
new file mode 100644
index 0000000000000000000000000000000000000000..f53d6af877edd9d7a3fa6a0809e399759cfe71d9
--- /dev/null
+++ b/wax-prosemirror-services/src/TrackChangeService/track-changes/helpers/removeMarkStep.js
@@ -0,0 +1,61 @@
+const removeMarkStep = (state, tr, step, newTr, map, doc, user, date) => {
+  doc.nodesBetween(step.from, step.to, (node, pos) => {
+    if (!node.isInline) {
+      return true;
+    }
+    if (node.marks.find(mark => mark.type.name === "deletion")) {
+      return false;
+    } else {
+      newTr.removeMark(
+        Math.max(step.from, pos),
+        Math.min(step.to, pos + node.nodeSize),
+        step.mark
+      );
+    }
+
+    if (
+      ["em", "strong", "underline"].includes(step.mark.type.name) &&
+      node.marks.find(mark => mark.type === step.mark.type)
+    ) {
+      const formatChangeMark = node.marks.find(
+        mark => mark.type.name === "format_change"
+      );
+      let after, before;
+      if (formatChangeMark) {
+        if (formatChangeMark.attrs.after.includes(step.mark.type.name)) {
+          after = formatChangeMark.attrs.after.filter(
+            markName => markName !== step.mark.type.name
+          );
+          before = formatChangeMark.attrs.before;
+        } else {
+          after = formatChangeMark.attrs.after;
+          before = formatChangeMark.attrs.before.concat(step.mark.type.name);
+        }
+      } else {
+        after = [];
+        before = [step.mark.type.name];
+      }
+      if (after.length || before.length) {
+        newTr.addMark(
+          Math.max(step.from, pos),
+          Math.min(step.to, pos + node.nodeSize),
+          state.schema.marks.format_change.create({
+            user: user.userId,
+            username: user.username,
+            date,
+            before,
+            after
+          })
+        );
+      } else if (formatChangeMark) {
+        newTr.removeMark(
+          Math.max(step.from, pos),
+          Math.min(step.to, pos + node.nodeSize),
+          formatChangeMark
+        );
+      }
+    }
+  });
+};
+
+export default removeMarkStep;
diff --git a/wax-prosemirror-services/src/TrackChangeService/track-changes/helpers/replaceAroundStep.js b/wax-prosemirror-services/src/TrackChangeService/track-changes/helpers/replaceAroundStep.js
new file mode 100644
index 0000000000000000000000000000000000000000..f7eb19824f4469286694c8e443f41301aaacaf0d
--- /dev/null
+++ b/wax-prosemirror-services/src/TrackChangeService/track-changes/helpers/replaceAroundStep.js
@@ -0,0 +1,57 @@
+import markDeletion from "./markDeletion";
+import markInsertion from "./markInsertion";
+import markWrapping from "./markWrapping";
+
+const replaceAroundStep = (state, tr, step, newTr, map, doc, user, date) => {
+  if (step.from === step.gapFrom && step.to === step.gapTo) {
+    // wrapped in something
+    newTr.step(step);
+    const from = step.getMap().map(step.from, -1);
+    const to = step.getMap().map(step.gapFrom);
+    markInsertion(newTr, from, to, user, date);
+  } else if (!step.slice.size) {
+    // unwrapped from something
+    map.appendMap(step.invert(doc).getMap());
+    map.appendMap(markDeletion(newTr, step.from, step.gapFrom, user, date));
+  } else if (
+    step.slice.size === 2 &&
+    step.gapFrom - step.from === 1 &&
+    step.to - step.gapTo === 1
+  ) {
+    // Replaced one wrapping with another
+    newTr.step(step);
+    const oldNode = doc.nodeAt(step.from);
+    if (oldNode.attrs.track) {
+      markWrapping(
+        newTr,
+        step.from,
+        oldNode,
+        step.slice.content.firstChild,
+        user,
+        date
+      );
+    }
+  } else {
+    newTr.step(step);
+    const ranges = [
+      {
+        from: step.getMap().map(step.from, -1),
+        to: step.getMap().map(step.gapFrom)
+      },
+      {
+        from: step.getMap().map(step.gapTo, -1),
+        to: step.getMap().map(step.to)
+      }
+    ];
+    ranges.forEach(range =>
+      doc.nodesBetween(range.from, range.to, (node, pos) => {
+        if (pos < range.from) {
+          return true;
+        }
+        markInsertion(newTr, range.from, range.to, user, date);
+      })
+    );
+  }
+};
+
+export default replaceAroundStep;
diff --git a/wax-prosemirror-services/src/TrackChangeService/track-changes/helpers/replaceStep.js b/wax-prosemirror-services/src/TrackChangeService/track-changes/helpers/replaceStep.js
new file mode 100644
index 0000000000000000000000000000000000000000..e0bfd55efbdbe50ef3d8215587167ad9b75f27f9
--- /dev/null
+++ b/wax-prosemirror-services/src/TrackChangeService/track-changes/helpers/replaceStep.js
@@ -0,0 +1,51 @@
+import { ReplaceStep } from "prosemirror-transform";
+import { CellSelection } from "prosemirror-tables";
+
+import markDeletion from "./markDeletion";
+import markInsertion from "./markInsertion";
+
+const replaceStep = (state, tr, step, newTr, map, doc, user, date) => {
+  // We only insert content if this is not directly a tr for cell deletion. This is because tables delete rows by deleting the
+  // contents of each cell and replacing it with an empty paragraph.
+  const cellDeleteTr =
+    ["deleteContentBackward", "deleteContentForward"].includes(
+      tr.getMeta("inputType")
+    ) && state.selection instanceof CellSelection;
+
+  const newStep = !cellDeleteTr
+    ? new ReplaceStep(
+        step.to, // We insert all the same steps, but with "from"/"to" both set to "to" in order not to delete content. Mapped as needed.
+        step.to,
+        step.slice,
+        step.structure
+      )
+    : false;
+  // We didn't apply the original step in its original place. We adjust the map accordingly.
+  map.appendMap(step.invert(doc).getMap());
+  if (newStep) {
+    const trTemp = state.apply(newTr).tr;
+    if (trTemp.maybeStep(newStep).failed) {
+      return;
+    }
+    const mappedNewStepTo = newStep.getMap().map(newStep.to);
+    markInsertion(trTemp, newStep.from, mappedNewStepTo, user, date);
+    // We condense it down to a single replace step.
+    const condensedStep = new ReplaceStep(
+      newStep.from,
+      newStep.to,
+      trTemp.doc.slice(newStep.from, mappedNewStepTo)
+    );
+
+    newTr.step(condensedStep);
+    const mirrorIndex = map.maps.length - 1;
+    map.appendMap(condensedStep.getMap(), mirrorIndex);
+    if (!newTr.selection.eq(trTemp.selection)) {
+      newTr.setSelection(trTemp.selection);
+    }
+  }
+  if (step.from !== step.to) {
+    map.appendMap(markDeletion(newTr, step.from, step.to, user, date));
+  }
+};
+
+export default replaceStep;
diff --git a/wax-prosemirror-services/src/TrackChangeService/track-changes/trackedTransaction.js b/wax-prosemirror-services/src/TrackChangeService/track-changes/trackedTransaction.js
index ce80335e46a03a96b655920868553ed70b5ee745..cf30f6c3daeeab3535edf6b4c33cba1c3ed4341e 100644
--- a/wax-prosemirror-services/src/TrackChangeService/track-changes/trackedTransaction.js
+++ b/wax-prosemirror-services/src/TrackChangeService/track-changes/trackedTransaction.js
@@ -5,7 +5,6 @@ License included in folder.
 */
 
 import { Selection, TextSelection } from "prosemirror-state";
-import { Slice } from "prosemirror-model";
 import {
   ReplaceStep,
   ReplaceAroundStep,
@@ -13,11 +12,11 @@ import {
   RemoveMarkStep,
   Mapping
 } from "prosemirror-transform";
-import { CellSelection } from "prosemirror-tables";
 
-import markDeletion from "./markDeletion";
-import markInsertion from "./markInsertion";
-import markWrapping from "./markWrapping";
+import replaceStep from "./helpers/replaceStep";
+import replaceAroundStep from "./helpers/replaceAroundStep";
+import addMarkStep from "./helpers/addMarkStep";
+import removeMarkStep from "./helpers/removeMarkStep";
 
 const trackedTransaction = (tr, state, user) => {
   if (
@@ -32,15 +31,9 @@ const trackedTransaction = (tr, state, user) => {
     return tr;
   }
 
-  const newTr = state.tr,
-    map = new Mapping(),
-    date = Math.floor(Date.now() / 60000), // 1 minute interval
-    // We only insert content if this is not directly a tr for cell deletion. This is because tables delete rows by deleting the
-    // contents of each cell and replacing it with an empty paragraph.
-    cellDeleteTr =
-      ["deleteContentBackward", "deleteContentForward"].includes(
-        tr.getMeta("inputType")
-      ) && state.selection instanceof CellSelection;
+  const newTr = state.tr;
+  const map = new Mapping();
+  const date = Math.floor(Date.now() / 60000);
 
   tr.steps.forEach(originalStep => {
     const step = originalStep.map(map),
@@ -50,215 +43,19 @@ const trackedTransaction = (tr, state, user) => {
     }
 
     if (step instanceof ReplaceStep) {
-      const newStep = !cellDeleteTr
-        ? new ReplaceStep(
-            step.to, // We insert all the same steps, but with "from"/"to" both set to "to" in order not to delete content. Mapped as needed.
-            step.to,
-            step.slice,
-            step.structure
-          )
-        : false;
-
-      // We didn't apply the original step in its original place. We adjust the map accordingly.
-      map.appendMap(step.invert(doc).getMap());
-      if (newStep) {
-        const trTemp = state.apply(newTr).tr;
-        if (trTemp.maybeStep(newStep).failed) {
-          return;
-        }
-
-        const mappedNewStepTo = newStep.getMap().map(newStep.to);
-        markInsertion(trTemp, newStep.from, mappedNewStepTo, user, date);
-        // We condense it down to a single replace step.
-        const condensedStep = new ReplaceStep(
-          newStep.from,
-          newStep.to,
-          trTemp.doc.slice(newStep.from, mappedNewStepTo)
-        );
-
-        newTr.step(condensedStep);
-        const mirrorIndex = map.maps.length - 1;
-        map.appendMap(condensedStep.getMap(), mirrorIndex);
-        if (!newTr.selection.eq(trTemp.selection)) {
-          newTr.setSelection(trTemp.selection);
-        }
-      }
-      if (step.from !== step.to) {
-        map.appendMap(markDeletion(newTr, step.from, step.to, user, date));
-      }
+      replaceStep(state, tr, step, newTr, map, doc, user, date);
     }
 
     if (step instanceof ReplaceAroundStep) {
-      if (step.from === step.gapFrom && step.to === step.gapTo) {
-        // wrapped in something
-        newTr.step(step);
-        const from = step.getMap().map(step.from, -1);
-        const to = step.getMap().map(step.gapFrom);
-        markInsertion(newTr, from, to, user, date);
-      } else if (!step.slice.size) {
-        // unwrapped from something
-        map.appendMap(step.invert(doc).getMap());
-        map.appendMap(markDeletion(newTr, step.from, step.gapFrom, user, date));
-      } else if (
-        step.slice.size === 2 &&
-        step.gapFrom - step.from === 1 &&
-        step.to - step.gapTo === 1
-      ) {
-        // Replaced one wrapping with another
-        newTr.step(step);
-        const oldNode = doc.nodeAt(step.from);
-        if (oldNode.attrs.track) {
-          markWrapping(
-            newTr,
-            step.from,
-            oldNode,
-            step.slice.content.firstChild,
-            user,
-            date
-          );
-        }
-      } else {
-        newTr.step(step);
-        const ranges = [
-          {
-            from: step.getMap().map(step.from, -1),
-            to: step.getMap().map(step.gapFrom)
-          },
-          {
-            from: step.getMap().map(step.gapTo, -1),
-            to: step.getMap().map(step.to)
-          }
-        ];
-        ranges.forEach(range =>
-          doc.nodesBetween(range.from, range.to, (node, pos) => {
-            if (pos < range.from) {
-              return true;
-            }
-            markInsertion(newTr, range.from, range.to, user, date);
-          })
-        );
-      }
+      replaceAroundStep(state, tr, step, newTr, map, doc, user, date);
     }
 
     if (step instanceof AddMarkStep) {
-      doc.nodesBetween(step.from, step.to, (node, pos) => {
-        if (!node.isInline) {
-          return true;
-        }
-        if (node.marks.find(mark => mark.type.name === "deletion")) {
-          return false;
-        } else {
-          newTr.addMark(
-            Math.max(step.from, pos),
-            Math.min(step.to, pos + node.nodeSize),
-            step.mark
-          );
-        }
-        if (
-          ["em", "strong", "underline"].includes(step.mark.type.name) &&
-          !node.marks.find(mark => mark.type === step.mark.type)
-        ) {
-          const formatChangeMark = node.marks.find(
-            mark => mark.type.name === "format_change"
-          );
-          let after, before;
-          if (formatChangeMark) {
-            if (formatChangeMark.attrs.before.includes(step.mark.type.name)) {
-              before = formatChangeMark.attrs.before.filter(
-                markName => markName !== step.mark.type.name
-              );
-              after = formatChangeMark.attrs.after;
-            } else {
-              before = formatChangeMark.attrs.before;
-              after = formatChangeMark.attrs.after.concat(step.mark.type.name);
-            }
-          } else {
-            before = [];
-            after = [step.mark.type.name];
-          }
-          if (after.length || before.length) {
-            newTr.addMark(
-              Math.max(step.from, pos),
-              Math.min(step.to, pos + node.nodeSize),
-              state.schema.marks.format_change.create({
-                user: user.userId,
-                username: user.username,
-                date,
-                before,
-                after
-              })
-            );
-          } else if (formatChangeMark) {
-            newTr.removeMark(
-              Math.max(step.from, pos),
-              Math.min(step.to, pos + node.nodeSize),
-              formatChangeMark
-            );
-          }
-        }
-      });
+      addMarkStep(state, tr, step, newTr, map, doc, user, date);
     }
 
     if (step instanceof RemoveMarkStep) {
-      doc.nodesBetween(step.from, step.to, (node, pos) => {
-        if (!node.isInline) {
-          return true;
-        }
-        if (node.marks.find(mark => mark.type.name === "deletion")) {
-          return false;
-        } else {
-          newTr.removeMark(
-            Math.max(step.from, pos),
-            Math.min(step.to, pos + node.nodeSize),
-            step.mark
-          );
-        }
-
-        if (
-          ["em", "strong", "underline"].includes(step.mark.type.name) &&
-          node.marks.find(mark => mark.type === step.mark.type)
-        ) {
-          const formatChangeMark = node.marks.find(
-            mark => mark.type.name === "format_change"
-          );
-          let after, before;
-          if (formatChangeMark) {
-            if (formatChangeMark.attrs.after.includes(step.mark.type.name)) {
-              after = formatChangeMark.attrs.after.filter(
-                markName => markName !== step.mark.type.name
-              );
-              before = formatChangeMark.attrs.before;
-            } else {
-              after = formatChangeMark.attrs.after;
-              before = formatChangeMark.attrs.before.concat(
-                step.mark.type.name
-              );
-            }
-          } else {
-            after = [];
-            before = [step.mark.type.name];
-          }
-          if (after.length || before.length) {
-            newTr.addMark(
-              Math.max(step.from, pos),
-              Math.min(step.to, pos + node.nodeSize),
-              state.schema.marks.format_change.create({
-                user: user.userId,
-                username: user.username,
-                date,
-                before,
-                after
-              })
-            );
-          } else if (formatChangeMark) {
-            newTr.removeMark(
-              Math.max(step.from, pos),
-              Math.min(step.to, pos + node.nodeSize),
-              formatChangeMark
-            );
-          }
-        }
-      });
+      removeMarkStep(state, tr, step, newTr, map, doc, user, date);
     }
   });