easy-richtextarea 4.0.1 → 4.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 +0 -8
- package/example.js +1012 -595
- package/lib/browser.js +9 -9
- package/lib/constants.js +13 -4
- package/lib/contentCompare.js +34 -0
- package/lib/example/richTextarea.js +2 -2
- package/lib/example/view.js +18 -9
- package/lib/keyCodes.js +13 -0
- package/lib/main.js +1 -1
- package/lib/operation/delete.js +101 -52
- package/lib/operation/empty.js +21 -6
- package/lib/operation/insert.js +78 -31
- package/lib/operations/fromJSON.js +4 -4
- package/lib/operations/generate.js +11 -11
- package/lib/operations/transform.js +3 -7
- package/lib/richTextarea.js +244 -156
- package/lib/selection.js +55 -13
- package/lib/types.js +13 -13
- package/lib/undoBuffer.js +105 -0
- package/package.json +3 -2
- package/src/browser.js +3 -3
- package/src/constants.js +1 -0
- package/src/contentCompare.js +34 -0
- package/src/example/richTextarea.js +11 -9
- package/src/example/view.js +28 -10
- package/src/keyCodes.js +3 -0
- package/src/main.js +1 -0
- package/src/operation/delete.js +135 -58
- package/src/operation/empty.js +19 -14
- package/src/operation/insert.js +97 -39
- package/src/operations/fromJSON.js +4 -4
- package/src/operations/generate.js +17 -13
- package/src/operations/transform.js +3 -3
- package/src/richTextarea.js +316 -185
- package/src/selection.js +53 -9
- package/src/types.js +6 -6
- package/src/undoBuffer.js +73 -0
- package/test/content/transform.js +15 -17
- package/test/helpers.js +27 -21
- package/test/operation/delete.js +187 -147
- package/test/operation/empty.js +3 -5
- package/test/operation/insert.js +134 -118
- package/test/operations/generate.js +25 -29
- package/test/operations/transform.js +37 -98
- package/lib/stringCompare.js +0 -33
- package/src/stringCompare.js +0 -33
package/src/operation/delete.js
CHANGED
|
@@ -2,22 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
import EmptyOperation from "../operation/empty";
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { INSERT_TYPE, DELETE_TYPE, EMPTY_TYPE } from "../types";
|
|
6
6
|
|
|
7
7
|
export default class DeleteOperation {
|
|
8
|
-
constructor(type,
|
|
8
|
+
constructor(type, content, position) {
|
|
9
9
|
this.type = type;
|
|
10
|
-
this.
|
|
10
|
+
this.content = content;
|
|
11
11
|
this.position = position;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
return
|
|
14
|
+
getType() {
|
|
15
|
+
return this.type;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
getContent() {
|
|
19
|
+
return this.content;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
getPosition() {
|
|
23
|
+
return this.position;
|
|
16
24
|
}
|
|
17
25
|
|
|
18
26
|
transformOperation(operation) {
|
|
19
|
-
|
|
20
|
-
|
|
27
|
+
const type = operation.getType();
|
|
28
|
+
|
|
29
|
+
switch (type) {
|
|
30
|
+
case INSERT_TYPE:
|
|
21
31
|
return ((tau, rho) => {
|
|
22
32
|
|
|
23
33
|
if (tau.position <= rho.position) {
|
|
@@ -25,56 +35,61 @@ export default class DeleteOperation {
|
|
|
25
35
|
}
|
|
26
36
|
|
|
27
37
|
if (tau.position > rho.position) {
|
|
28
|
-
if (tau.position < rho.length + rho.position) {
|
|
38
|
+
if (tau.position < rho.content.length + rho.position) {
|
|
29
39
|
return [tau.left(rho).shift(tau)];
|
|
30
40
|
}
|
|
31
|
-
|
|
41
|
+
|
|
42
|
+
if (tau.position >= rho.content.length + rho.position) {
|
|
32
43
|
return [rho.shift(tau)];
|
|
33
44
|
}
|
|
34
45
|
}
|
|
35
46
|
|
|
36
47
|
})(operation, this);
|
|
37
48
|
|
|
38
|
-
case
|
|
49
|
+
case DELETE_TYPE:
|
|
39
50
|
return ((tau, rho) => {
|
|
40
51
|
|
|
41
52
|
if (tau.position < rho.position) {
|
|
42
|
-
if (tau.length + tau.position <= rho.position) {
|
|
53
|
+
if (tau.content.length + tau.position <= rho.position) {
|
|
43
54
|
return [tau.clone()];
|
|
44
55
|
}
|
|
45
|
-
|
|
56
|
+
|
|
57
|
+
if (tau.content.length + tau.position <= rho.content.length + rho.position) {
|
|
46
58
|
return [rho.takenFrom(tau)];
|
|
47
59
|
}
|
|
48
|
-
|
|
60
|
+
|
|
61
|
+
if (tau.content.length + tau.position > rho.content.length + rho.position) {
|
|
49
62
|
return [rho.split(tau)];
|
|
50
63
|
}
|
|
51
64
|
}
|
|
52
65
|
|
|
53
66
|
if (tau.position === rho.position) {
|
|
54
|
-
if (tau.length + tau.position <= rho.length + rho.position) {
|
|
67
|
+
if (tau.content.length + tau.position <= rho.content.length + rho.position) {
|
|
55
68
|
return [EmptyOperation.fromNothing()];
|
|
56
69
|
}
|
|
57
|
-
|
|
70
|
+
|
|
71
|
+
if (tau.content.length + tau.position > rho.content.length + rho.position) {
|
|
58
72
|
return [rho.shift(rho.takenFrom(tau))];
|
|
59
73
|
}
|
|
60
74
|
}
|
|
61
75
|
|
|
62
|
-
if (tau.position >= rho.length + rho.position) {
|
|
76
|
+
if (tau.position >= rho.content.length + rho.position) {
|
|
63
77
|
return [rho.shift(tau)];
|
|
64
78
|
}
|
|
65
79
|
|
|
66
80
|
if (tau.position > rho.position) {
|
|
67
|
-
if (tau.length + tau.position <= rho.length + rho.position) {
|
|
81
|
+
if (tau.content.length + tau.position <= rho.content.length + rho.position) {
|
|
68
82
|
return [EmptyOperation.fromNothing()];
|
|
69
83
|
}
|
|
70
|
-
|
|
84
|
+
|
|
85
|
+
if (tau.content.length + tau.position > rho.content.length + rho.position) {
|
|
71
86
|
return [rho.shift(rho.takenFrom(tau))];
|
|
72
87
|
}
|
|
73
88
|
}
|
|
74
89
|
|
|
75
90
|
})(operation, this);
|
|
76
91
|
|
|
77
|
-
case
|
|
92
|
+
case EMPTY_TYPE:
|
|
78
93
|
return ((tau, rho) => {
|
|
79
94
|
|
|
80
95
|
return [tau.clone()];
|
|
@@ -84,44 +99,53 @@ export default class DeleteOperation {
|
|
|
84
99
|
}
|
|
85
100
|
|
|
86
101
|
transformContent(content) {
|
|
87
|
-
|
|
102
|
+
let start, end;
|
|
103
|
+
|
|
104
|
+
start = 0;
|
|
105
|
+
|
|
106
|
+
end = this.position;
|
|
107
|
+
|
|
108
|
+
const leftContent = content.substring(start, end),
|
|
109
|
+
contentLength = this.content.length;
|
|
110
|
+
|
|
111
|
+
start = this.position + contentLength;
|
|
112
|
+
|
|
113
|
+
const rightContent = content.substring(start),
|
|
114
|
+
transformedContent = leftContent + rightContent;
|
|
115
|
+
|
|
116
|
+
return transformedContent;
|
|
88
117
|
}
|
|
89
118
|
|
|
90
119
|
transformSelection(selection) {
|
|
91
120
|
let transformedSelection;
|
|
92
121
|
|
|
93
|
-
const
|
|
122
|
+
const selectionStartPosition = selection.getStartPosition(),
|
|
123
|
+
selectionEndPosition = selection.getEndPosition(),
|
|
124
|
+
contentLength = this.content.length,
|
|
94
125
|
startPosition = this.position, ///
|
|
95
|
-
endPosition = startPosition +
|
|
96
|
-
selectionStartPosition = selection.getStartPosition(),
|
|
97
|
-
selectionEndPosition = selection.getEndPosition();
|
|
98
|
-
|
|
99
|
-
let offset,
|
|
100
|
-
endOffset;
|
|
126
|
+
endPosition = startPosition + contentLength;
|
|
101
127
|
|
|
102
128
|
if (false) {
|
|
103
129
|
///
|
|
104
130
|
} else if (selectionStartPosition >= endPosition) {
|
|
105
|
-
offset = -
|
|
131
|
+
const offset = -contentLength;
|
|
106
132
|
|
|
107
133
|
transformedSelection = selection.shifted(offset);
|
|
108
134
|
} else if (selectionStartPosition >= startPosition) {
|
|
109
135
|
if (selectionEndPosition > endPosition) {
|
|
110
|
-
offset = startPosition - selectionStartPosition
|
|
111
|
-
|
|
136
|
+
const offset = startPosition - selectionStartPosition,
|
|
137
|
+
endOffset = selectionStartPosition - endPosition;
|
|
112
138
|
|
|
113
139
|
transformedSelection = selection.shifted(offset).endPositionShifted(endOffset);
|
|
114
140
|
} else {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
transformedSelection = new Selection(startPosition, startPosition);
|
|
141
|
+
transformedSelection = selection.emptied();
|
|
118
142
|
}
|
|
119
143
|
} else if (selectionEndPosition > endPosition) {
|
|
120
|
-
endOffset = -
|
|
144
|
+
const endOffset = -contentLength;
|
|
121
145
|
|
|
122
146
|
transformedSelection = selection.endPositionShifted(endOffset);
|
|
123
147
|
} else if (selectionEndPosition > startPosition) {
|
|
124
|
-
endOffset = startPosition - selectionEndPosition;
|
|
148
|
+
const endOffset = startPosition - selectionEndPosition;
|
|
125
149
|
|
|
126
150
|
transformedSelection = selection.endPositionShifted(endOffset);
|
|
127
151
|
} else {
|
|
@@ -132,58 +156,96 @@ export default class DeleteOperation {
|
|
|
132
156
|
}
|
|
133
157
|
|
|
134
158
|
shifted(offset) {
|
|
135
|
-
const
|
|
159
|
+
const content = this.content,
|
|
136
160
|
position = this.position + offset,
|
|
137
|
-
deleteOperation = DeleteOperation.
|
|
161
|
+
deleteOperation = DeleteOperation.fromContentAndPosition(content, position);
|
|
138
162
|
|
|
139
163
|
return deleteOperation;
|
|
140
164
|
}
|
|
141
165
|
|
|
142
166
|
shift(operation) {
|
|
143
|
-
const
|
|
167
|
+
const contentLength = this.content.length,
|
|
168
|
+
offset = -contentLength,
|
|
144
169
|
shiftedOperation = operation.shifted(offset);
|
|
145
170
|
|
|
146
171
|
return shiftedOperation
|
|
147
172
|
}
|
|
148
173
|
|
|
149
174
|
takenFrom(deleteOperation) {
|
|
150
|
-
let
|
|
151
|
-
position = deleteOperation.
|
|
175
|
+
let content = deleteOperation.getContent(),
|
|
176
|
+
position = deleteOperation.getPosition();
|
|
177
|
+
|
|
178
|
+
let contentLength = content.length;
|
|
152
179
|
|
|
153
|
-
if (this.position > position && this.
|
|
154
|
-
|
|
180
|
+
if ((this.position > position) && (this.position + this.content.length >= position + contentLength)) {
|
|
181
|
+
const contentLength = this.position - position,
|
|
182
|
+
start = 0,
|
|
183
|
+
end = start + contentLength; ///
|
|
155
184
|
|
|
156
|
-
|
|
185
|
+
content = content.substring(start, end);
|
|
186
|
+
|
|
187
|
+
deleteOperation = DeleteOperation.fromContentAndPosition(content, position);
|
|
157
188
|
}
|
|
158
189
|
|
|
159
|
-
if (this.position <= position && this.
|
|
160
|
-
|
|
161
|
-
|
|
190
|
+
if ((this.position <= position) && (this.position + this.content.length < position + contentLength)) {
|
|
191
|
+
contentLength = (position + contentLength) - (this.position + this.content.length);
|
|
192
|
+
|
|
193
|
+
const start = (this.position + this.content.length) - position,
|
|
194
|
+
end = start + contentLength; ///
|
|
162
195
|
|
|
163
|
-
|
|
196
|
+
position = this.position + this.content.length;
|
|
197
|
+
|
|
198
|
+
content = content.substring(start, end);
|
|
199
|
+
|
|
200
|
+
deleteOperation = DeleteOperation.fromContentAndPosition(content, position);
|
|
164
201
|
}
|
|
165
202
|
|
|
166
203
|
return deleteOperation;
|
|
167
204
|
}
|
|
168
205
|
|
|
169
206
|
split(deleteOperation) {
|
|
170
|
-
let
|
|
171
|
-
position = deleteOperation.
|
|
207
|
+
let content = deleteOperation.getContent(),
|
|
208
|
+
position = deleteOperation.getPosition();
|
|
209
|
+
|
|
210
|
+
let start,
|
|
211
|
+
end;
|
|
212
|
+
|
|
213
|
+
start = 0;
|
|
214
|
+
|
|
215
|
+
end = this.position - position;
|
|
216
|
+
|
|
217
|
+
const leftContent = content.substring(start, end);
|
|
218
|
+
|
|
219
|
+
start = this.position - position + this.content.length;
|
|
220
|
+
|
|
221
|
+
const rightContent = content.substring(start);
|
|
222
|
+
|
|
223
|
+
content = leftContent + rightContent;
|
|
224
|
+
|
|
225
|
+
deleteOperation = DeleteOperation.fromContentAndPosition(content, position);
|
|
226
|
+
|
|
227
|
+
return deleteOperation;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
invert(InsertOperation, DeleteOperation) {
|
|
231
|
+
const insertOperation = InsertOperation.fromContentAndPosition(this.content, this.position);
|
|
172
232
|
|
|
173
|
-
|
|
233
|
+
return insertOperation;
|
|
234
|
+
}
|
|
174
235
|
|
|
175
|
-
|
|
236
|
+
clone() {
|
|
237
|
+
const deleteOperation = DeleteOperation.fromContentAndPosition(this.content, this.position);
|
|
176
238
|
|
|
177
239
|
return deleteOperation;
|
|
178
240
|
}
|
|
179
241
|
|
|
180
242
|
toJSON() {
|
|
181
243
|
const type = this.type,
|
|
182
|
-
|
|
244
|
+
content = this.content,
|
|
183
245
|
position = this.position,
|
|
184
246
|
json = {
|
|
185
247
|
type,
|
|
186
|
-
|
|
248
|
+
content,
|
|
187
249
|
position,
|
|
188
250
|
};
|
|
189
251
|
|
|
@@ -191,15 +253,30 @@ export default class DeleteOperation {
|
|
|
191
253
|
}
|
|
192
254
|
|
|
193
255
|
static fromJSON(json) {
|
|
194
|
-
const { type,
|
|
195
|
-
deleteOperation = new DeleteOperation(type,
|
|
256
|
+
const { type, content, position } = json,
|
|
257
|
+
deleteOperation = new DeleteOperation(type, content, position);
|
|
196
258
|
|
|
197
259
|
return deleteOperation;
|
|
198
260
|
}
|
|
199
261
|
|
|
200
|
-
static
|
|
201
|
-
const type =
|
|
202
|
-
deleteOperation = new DeleteOperation(type,
|
|
262
|
+
static fromContentAndPosition(content, position) {
|
|
263
|
+
const type = DELETE_TYPE, ///
|
|
264
|
+
deleteOperation = new DeleteOperation(type, content, position);
|
|
265
|
+
|
|
266
|
+
return deleteOperation;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
static fromContentAndSelection(content, selection) {
|
|
270
|
+
const startPosition = selection.getStartPosition(),
|
|
271
|
+
endPosition = selection.getEndPosition(),
|
|
272
|
+
begin = startPosition, ///
|
|
273
|
+
end = endPosition; ///
|
|
274
|
+
|
|
275
|
+
content = content.slice(begin, end); ///
|
|
276
|
+
|
|
277
|
+
const type = DELETE_TYPE, ///
|
|
278
|
+
position = startPosition, ///
|
|
279
|
+
deleteOperation = new DeleteOperation(type, content, position);
|
|
203
280
|
|
|
204
281
|
return deleteOperation;
|
|
205
282
|
}
|
package/src/operation/empty.js
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { EMPTY_TYPE } from "../types";
|
|
4
4
|
|
|
5
5
|
export default class EmptyOperation {
|
|
6
6
|
constructor(type) {
|
|
7
7
|
this.type = type;
|
|
8
|
-
|
|
9
|
-
|
|
10
8
|
}
|
|
11
9
|
|
|
12
|
-
|
|
13
|
-
return
|
|
10
|
+
getType() {
|
|
11
|
+
return this.type;
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
transformOperation(operation) {
|
|
@@ -22,7 +20,9 @@ export default class EmptyOperation {
|
|
|
22
20
|
}
|
|
23
21
|
|
|
24
22
|
transformContent(content) {
|
|
25
|
-
|
|
23
|
+
const transformedContent = content; ///
|
|
24
|
+
|
|
25
|
+
return transformedContent;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
transformSelection(selection) {
|
|
@@ -31,8 +31,6 @@ export default class EmptyOperation {
|
|
|
31
31
|
return transformedSelection;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
34
|
shift(operation) {
|
|
37
35
|
const offset = 0,
|
|
38
36
|
shiftedOperation = operation.shifted(offset);
|
|
@@ -40,17 +38,24 @@ export default class EmptyOperation {
|
|
|
40
38
|
return shiftedOperation;
|
|
41
39
|
}
|
|
42
40
|
|
|
41
|
+
invert(InsertOperation, DeleteOperation) {
|
|
42
|
+
const type = EMPTY_TYPE,
|
|
43
|
+
emptyOperation = new EmptyOperation(type);
|
|
43
44
|
|
|
45
|
+
return emptyOperation;
|
|
46
|
+
}
|
|
44
47
|
|
|
48
|
+
clone() {
|
|
49
|
+
const emptyOperation = EmptyOperation.fromNothing();
|
|
45
50
|
|
|
51
|
+
return emptyOperation;
|
|
52
|
+
}
|
|
46
53
|
|
|
47
54
|
toJSON() {
|
|
48
55
|
const type = this.type,
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
json = {
|
|
57
|
+
type
|
|
58
|
+
};
|
|
54
59
|
|
|
55
60
|
return json;
|
|
56
61
|
}
|
|
@@ -63,7 +68,7 @@ export default class EmptyOperation {
|
|
|
63
68
|
}
|
|
64
69
|
|
|
65
70
|
static fromNothing() {
|
|
66
|
-
const type =
|
|
71
|
+
const type = EMPTY_TYPE, ///
|
|
67
72
|
emptyOperation = new EmptyOperation(type);
|
|
68
73
|
|
|
69
74
|
return emptyOperation;
|
package/src/operation/insert.js
CHANGED
|
@@ -1,24 +1,34 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import contentCompare from "../contentCompare";
|
|
4
4
|
import DeleteOperation from "../operation/delete";
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { INSERT_TYPE, DELETE_TYPE, EMPTY_TYPE } from "../types";
|
|
7
7
|
|
|
8
8
|
export default class InsertOperation {
|
|
9
|
-
constructor(type,
|
|
9
|
+
constructor(type, content, position) {
|
|
10
10
|
this.type = type;
|
|
11
|
-
this.
|
|
11
|
+
this.content = content;
|
|
12
12
|
this.position = position;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
return
|
|
15
|
+
getType() {
|
|
16
|
+
return this.type;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
getContent() {
|
|
20
|
+
return this.content;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
getPosition() {
|
|
24
|
+
return this.position;
|
|
17
25
|
}
|
|
18
26
|
|
|
19
27
|
transformOperation(operation) {
|
|
20
|
-
|
|
21
|
-
|
|
28
|
+
const type = operation.getType();
|
|
29
|
+
|
|
30
|
+
switch (type) {
|
|
31
|
+
case INSERT_TYPE:
|
|
22
32
|
return ((tau, rho) => {
|
|
23
33
|
|
|
24
34
|
if (tau.position < rho.position) {
|
|
@@ -26,11 +36,12 @@ export default class InsertOperation {
|
|
|
26
36
|
}
|
|
27
37
|
|
|
28
38
|
if (tau.position === rho.position) {
|
|
29
|
-
if (tau.
|
|
39
|
+
if (tau.content === rho.content) {
|
|
30
40
|
return [tau.clone()];
|
|
31
41
|
}
|
|
32
|
-
|
|
33
|
-
|
|
42
|
+
|
|
43
|
+
if (tau.content !== rho.content) {
|
|
44
|
+
if (contentCompare(rho.content, tau.content)) {
|
|
34
45
|
return [rho.shift(tau)];
|
|
35
46
|
} else {
|
|
36
47
|
return [tau.clone()];
|
|
@@ -44,10 +55,10 @@ export default class InsertOperation {
|
|
|
44
55
|
|
|
45
56
|
})(operation, this);
|
|
46
57
|
|
|
47
|
-
case
|
|
58
|
+
case DELETE_TYPE:
|
|
48
59
|
return ((tau, rho) => {
|
|
49
60
|
|
|
50
|
-
if (tau.position + tau.length <= rho.position) {
|
|
61
|
+
if (tau.position + tau.content.length <= rho.position) {
|
|
51
62
|
return [tau.clone()];
|
|
52
63
|
}
|
|
53
64
|
|
|
@@ -61,7 +72,7 @@ export default class InsertOperation {
|
|
|
61
72
|
|
|
62
73
|
})(operation, this);
|
|
63
74
|
|
|
64
|
-
case
|
|
75
|
+
case EMPTY_TYPE:
|
|
65
76
|
return ((tau, rho) => {
|
|
66
77
|
|
|
67
78
|
return [tau.clone()];
|
|
@@ -71,24 +82,41 @@ export default class InsertOperation {
|
|
|
71
82
|
}
|
|
72
83
|
|
|
73
84
|
transformContent(content) {
|
|
74
|
-
|
|
85
|
+
let start,
|
|
86
|
+
end;
|
|
87
|
+
|
|
88
|
+
start = 0;
|
|
89
|
+
|
|
90
|
+
end = this.position;
|
|
91
|
+
|
|
92
|
+
const leftContent = content.substring(start, end);
|
|
93
|
+
|
|
94
|
+
start = this.position;
|
|
95
|
+
|
|
96
|
+
const rightContent = content.substring(start),
|
|
97
|
+
transformedContent = leftContent + this.content + rightContent;
|
|
98
|
+
|
|
99
|
+
return transformedContent;
|
|
75
100
|
}
|
|
76
101
|
|
|
77
102
|
transformSelection(selection) {
|
|
78
103
|
let transformedSelection;
|
|
79
104
|
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
offset = length, ///
|
|
85
|
-
endOffset = offset; ///
|
|
105
|
+
const selectionStartPosition = selection.getStartPosition(),
|
|
106
|
+
selectionEndPosition = selection.getEndPosition(), ///
|
|
107
|
+
contentLength = this.content.length,
|
|
108
|
+
startPosition = this.position; ///
|
|
86
109
|
|
|
87
110
|
if (false) {
|
|
88
|
-
|
|
111
|
+
///
|
|
89
112
|
} else if (selectionStartPosition >= startPosition) {
|
|
113
|
+
const offset = contentLength; ///
|
|
114
|
+
|
|
90
115
|
transformedSelection = selection.shifted(offset);
|
|
91
116
|
} else if (selectionEndPosition > startPosition) {
|
|
117
|
+
const contentLength = this.content.length,
|
|
118
|
+
endOffset = contentLength; ///
|
|
119
|
+
|
|
92
120
|
transformedSelection = selection.endPositionShifted(endOffset);
|
|
93
121
|
} else {
|
|
94
122
|
transformedSelection = selection.clone();
|
|
@@ -98,15 +126,15 @@ export default class InsertOperation {
|
|
|
98
126
|
}
|
|
99
127
|
|
|
100
128
|
shifted(offset) {
|
|
101
|
-
const
|
|
129
|
+
const content = this.content,
|
|
102
130
|
position = this.position + offset,
|
|
103
|
-
insertOperation = InsertOperation.
|
|
131
|
+
insertOperation = InsertOperation.fromContentAndPosition(content, position);
|
|
104
132
|
|
|
105
133
|
return insertOperation;
|
|
106
134
|
}
|
|
107
135
|
|
|
108
136
|
shift(operation) {
|
|
109
|
-
const length = this.
|
|
137
|
+
const length = this.content.length,
|
|
110
138
|
offset = length, ///
|
|
111
139
|
shiftedOperation = operation.shifted(offset);
|
|
112
140
|
|
|
@@ -114,33 +142,54 @@ export default class InsertOperation {
|
|
|
114
142
|
}
|
|
115
143
|
|
|
116
144
|
left(deleteOperation) {
|
|
117
|
-
|
|
118
|
-
|
|
145
|
+
let content = deleteOperation.getContent();
|
|
146
|
+
|
|
147
|
+
const position = deleteOperation.getPosition(),
|
|
148
|
+
contentLength = this.position - position,
|
|
149
|
+
start = 0,
|
|
150
|
+
end = contentLength; ///
|
|
119
151
|
|
|
120
|
-
|
|
152
|
+
content = content.substring(start, end);
|
|
153
|
+
|
|
154
|
+
deleteOperation = DeleteOperation.fromContentAndPosition(content, position);
|
|
121
155
|
|
|
122
156
|
return deleteOperation;
|
|
123
157
|
}
|
|
124
158
|
|
|
125
159
|
right(deleteOperation) {
|
|
126
|
-
let
|
|
127
|
-
position = deleteOperation.
|
|
160
|
+
let content = deleteOperation.getContent(),
|
|
161
|
+
position = deleteOperation.getPosition();
|
|
162
|
+
|
|
163
|
+
const start = this.position - position;
|
|
128
164
|
|
|
129
|
-
length = length - this.position + position;
|
|
130
165
|
position = this.position;
|
|
131
166
|
|
|
132
|
-
|
|
167
|
+
content = content.substring(start);
|
|
168
|
+
|
|
169
|
+
deleteOperation = DeleteOperation.fromContentAndPosition(content, position);
|
|
170
|
+
|
|
171
|
+
return deleteOperation;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
invert(InsertOperation, DeleteOperation) {
|
|
175
|
+
const deleteOperation = DeleteOperation.fromContentAndPosition(this.content, this.position);
|
|
133
176
|
|
|
134
177
|
return deleteOperation;
|
|
135
178
|
}
|
|
136
179
|
|
|
180
|
+
clone() {
|
|
181
|
+
const insertOperation = InsertOperation.fromContentAndPosition(this.content, this.position);
|
|
182
|
+
|
|
183
|
+
return insertOperation;
|
|
184
|
+
}
|
|
185
|
+
|
|
137
186
|
toJSON() {
|
|
138
187
|
const type = this.type,
|
|
139
|
-
|
|
188
|
+
content = this.content,
|
|
140
189
|
position = this.position,
|
|
141
190
|
json = {
|
|
142
191
|
type,
|
|
143
|
-
|
|
192
|
+
content,
|
|
144
193
|
position
|
|
145
194
|
};
|
|
146
195
|
|
|
@@ -148,15 +197,24 @@ export default class InsertOperation {
|
|
|
148
197
|
}
|
|
149
198
|
|
|
150
199
|
static fromJSON(json) {
|
|
151
|
-
const { type,
|
|
152
|
-
insertOperation = new InsertOperation(type,
|
|
200
|
+
const { type, content, position } = json,
|
|
201
|
+
insertOperation = new InsertOperation(type, content, position);
|
|
202
|
+
|
|
203
|
+
return insertOperation;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
static fromContentAndPosition(content, position) {
|
|
207
|
+
const type = INSERT_TYPE, ///
|
|
208
|
+
insertOperation = new InsertOperation(type, content, position);
|
|
153
209
|
|
|
154
210
|
return insertOperation;
|
|
155
211
|
}
|
|
156
212
|
|
|
157
|
-
static
|
|
158
|
-
const
|
|
159
|
-
|
|
213
|
+
static fromContentAndSelection(content, selection) {
|
|
214
|
+
const startPosition = selection.getStartPosition(),
|
|
215
|
+
type = INSERT_TYPE, ///
|
|
216
|
+
position = startPosition, ///
|
|
217
|
+
insertOperation = new InsertOperation(type, content, position);
|
|
160
218
|
|
|
161
219
|
return insertOperation;
|
|
162
220
|
}
|
|
@@ -4,7 +4,7 @@ import EmptyOperation from "../operation/empty";
|
|
|
4
4
|
import DeleteOperation from "../operation/delete";
|
|
5
5
|
import InsertOperation from "../operation/insert";
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { EMPTY_TYPE, DELETE_TYPE, INSERT_TYPE } from "../types";
|
|
8
8
|
|
|
9
9
|
export default function operationsFromJSON(operationsJSON) {
|
|
10
10
|
const operations = operationsJSON.map((operationJSON) => {
|
|
@@ -14,15 +14,15 @@ export default function operationsFromJSON(operationsJSON) {
|
|
|
14
14
|
{ type } = json;
|
|
15
15
|
|
|
16
16
|
switch (type) {
|
|
17
|
-
case
|
|
17
|
+
case EMPTY_TYPE:
|
|
18
18
|
operation = EmptyOperation.fromJSON(json);
|
|
19
19
|
break;
|
|
20
20
|
|
|
21
|
-
case
|
|
21
|
+
case DELETE_TYPE:
|
|
22
22
|
operation = DeleteOperation.fromJSON(json);
|
|
23
23
|
break;
|
|
24
24
|
|
|
25
|
-
case
|
|
25
|
+
case INSERT_TYPE:
|
|
26
26
|
operation = InsertOperation.fromJSON(json);
|
|
27
27
|
break;
|
|
28
28
|
}
|