@manuscripts/track-changes-plugin 0.0.1 → 0.0.4
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/README.md +47 -42
- package/dist/index.es.js +7 -11
- package/dist/index.js +7 -11
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -1,20 +1,58 @@
|
|
|
1
|
-
# @manuscripts/track-changes-plugin
|
|
1
|
+
# [@manuscripts/track-changes-plugin](https://github.com/Atypon-OpenSource/manuscripts-quarterback/tree/main/quarterback-packages/track-changes-plugin)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
ProseMirror plugin to track inserts/deletes to nodes and text.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
If you have multiple versions of prosemirror packages, ensure that track-changes' dependencies `prosemirror-model` and `prosemirror-transform` are aliased/deduped to same instance. `prosemirror-state` and `prosemirror-view` are only used at type level. [Example](https://github.com/Atypon-OpenSource/manuscripts-quarterback/blob/main/examples-packages/client/vite.config.js).
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
[More detailed overview](https://github.com/Atypon-OpenSource/manuscripts-quarterback/blob/main/quarterback-packages/track-changes-plugin/OVERVIEW.md)
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## How to use
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
First install the plugin: `npm i @manuscripts/track-changes-plugin`
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Then add the plugin to ProseMirror plugins:
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
```ts
|
|
16
|
+
import { EditorState } from 'prosemirror-state'
|
|
17
|
+
import { EditorView } from 'prosemirror-view'
|
|
18
|
+
import { exampleSetup } from 'prosemirror-example-setup'
|
|
19
|
+
import { trackChangesPlugin } from '@manuscripts/track-changes-plugin'
|
|
20
|
+
|
|
21
|
+
import { schema } from './schema'
|
|
22
|
+
|
|
23
|
+
const plugins = exampleSetup({ schema }).concat(trackChangesPlugin({
|
|
24
|
+
debug: true
|
|
25
|
+
}))
|
|
26
|
+
const state = EditorState.create({
|
|
27
|
+
schema,
|
|
28
|
+
plugins,
|
|
29
|
+
})
|
|
30
|
+
const view = new EditorView(document.querySelector('#editor') as HTMLElement, {
|
|
31
|
+
state,
|
|
32
|
+
})
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
where `schema` is https://github.com/Atypon-OpenSource/manuscripts-quarterback/blob/main/quarterback-packages/track-changes-plugin/test/utils/schema.ts
|
|
36
|
+
|
|
37
|
+
Enable or disable the plugin with:
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { trackCommands, TrackChangesStatus } from '@manuscripts/track-changes-plugin'
|
|
16
41
|
|
|
17
|
-
|
|
42
|
+
// toggle
|
|
43
|
+
trackCommands.setTrackingStatus())(view.state, view.dispatch, view)
|
|
44
|
+
|
|
45
|
+
// enable
|
|
46
|
+
trackCommands.setTrackingStatus(TrackChangesStatus.enabled))(view.state, view.dispatch, view)
|
|
47
|
+
|
|
48
|
+
// disable
|
|
49
|
+
trackCommands.setTrackingStatus(TrackChangesStatus.disabled))(view.state, view.dispatch, view)
|
|
50
|
+
|
|
51
|
+
// sets editor's 'editable' prop to false, making it ready-only
|
|
52
|
+
trackCommands.setTrackingStatus(TrackChangesStatus.viewSnapshots))(view.state, view.dispatch, view)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
See an example app at https://github.com/Atypon-OpenSource/manuscripts-quarterback/tree/main/examples-packages/client
|
|
18
56
|
|
|
19
57
|
## API
|
|
20
58
|
|
|
@@ -133,36 +171,3 @@ export function setAction<K extends keyof TrackChangesActionParams>(
|
|
|
133
171
|
### Types
|
|
134
172
|
|
|
135
173
|
Can be found in `./src/types` and `./src/ChangeSet.ts`
|
|
136
|
-
|
|
137
|
-
## Feature summary
|
|
138
|
-
|
|
139
|
-
- tracks block, inline, atom node inserts & deletes as `dataTracked` attribute objects
|
|
140
|
-
- tracks text insert & delete as `tracked_insert` and `tracked_delete` marks
|
|
141
|
-
- joins track marks based on `userID`, `operation` and `status`, uses the oldest `createdAt` value as timestamp
|
|
142
|
-
- allows deletes of block nodes & text if operation is `inserted`
|
|
143
|
-
- does not diff operations next to each other eg `(ins aasdf)(del asdf)` is not reduced to `ins a`
|
|
144
|
-
- does not track block node attribute updates
|
|
145
|
-
- does not track mark inserts & deletes
|
|
146
|
-
- does not track ReplaceAroundSteps
|
|
147
|
-
- has probably bugs regarding the edge cases around copy-pasting complicated slices
|
|
148
|
-
|
|
149
|
-
## Roadmap
|
|
150
|
-
|
|
151
|
-
- track block node attribute updates, they currently go undetected
|
|
152
|
-
- test copy-pasting works (slices with varying open endedness)
|
|
153
|
-
- test for race conditions
|
|
154
|
-
- refactor unused code, add better comments
|
|
155
|
-
- more thorough tests
|
|
156
|
-
- track ReplaceAroundSteps
|
|
157
|
-
- track formatting changes, basically handle AddMarkStep and RemoveMarkSteps
|
|
158
|
-
|
|
159
|
-
## Related reading
|
|
160
|
-
|
|
161
|
-
- https://ckeditor.com/docs/ckeditor5/latest/features/collaboration/track-changes/track-changes.html
|
|
162
|
-
- https://ckeditor.com/blog/ckeditor-5-comparing-revision-history-with-track-changes/
|
|
163
|
-
- https://github.com/fiduswriter/fiduswriter
|
|
164
|
-
- https://www.ncbi.nlm.nih.gov/books/NBK159965/
|
|
165
|
-
- https://teemukoivisto.github.io/prosemirror-track-changes-example/
|
|
166
|
-
- https://demos.yjs.dev/prosemirror-versions/prosemirror-versions.html
|
|
167
|
-
- https://slab.com/blog/announcing-delta-for-elixir/
|
|
168
|
-
- https://www.inkandswitch.com/peritext/
|
package/dist/index.es.js
CHANGED
|
@@ -501,7 +501,9 @@ function applyAcceptedRejectedChanges(tr, schema, changes, deleteMap = new Mappi
|
|
|
501
501
|
if (change.attrs.status === CHANGE_STATUS.pending) {
|
|
502
502
|
return;
|
|
503
503
|
}
|
|
504
|
-
|
|
504
|
+
// Map change.from and skip those which dont need to be applied
|
|
505
|
+
// or were already deleted by an applied block delete
|
|
506
|
+
const { pos: from, deleted } = deleteMap.mapResult(change.from), node = tr.doc.nodeAt(from), noChangeNeeded = deleted || ChangeSet.shouldNotDelete(change);
|
|
505
507
|
if (!node) {
|
|
506
508
|
log.warn('no node found to update for change', change);
|
|
507
509
|
return;
|
|
@@ -1263,16 +1265,10 @@ function trackTransaction(tr, oldState, newTr, userID) {
|
|
|
1263
1265
|
// } else if (step instanceof AddMarkStep) {
|
|
1264
1266
|
// } else if (step instanceof RemoveMarkStep) {
|
|
1265
1267
|
}
|
|
1266
|
-
//
|
|
1267
|
-
//
|
|
1268
|
-
//
|
|
1269
|
-
|
|
1270
|
-
// This is quite non-optimal in some sense but to ensure no information is lost
|
|
1271
|
-
// we have to re-add all the old meta keys, such as inputType or uiEvent.
|
|
1272
|
-
// This should prevent bugs incase other plugins/widgets rely upon them existing (and they
|
|
1273
|
-
// are not able to process the transactions before track-changes).
|
|
1274
|
-
// TODO: will this cause race-condition if a meta causes another appendTransaction to fire
|
|
1275
|
-
Object.keys(meta).forEach((key) => newTr.setMeta(key, tr.getMeta(key)));
|
|
1268
|
+
// 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)))
|
|
1276
1272
|
});
|
|
1277
1273
|
// This is kinda hacky solution at the moment to maintain NodeSelections over transactions
|
|
1278
1274
|
// These are required by at least cross-references that need it to activate the selector pop-up
|
package/dist/index.js
CHANGED
|
@@ -509,7 +509,9 @@ function applyAcceptedRejectedChanges(tr, schema, changes, deleteMap = new prose
|
|
|
509
509
|
if (change.attrs.status === exports.CHANGE_STATUS.pending) {
|
|
510
510
|
return;
|
|
511
511
|
}
|
|
512
|
-
|
|
512
|
+
// Map change.from and skip those which dont need to be applied
|
|
513
|
+
// or were already deleted by an applied block delete
|
|
514
|
+
const { pos: from, deleted } = deleteMap.mapResult(change.from), node = tr.doc.nodeAt(from), noChangeNeeded = deleted || ChangeSet.shouldNotDelete(change);
|
|
513
515
|
if (!node) {
|
|
514
516
|
log.warn('no node found to update for change', change);
|
|
515
517
|
return;
|
|
@@ -1271,16 +1273,10 @@ function trackTransaction(tr, oldState, newTr, userID) {
|
|
|
1271
1273
|
// } else if (step instanceof AddMarkStep) {
|
|
1272
1274
|
// } else if (step instanceof RemoveMarkStep) {
|
|
1273
1275
|
}
|
|
1274
|
-
//
|
|
1275
|
-
//
|
|
1276
|
-
//
|
|
1277
|
-
|
|
1278
|
-
// This is quite non-optimal in some sense but to ensure no information is lost
|
|
1279
|
-
// we have to re-add all the old meta keys, such as inputType or uiEvent.
|
|
1280
|
-
// This should prevent bugs incase other plugins/widgets rely upon them existing (and they
|
|
1281
|
-
// are not able to process the transactions before track-changes).
|
|
1282
|
-
// TODO: will this cause race-condition if a meta causes another appendTransaction to fire
|
|
1283
|
-
Object.keys(meta).forEach((key) => newTr.setMeta(key, tr.getMeta(key)));
|
|
1276
|
+
// 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)))
|
|
1284
1280
|
});
|
|
1285
1281
|
// This is kinda hacky solution at the moment to maintain NodeSelections over transactions
|
|
1286
1282
|
// These are required by at least cross-references that need it to activate the selector pop-up
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@manuscripts/track-changes-plugin",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"author": "Atypon Systems LLC",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
|
-
"homepage": "https://github.com/Atypon-OpenSource/manuscripts-quarterback",
|
|
6
|
+
"homepage": "https://github.com/Atypon-OpenSource/manuscripts-quarterback/tree/main/quarterback-packages/track-changes-plugin",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"module": "dist/index.es.js",
|
|
9
9
|
"type": "module",
|
|
@@ -49,10 +49,10 @@
|
|
|
49
49
|
"typescript": "^4.6.4"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
|
-
"prosemirror-model": "
|
|
53
|
-
"prosemirror-state": "
|
|
54
|
-
"prosemirror-transform": "
|
|
55
|
-
"prosemirror-view": "
|
|
52
|
+
"prosemirror-model": ">=1.14.0",
|
|
53
|
+
"prosemirror-state": ">=1.3.0",
|
|
54
|
+
"prosemirror-transform": ">=1.3.0",
|
|
55
|
+
"prosemirror-view": ">=1.18.0"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
58
|
"debug": "^4.3.4"
|