@manuscripts/track-changes-plugin 0.0.4 → 0.1.1

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/dist/index.es.js CHANGED
@@ -327,8 +327,9 @@ function deleteNode(node, pos, tr) {
327
327
  var _a;
328
328
  const startPos = tr.doc.resolve(pos + 1);
329
329
  const range = startPos.blockRange(tr.doc.resolve(startPos.pos - 2 + node.nodeSize));
330
- const targetDepth = range ? Number(liftTarget(range)) : NaN;
331
- if (range && !Number.isNaN(targetDepth)) {
330
+ const targetDepth = range && liftTarget(range);
331
+ // Check with typeof since with old prosemirror-transform targetDepth is undefined
332
+ if (range && typeof targetDepth === 'number') {
332
333
  return tr.lift(range, targetDepth);
333
334
  }
334
335
  const resPos = tr.doc.resolve(pos);
@@ -505,7 +506,7 @@ function applyAcceptedRejectedChanges(tr, schema, changes, deleteMap = new Mappi
505
506
  // or were already deleted by an applied block delete
506
507
  const { pos: from, deleted } = deleteMap.mapResult(change.from), node = tr.doc.nodeAt(from), noChangeNeeded = deleted || ChangeSet.shouldNotDelete(change);
507
508
  if (!node) {
508
- log.warn('no node found to update for change', change);
509
+ !deleted && log.warn('no node found to update for change', change);
509
510
  return;
510
511
  }
511
512
  if (ChangeSet.isTextChange(change) && noChangeNeeded) {
@@ -929,6 +930,7 @@ function deleteAndMergeSplitNodes(from, to, gap, startDoc, newTr, schema, trackA
929
930
  // But from what I remember what it safeguards against is, when you've already deleted a node
930
931
  // say an inserted blockquote that had all its children deleted, nodesBetween still iterates over those
931
932
  // nodes and therefore we have to make this check to ensure they still exist in the doc.
933
+ //
932
934
  if (nodeEnd > offsetFrom && !nodeWasDeleted && !wasWithinGap) {
933
935
  // |<p>asdf</p>| -> node deleted completely
934
936
  const nodeCompletelyDeleted = offsetPos >= offsetFrom && nodeEnd <= offsetTo;
@@ -1209,11 +1211,9 @@ function trackReplaceStep(step, oldState, newTr, attrs) {
1209
1211
  * This skips the direct dependency to prosemirror-state where multiple versions might cause conflicts
1210
1212
  * as the created instances might belong to different prosemirror-state import than one used in the editor.
1211
1213
  * @param sel
1212
- * @param doc
1213
- * @param from
1214
1214
  * @returns
1215
1215
  */
1216
- const getSelectionStaticCreate = (sel, doc, from) => Object.getPrototypeOf(sel).constructor.create(doc, from);
1216
+ const getSelectionStaticConstructor = (sel) => Object.getPrototypeOf(sel).constructor;
1217
1217
  /**
1218
1218
  * Inverts transactions to wrap their contents/operations with track data instead
1219
1219
  *
@@ -1257,7 +1257,12 @@ function trackTransaction(tr, oldState, newTr, userID) {
1257
1257
  else if (step instanceof ReplaceStep) {
1258
1258
  const selectionPos = trackReplaceStep(step, oldState, newTr, emptyAttrs);
1259
1259
  if (!wasNodeSelection) {
1260
- newTr.setSelection(getSelectionStaticCreate(tr.selection, newTr.doc, selectionPos));
1260
+ const sel = getSelectionStaticConstructor(tr.selection);
1261
+ // Use Selection.near to fix selections that point to a block node instead of inline content
1262
+ // eg when inserting a complete new paragraph. -1 finds the first valid position moving backwards
1263
+ // inside the content
1264
+ const near = sel.near(newTr.doc.resolve(selectionPos), -1);
1265
+ newTr.setSelection(near);
1261
1266
  }
1262
1267
  }
1263
1268
  else if (step instanceof ReplaceAroundStep) {
@@ -1265,10 +1270,15 @@ function trackTransaction(tr, oldState, newTr, userID) {
1265
1270
  // } else if (step instanceof AddMarkStep) {
1266
1271
  // } else if (step instanceof RemoveMarkStep) {
1267
1272
  }
1273
+ // TODO: here we could check whether adjacent inserts & deletes cancel each other out.
1274
+ // However, this should not be done by diffing and only matching node or char by char instead since
1275
+ // it's A easier and B more intuitive to user.
1268
1276
  // The old meta keys are not copied to the new transaction since this will cause race-conditions
1269
- // when a single meta-field is thought to be processed. MAYBE only the generic meta keys, such as
1270
- // inputType or uiEvent, could be copied over but it remains to be seen if it's necessary.
1271
- // Object.keys(meta).forEach((key) => newTr.setMeta(key, tr.getMeta(key)))
1277
+ // when a single meta-field is expected to having been processed / removed. Generic input meta keys,
1278
+ // inputType and uiEvent, are re-added since some plugins might depend on them and process the transaction
1279
+ // after track-changes plugin.
1280
+ tr.getMeta('inputType') && newTr.setMeta('inputType', tr.getMeta('inputType'));
1281
+ tr.getMeta('uiEvent') && newTr.setMeta('uiEvent', tr.getMeta('uiEvent'));
1272
1282
  });
1273
1283
  // This is kinda hacky solution at the moment to maintain NodeSelections over transactions
1274
1284
  // These are required by at least cross-references that need it to activate the selector pop-up
@@ -1276,7 +1286,8 @@ function trackTransaction(tr, oldState, newTr, userID) {
1276
1286
  const mappedPos = newTr.mapping.map(tr.selection.from);
1277
1287
  const resPos = newTr.doc.resolve(mappedPos);
1278
1288
  const nodePos = mappedPos - (((_a = resPos.nodeBefore) === null || _a === void 0 ? void 0 : _a.nodeSize) || 0);
1279
- newTr.setSelection(getSelectionStaticCreate(tr.selection, newTr.doc, nodePos));
1289
+ const sel = getSelectionStaticConstructor(tr.selection);
1290
+ newTr.setSelection(sel.create(newTr.doc, nodePos));
1280
1291
  }
1281
1292
  log.info('NEW transaction', newTr);
1282
1293
  return newTr;
@@ -1326,7 +1337,8 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
1326
1337
  key: trackChangesPluginKey,
1327
1338
  props: {
1328
1339
  editable(state) {
1329
- return this.getState(state).status !== TrackChangesStatus.viewSnapshots;
1340
+ var _a;
1341
+ return ((_a = trackChangesPluginKey.getState(state)) === null || _a === void 0 ? void 0 : _a.status) !== TrackChangesStatus.viewSnapshots;
1330
1342
  },
1331
1343
  },
1332
1344
  state: {
@@ -1396,7 +1408,6 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
1396
1408
  (wasAppended && getAction(wasAppended, TrackChangesAction.skipTrack));
1397
1409
  if (tr.docChanged && !skipMetaUsed && !skipTrackUsed && !tr.getMeta('history$')) {
1398
1410
  createdTr = trackTransaction(tr, oldState, createdTr, userID);
1399
- createdTr.setMeta('origin', trackChangesPluginKey);
1400
1411
  infiniteLoopCounter.iters += 1;
1401
1412
  }
1402
1413
  docChanged = docChanged || tr.docChanged;
@@ -1423,6 +1434,7 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
1423
1434
  log.warn('had to fix inconsistent changes in', createdTr);
1424
1435
  }
1425
1436
  if (docChanged || createdTr.docChanged || changed) {
1437
+ createdTr.setMeta('origin', trackChangesPluginKey);
1426
1438
  return setAction(createdTr, TrackChangesAction.refreshChanges, true);
1427
1439
  }
1428
1440
  return null;
package/dist/index.js CHANGED
@@ -335,8 +335,9 @@ function deleteNode(node, pos, tr) {
335
335
  var _a;
336
336
  const startPos = tr.doc.resolve(pos + 1);
337
337
  const range = startPos.blockRange(tr.doc.resolve(startPos.pos - 2 + node.nodeSize));
338
- const targetDepth = range ? Number(prosemirrorTransform.liftTarget(range)) : NaN;
339
- if (range && !Number.isNaN(targetDepth)) {
338
+ const targetDepth = range && prosemirrorTransform.liftTarget(range);
339
+ // Check with typeof since with old prosemirror-transform targetDepth is undefined
340
+ if (range && typeof targetDepth === 'number') {
340
341
  return tr.lift(range, targetDepth);
341
342
  }
342
343
  const resPos = tr.doc.resolve(pos);
@@ -513,7 +514,7 @@ function applyAcceptedRejectedChanges(tr, schema, changes, deleteMap = new prose
513
514
  // or were already deleted by an applied block delete
514
515
  const { pos: from, deleted } = deleteMap.mapResult(change.from), node = tr.doc.nodeAt(from), noChangeNeeded = deleted || ChangeSet.shouldNotDelete(change);
515
516
  if (!node) {
516
- log.warn('no node found to update for change', change);
517
+ !deleted && log.warn('no node found to update for change', change);
517
518
  return;
518
519
  }
519
520
  if (ChangeSet.isTextChange(change) && noChangeNeeded) {
@@ -937,6 +938,7 @@ function deleteAndMergeSplitNodes(from, to, gap, startDoc, newTr, schema, trackA
937
938
  // But from what I remember what it safeguards against is, when you've already deleted a node
938
939
  // say an inserted blockquote that had all its children deleted, nodesBetween still iterates over those
939
940
  // nodes and therefore we have to make this check to ensure they still exist in the doc.
941
+ //
940
942
  if (nodeEnd > offsetFrom && !nodeWasDeleted && !wasWithinGap) {
941
943
  // |<p>asdf</p>| -> node deleted completely
942
944
  const nodeCompletelyDeleted = offsetPos >= offsetFrom && nodeEnd <= offsetTo;
@@ -1217,11 +1219,9 @@ function trackReplaceStep(step, oldState, newTr, attrs) {
1217
1219
  * This skips the direct dependency to prosemirror-state where multiple versions might cause conflicts
1218
1220
  * as the created instances might belong to different prosemirror-state import than one used in the editor.
1219
1221
  * @param sel
1220
- * @param doc
1221
- * @param from
1222
1222
  * @returns
1223
1223
  */
1224
- const getSelectionStaticCreate = (sel, doc, from) => Object.getPrototypeOf(sel).constructor.create(doc, from);
1224
+ const getSelectionStaticConstructor = (sel) => Object.getPrototypeOf(sel).constructor;
1225
1225
  /**
1226
1226
  * Inverts transactions to wrap their contents/operations with track data instead
1227
1227
  *
@@ -1265,7 +1265,12 @@ function trackTransaction(tr, oldState, newTr, userID) {
1265
1265
  else if (step instanceof prosemirrorTransform.ReplaceStep) {
1266
1266
  const selectionPos = trackReplaceStep(step, oldState, newTr, emptyAttrs);
1267
1267
  if (!wasNodeSelection) {
1268
- newTr.setSelection(getSelectionStaticCreate(tr.selection, newTr.doc, selectionPos));
1268
+ const sel = getSelectionStaticConstructor(tr.selection);
1269
+ // Use Selection.near to fix selections that point to a block node instead of inline content
1270
+ // eg when inserting a complete new paragraph. -1 finds the first valid position moving backwards
1271
+ // inside the content
1272
+ const near = sel.near(newTr.doc.resolve(selectionPos), -1);
1273
+ newTr.setSelection(near);
1269
1274
  }
1270
1275
  }
1271
1276
  else if (step instanceof prosemirrorTransform.ReplaceAroundStep) {
@@ -1273,10 +1278,15 @@ function trackTransaction(tr, oldState, newTr, userID) {
1273
1278
  // } else if (step instanceof AddMarkStep) {
1274
1279
  // } else if (step instanceof RemoveMarkStep) {
1275
1280
  }
1281
+ // TODO: here we could check whether adjacent inserts & deletes cancel each other out.
1282
+ // However, this should not be done by diffing and only matching node or char by char instead since
1283
+ // it's A easier and B more intuitive to user.
1276
1284
  // The old meta keys are not copied to the new transaction since this will cause race-conditions
1277
- // when a single meta-field is thought to be processed. MAYBE only the generic meta keys, such as
1278
- // inputType or uiEvent, could be copied over but it remains to be seen if it's necessary.
1279
- // Object.keys(meta).forEach((key) => newTr.setMeta(key, tr.getMeta(key)))
1285
+ // when a single meta-field is expected to having been processed / removed. Generic input meta keys,
1286
+ // inputType and uiEvent, are re-added since some plugins might depend on them and process the transaction
1287
+ // after track-changes plugin.
1288
+ tr.getMeta('inputType') && newTr.setMeta('inputType', tr.getMeta('inputType'));
1289
+ tr.getMeta('uiEvent') && newTr.setMeta('uiEvent', tr.getMeta('uiEvent'));
1280
1290
  });
1281
1291
  // This is kinda hacky solution at the moment to maintain NodeSelections over transactions
1282
1292
  // These are required by at least cross-references that need it to activate the selector pop-up
@@ -1284,7 +1294,8 @@ function trackTransaction(tr, oldState, newTr, userID) {
1284
1294
  const mappedPos = newTr.mapping.map(tr.selection.from);
1285
1295
  const resPos = newTr.doc.resolve(mappedPos);
1286
1296
  const nodePos = mappedPos - (((_a = resPos.nodeBefore) === null || _a === void 0 ? void 0 : _a.nodeSize) || 0);
1287
- newTr.setSelection(getSelectionStaticCreate(tr.selection, newTr.doc, nodePos));
1297
+ const sel = getSelectionStaticConstructor(tr.selection);
1298
+ newTr.setSelection(sel.create(newTr.doc, nodePos));
1288
1299
  }
1289
1300
  log.info('NEW transaction', newTr);
1290
1301
  return newTr;
@@ -1334,7 +1345,8 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
1334
1345
  key: trackChangesPluginKey,
1335
1346
  props: {
1336
1347
  editable(state) {
1337
- return this.getState(state).status !== exports.TrackChangesStatus.viewSnapshots;
1348
+ var _a;
1349
+ return ((_a = trackChangesPluginKey.getState(state)) === null || _a === void 0 ? void 0 : _a.status) !== exports.TrackChangesStatus.viewSnapshots;
1338
1350
  },
1339
1351
  },
1340
1352
  state: {
@@ -1404,7 +1416,6 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
1404
1416
  (wasAppended && getAction(wasAppended, exports.TrackChangesAction.skipTrack));
1405
1417
  if (tr.docChanged && !skipMetaUsed && !skipTrackUsed && !tr.getMeta('history$')) {
1406
1418
  createdTr = trackTransaction(tr, oldState, createdTr, userID);
1407
- createdTr.setMeta('origin', trackChangesPluginKey);
1408
1419
  infiniteLoopCounter.iters += 1;
1409
1420
  }
1410
1421
  docChanged = docChanged || tr.docChanged;
@@ -1431,6 +1442,7 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
1431
1442
  log.warn('had to fix inconsistent changes in', createdTr);
1432
1443
  }
1433
1444
  if (docChanged || createdTr.docChanged || changed) {
1445
+ createdTr.setMeta('origin', trackChangesPluginKey);
1434
1446
  return setAction(createdTr, exports.TrackChangesAction.refreshChanges, true);
1435
1447
  }
1436
1448
  return null;
package/dist/plugin.d.ts CHANGED
@@ -15,11 +15,11 @@
15
15
  */
16
16
  import { Plugin, PluginKey } from 'prosemirror-state';
17
17
  import { TrackChangesOptions, TrackChangesState } from './types/track';
18
- export declare const trackChangesPluginKey: PluginKey<TrackChangesState, any>;
18
+ export declare const trackChangesPluginKey: PluginKey<TrackChangesState>;
19
19
  /**
20
20
  * The ProseMirror plugin needed to enable track-changes.
21
21
  *
22
22
  * Accepts an empty options object as an argument but note that this uses 'anonymous:Anonymous' as the default userID.
23
23
  * @param opts
24
24
  */
25
- export declare const trackChangesPlugin: (opts?: TrackChangesOptions) => Plugin<TrackChangesState, any>;
25
+ export declare const trackChangesPlugin: (opts?: TrackChangesOptions) => Plugin<TrackChangesState>;
@@ -24,4 +24,4 @@ import { Transaction } from 'prosemirror-state';
24
24
  * @param tr
25
25
  * @returns
26
26
  */
27
- export declare function deleteNode(node: PMNode, pos: number, tr: Transaction): Transaction<any>;
27
+ export declare function deleteNode(node: PMNode, pos: number, tr: Transaction): Transaction;
@@ -49,5 +49,5 @@ export declare function deleteAndMergeSplitNodes(from: number, to: number, gap:
49
49
  } | undefined, startDoc: PMNode, newTr: Transaction, schema: Schema, trackAttrs: NewEmptyAttrs, insertSlice: ExposedSlice): {
50
50
  deleteMap: Mapping;
51
51
  mergedInsertPos: undefined;
52
- newSliceContent: Fragment<any>;
52
+ newSliceContent: Fragment;
53
53
  };
@@ -15,4 +15,4 @@
15
15
  */
16
16
  import { Fragment, Schema } from 'prosemirror-model';
17
17
  import { NewInsertAttrs } from '../../types/track';
18
- export declare function setFragmentAsInserted(inserted: Fragment, insertAttrs: NewInsertAttrs, schema: Schema): Fragment<any>;
18
+ export declare function setFragmentAsInserted(inserted: Fragment, insertAttrs: NewInsertAttrs, schema: Schema): Fragment;
@@ -14,4 +14,4 @@ import type { EditorState, Transaction } from 'prosemirror-state';
14
14
  * @param userID User id
15
15
  * @returns newTr that inverts the initial tr and applies track attributes/marks
16
16
  */
17
- export declare function trackTransaction(tr: Transaction, oldState: EditorState, newTr: Transaction, userID: string): Transaction<any>;
17
+ export declare function trackTransaction(tr: Transaction, oldState: EditorState, newTr: Transaction, userID: string): Transaction;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@manuscripts/track-changes-plugin",
3
- "version": "0.0.4",
3
+ "version": "0.1.1",
4
4
  "author": "Atypon Systems LLC",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://github.com/Atypon-OpenSource/manuscripts-quarterback/tree/main/quarterback-packages/track-changes-plugin",
@@ -21,30 +21,25 @@
21
21
  "access": "public"
22
22
  },
23
23
  "devDependencies": {
24
+ "@manuscripts/manuscript-transform": "^0.49.1",
24
25
  "@rollup/plugin-commonjs": "^22.0.0",
25
26
  "@types/debug": "^4.1.7",
26
27
  "@types/jest": "27.5.1",
27
28
  "@types/node": "^17.0.35",
28
- "@types/prosemirror-commands": "^1.0.4",
29
- "@types/prosemirror-model": "^1.16.2",
30
- "@types/prosemirror-schema-list": "^1.0.3",
31
- "@types/prosemirror-state": "^1.3.0",
32
- "@types/prosemirror-transform": "^1.4.1",
33
- "@types/prosemirror-view": "^1.23.3",
34
- "jest": "28.1.0",
35
- "jest-environment-jsdom": "28.1.0",
29
+ "jest": "27.5.1",
30
+ "jest-environment-jsdom": "27.5.1",
36
31
  "jsdom": "^19.0.0",
37
- "prosemirror-commands": "^1.2.2",
38
- "prosemirror-example-setup": "^1.1.2",
39
- "prosemirror-keymap": "^1.1.5",
40
- "prosemirror-model": "^1.16.1",
41
- "prosemirror-schema-list": "^1.1.6",
42
- "prosemirror-state": "^1.3.4",
43
- "prosemirror-transform": "^1.4.2",
44
- "prosemirror-view": "^1.23.13",
32
+ "prosemirror-commands": "^1.3.0",
33
+ "prosemirror-example-setup": "^1.2.1",
34
+ "prosemirror-keymap": "^1.2.0",
35
+ "prosemirror-model": "^1.18.1",
36
+ "prosemirror-schema-list": "^1.2.0",
37
+ "prosemirror-state": "^1.4.1",
38
+ "prosemirror-transform": "^1.6.0",
39
+ "prosemirror-view": "^1.26.2",
45
40
  "rollup": "^2.74.0",
46
41
  "rollup-plugin-typescript2": "^0.31.2",
47
- "ts-jest": "28.0.2",
42
+ "ts-jest": "27.1.4",
48
43
  "tslib": "^2.4.0",
49
44
  "typescript": "^4.6.4"
50
45
  },
@@ -62,6 +57,7 @@
62
57
  "watch": "rollup -cw",
63
58
  "test": "jest --runInBand",
64
59
  "format": "prettier --write \"*.+(js|json|yml|yaml|ts|md|graphql|mdx)\" src/ test/",
60
+ "typecheck": "tsc --project tsconfig.test.json --noEmit",
65
61
  "lint": "eslint --cache --ext .js,.ts, ./src ./test",
66
62
  "lint:fix": "eslint --fix --ext .js,.ts, ./src ./test"
67
63
  }