This repository has been archived by the owner on Mar 30, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
prosemirror-change.ts
72 lines (60 loc) · 2.74 KB
/
prosemirror-change.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import { EditorState, Transaction } from 'prosemirror-state';
import { Step } from 'prosemirror-transform';
import { get, set } from 'lodash';
import { Manuscript } from '../../types/manuscript';
import { Change } from './change';
import { cloneManuscript } from '../state.utils';
import { JSONObject } from '../../types/utility.types';
export class ProsemirrorChange extends Change {
public static fromJSON(data: JSONObject): ProsemirrorChange {
const change = new ProsemirrorChange(data.path as string, null);
change.unserializedSteps = (data.transactionSteps as JSONObject[]) || [];
change._timestamp = data.timestamp as number;
return change;
}
private unserializedSteps: JSONObject[];
constructor(private path: string, private transaction: Transaction) {
super();
}
get isEmpty(): boolean {
return this.transaction ? !this.transaction.docChanged : this.unserializedSteps.length === 0;
}
isPathAffected(pathPattern: RegExp): boolean {
return pathPattern.test(this.path);
}
applyChange(manuscript: Manuscript): Manuscript {
const editorState = get(manuscript, this.path);
if (!this.transaction) {
// deserialized steps can only be turned into a transaction before applying to avoid applying mismatched
// transactions. If we try to convert a chained series of transactions upon creating a Change all transactions
// will refer to the same document and thus applying them one after another will cause an error because
// transactions will be applied to mismatched documents. Each transaction produces a new document. Chained
// transactions need to be created from corresponding documents.
this.deserializeSteps(editorState);
}
return set(cloneManuscript(manuscript), this.path, editorState.apply(this.transaction));
}
rollbackChange(manuscript: Manuscript): Manuscript {
const invertedSteps = this.transaction.steps.map((step, index) => {
return step.invert(this.transaction.docs[index]);
});
const editorState = get(manuscript, this.path);
const rollbackTransaction = editorState.tr;
invertedSteps.reverse().forEach((step) => rollbackTransaction.maybeStep(step));
return set(cloneManuscript(manuscript), this.path, editorState.apply(rollbackTransaction));
}
toJSON(): JSONObject {
return {
type: 'prosemirror',
timestamp: this.timestamp,
path: this.path,
transactionSteps: this.transaction ? this.transaction.steps.map((step) => step.toJSON()) : this.unserializedSteps
};
}
private deserializeSteps(editorState: EditorState): void {
this.transaction = editorState.tr;
this.unserializedSteps.forEach((stepJson) => {
this.transaction.maybeStep(Step.fromJSON(editorState.schema, stepJson));
});
}
}