easy-richtextarea 4.0.3 → 4.0.5
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 +1535 -1039
- package/lib/browser.js +9 -5
- 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 +9 -5
- 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 +3 -3
- package/lib/richTextarea.js +258 -153
- package/lib/selection.js +55 -13
- package/lib/transform/content.js +19 -0
- package/lib/{operations/transform.js → transform/operations.js} +3 -7
- package/lib/transform/selection.js +19 -0
- package/lib/types.js +13 -13
- package/lib/undoBuffer.js +140 -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 +3 -2
- 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 +8 -4
- package/src/richTextarea.js +343 -181
- package/src/selection.js +53 -9
- package/src/transform/content.js +11 -0
- package/src/{operations/transform.js → transform/operations.js} +3 -3
- package/src/transform/selection.js +11 -0
- package/src/types.js +6 -6
- package/src/undoBuffer.js +105 -0
- package/test/content/transform.js +9 -11
- 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 +19 -22
- package/test/operations/transform.js +37 -98
- package/lib/content/transform.js +0 -17
- package/lib/stringCompare.js +0 -33
- package/src/content/transform.js +0 -5
- package/src/stringCompare.js +0 -33
|
@@ -23,17 +23,21 @@ export default function generateOperations(contentA, contentB) {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
if (left + right !== contentALength) {
|
|
26
|
-
const
|
|
26
|
+
const start = left, ///
|
|
27
|
+
end = contentALength - right,
|
|
28
|
+
content = contentA.substring(start, end),
|
|
27
29
|
position = left, ///
|
|
28
|
-
deleteOperation = DeleteOperation.
|
|
30
|
+
deleteOperation = DeleteOperation.fromContentAndPosition(content, position);
|
|
29
31
|
|
|
30
32
|
operations.push(deleteOperation);
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
if (left + right !== contentBLength) {
|
|
34
|
-
const
|
|
36
|
+
const start = left, ///
|
|
37
|
+
end = contentBLength - right,
|
|
38
|
+
content = contentB.substring(start, end),
|
|
35
39
|
position = left, ///
|
|
36
|
-
insertOperation = InsertOperation.
|
|
40
|
+
insertOperation = InsertOperation.fromContentAndPosition(content, position);
|
|
37
41
|
|
|
38
42
|
operations.push(insertOperation);
|
|
39
43
|
}
|
package/src/richTextarea.js
CHANGED
|
@@ -1,86 +1,138 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { Element, document, eventTypes } from "easy";
|
|
4
4
|
|
|
5
5
|
import Selection from "./selection"
|
|
6
|
+
import UndoBuffer from "./undoBuffer";
|
|
7
|
+
import InsertOperation from "./operation/insert";
|
|
8
|
+
import DeleteOperation from "./operation/delete";
|
|
9
|
+
import transformContent from "./transform/content";
|
|
10
|
+
import transformSelection from "./transform/selection";
|
|
11
|
+
import generateOperations from "./operations/generate";
|
|
12
|
+
|
|
13
|
+
import { Z_KEY_CODE } from "./keyCodes";
|
|
14
|
+
import { TEXT, EMPTY_STRING } from "./constants";
|
|
15
|
+
|
|
16
|
+
const { CUT_EVENT_TYPE,
|
|
17
|
+
COPY_EVENT_TYPE,
|
|
18
|
+
BLUR_EVENT_TYPE,
|
|
19
|
+
PASTE_EVENT_TYPE,
|
|
20
|
+
INPUT_EVENT_TYPE,
|
|
21
|
+
FOCUS_EVENT_TYPE,
|
|
22
|
+
CHANGE_EVENT_TYPE,
|
|
23
|
+
SCROLL_EVENT_TYPE,
|
|
24
|
+
KEYDOWN_EVENT_TYPE,
|
|
25
|
+
CONTEXTMENU_EVENT_TYPE,
|
|
26
|
+
SELECTIONCHANGE_EVENT_TYPE } = eventTypes;
|
|
6
27
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
CHANGE_EVENT_TYPE,
|
|
11
|
-
SCROLL_EVENT_TYPE,
|
|
12
|
-
KEYDOWN_EVENT_TYPE,
|
|
13
|
-
MOUSEUP_EVENT_TYPE,
|
|
14
|
-
MOUSEDOWN_EVENT_TYPE,
|
|
15
|
-
MOUSEMOVE_EVENT_TYPE,
|
|
16
|
-
CONTEXTMENU_EVENT_TYPE } = eventTypes;
|
|
28
|
+
export default class RichTextarea extends Element {
|
|
29
|
+
constructor(selector, focused, readOnly, undoBuffer, previousContent, previousSelection) {
|
|
30
|
+
super(selector);
|
|
17
31
|
|
|
18
|
-
|
|
32
|
+
this.focused = focused;
|
|
33
|
+
this.readOnly = readOnly;
|
|
34
|
+
this.undoBuffer = undoBuffer;
|
|
35
|
+
this.previousContent = previousContent;
|
|
36
|
+
this.previousSelection = previousSelection;
|
|
37
|
+
}
|
|
19
38
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
39
|
+
isFocused() {
|
|
40
|
+
return this.focused;
|
|
41
|
+
}
|
|
23
42
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
43
|
+
isReadOnly() {
|
|
44
|
+
return this.readOnly;
|
|
45
|
+
}
|
|
27
46
|
|
|
28
|
-
|
|
29
|
-
|
|
47
|
+
getUndoBuffer() {
|
|
48
|
+
return this.undoBuffer;
|
|
49
|
+
}
|
|
30
50
|
|
|
31
|
-
|
|
51
|
+
getPreviousContent() {
|
|
52
|
+
return this.prevousContent;
|
|
53
|
+
}
|
|
32
54
|
|
|
33
|
-
|
|
34
|
-
|
|
55
|
+
getPreviousSelection() {
|
|
56
|
+
return this.previousSelection;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
setFocused(focused) {
|
|
60
|
+
this.focused = focused;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
setReadOnly(readOnly) {
|
|
64
|
+
this.readOnly = readOnly;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
setPreviousContent(previousContent) {
|
|
68
|
+
this.previousContent = previousContent;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
setPreviousSelection(previousSelection) {
|
|
72
|
+
this.previousSelection = previousSelection;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
intermediateHandler = (event, element, undoable = true, eventType = CHANGE_EVENT_TYPE, selectionChanged = this.hasSelectionChanged()) => {
|
|
76
|
+
if (this.readOnly) {
|
|
77
|
+
const content = this.previousContent; ///
|
|
78
|
+
|
|
79
|
+
this.setContent(content);
|
|
35
80
|
}
|
|
36
81
|
|
|
37
82
|
const content = this.getContent(),
|
|
38
83
|
selection = this.getSelection(),
|
|
39
|
-
|
|
40
|
-
|
|
84
|
+
contentChanged = this.hasContentChanged(),
|
|
85
|
+
changed = (contentChanged || selectionChanged);
|
|
41
86
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
87
|
+
if (changed) {
|
|
88
|
+
this.callHandlers(eventType, event, element);
|
|
89
|
+
}
|
|
45
90
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
eventType = CHANGE_EVENT_TYPE;
|
|
91
|
+
if (undoable) {
|
|
92
|
+
if (contentChanged) {
|
|
93
|
+
const operations = generateOperations(this.previousContent, content);
|
|
50
94
|
|
|
51
|
-
|
|
95
|
+
this.undoBuffer.addOperations(operations);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
52
98
|
|
|
53
|
-
|
|
54
|
-
}
|
|
99
|
+
this.previousContent = content; ///
|
|
55
100
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
mouseDown = this.isMouseDown(),
|
|
59
|
-
eventTYpe = CHANGE_EVENT_TYPE;
|
|
101
|
+
this.previousSelection = selection; ///
|
|
102
|
+
}
|
|
60
103
|
|
|
61
|
-
|
|
62
|
-
|
|
104
|
+
selectChangeHandler = (event, element) => {
|
|
105
|
+
if (this.focused) {
|
|
106
|
+
this.intermediateHandler(event, element);
|
|
63
107
|
}
|
|
64
108
|
}
|
|
65
109
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
this.setMouseDown(mouseDown);
|
|
70
|
-
};
|
|
110
|
+
contextmenuHandler = (event, element) => {
|
|
111
|
+
event.preventDefault();
|
|
112
|
+
}
|
|
71
113
|
|
|
72
114
|
keyDownHandler = (event, element) => {
|
|
73
|
-
const
|
|
74
|
-
eventType = CHANGE_EVENT_TYPE;
|
|
115
|
+
const { keyCode } = event;
|
|
75
116
|
|
|
76
|
-
|
|
77
|
-
|
|
117
|
+
if (keyCode === Z_KEY_CODE) {
|
|
118
|
+
const { ctrlKey, metaKey } = event;
|
|
78
119
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
eventType = CHANGE_EVENT_TYPE;
|
|
120
|
+
if (ctrlKey || metaKey) {
|
|
121
|
+
const { shiftKey } = event;
|
|
82
122
|
|
|
83
|
-
|
|
123
|
+
shiftKey ?
|
|
124
|
+
this.redo(event, element) :
|
|
125
|
+
this.undo(event, element);
|
|
126
|
+
|
|
127
|
+
event.preventDefault();
|
|
128
|
+
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
defer(() => {
|
|
134
|
+
this.intermediateHandler(event, element);
|
|
135
|
+
});
|
|
84
136
|
}
|
|
85
137
|
|
|
86
138
|
scrollHandler = (event, element) => {
|
|
@@ -90,17 +142,97 @@ export default class RichTextarea extends Element {
|
|
|
90
142
|
}
|
|
91
143
|
|
|
92
144
|
focusHandler = (event, element) => {
|
|
93
|
-
|
|
94
|
-
eventType = FOCUS_EVENT_TYPE;
|
|
145
|
+
this.focused = true;
|
|
95
146
|
|
|
96
|
-
defer(() =>
|
|
147
|
+
defer(() => {
|
|
148
|
+
const undoable = true,
|
|
149
|
+
eventType = FOCUS_EVENT_TYPE,
|
|
150
|
+
selectionChanged = true;
|
|
151
|
+
|
|
152
|
+
this.intermediateHandler(event, element, undoable, eventType, selectionChanged);
|
|
153
|
+
});
|
|
97
154
|
}
|
|
98
155
|
|
|
99
156
|
blurHandler = (event, element) => {
|
|
100
|
-
|
|
101
|
-
|
|
157
|
+
this.focused = false;
|
|
158
|
+
|
|
159
|
+
const undoable = true,
|
|
160
|
+
eventType = BLUR_EVENT_TYPE,
|
|
161
|
+
selectionChanged = true;
|
|
102
162
|
|
|
103
|
-
this.intermediateHandler(event, element, eventType,
|
|
163
|
+
this.intermediateHandler(event, element, undoable, eventType, selectionChanged);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
inputHandler = (event, element) => {
|
|
167
|
+
this.intermediateHandler(event, element);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
pasteHandler = (event, element) => {
|
|
171
|
+
const { clipboardData } = event,
|
|
172
|
+
textData = clipboardData.getData(TEXT);
|
|
173
|
+
|
|
174
|
+
if (textData === EMPTY_STRING) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const selection = this.getSelection(),
|
|
179
|
+
selectionEmpty = selection.isEmpty();
|
|
180
|
+
|
|
181
|
+
if (!selectionEmpty) {
|
|
182
|
+
const content = this.getContent(),
|
|
183
|
+
deleteOperation = DeleteOperation.fromContentAndSelection(content, selection),
|
|
184
|
+
operation = deleteOperation;
|
|
185
|
+
|
|
186
|
+
this.applyOperation(operation);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const content = textData, ///
|
|
190
|
+
insertOperation = InsertOperation.fromContentAndSelection(content, selection),
|
|
191
|
+
operation = insertOperation; ///
|
|
192
|
+
|
|
193
|
+
this.applyOperation(operation);
|
|
194
|
+
|
|
195
|
+
this.intermediateHandler(event, element);
|
|
196
|
+
|
|
197
|
+
event.preventDefault();
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
copyHandler = (event, element) => {
|
|
201
|
+
const selection = this.getSelection(),
|
|
202
|
+
selectionEmpty = selection.isEmpty();
|
|
203
|
+
|
|
204
|
+
if (selectionEmpty) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const selectedContent = this.getSelectedContent();
|
|
209
|
+
|
|
210
|
+
navigator.clipboard.writeText(selectedContent);
|
|
211
|
+
|
|
212
|
+
event.preventDefault();
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
cutHandler = (event, element) => {
|
|
216
|
+
const selection = this.getSelection(),
|
|
217
|
+
selectionEmpty = selection.isEmpty();
|
|
218
|
+
|
|
219
|
+
if (selectionEmpty) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const selectedContent = this.getSelectedContent();
|
|
224
|
+
|
|
225
|
+
navigator.clipboard.writeText(selectedContent);
|
|
226
|
+
|
|
227
|
+
const content = this.getContent(),
|
|
228
|
+
deleteOperation = DeleteOperation.fromContentAndSelection(content, selection),
|
|
229
|
+
operation = deleteOperation; ///
|
|
230
|
+
|
|
231
|
+
this.applyOperation(operation);
|
|
232
|
+
|
|
233
|
+
this.intermediateHandler(event, element);
|
|
234
|
+
|
|
235
|
+
event.preventDefault();
|
|
104
236
|
}
|
|
105
237
|
|
|
106
238
|
isActive() {
|
|
@@ -109,6 +241,30 @@ export default class RichTextarea extends Element {
|
|
|
109
241
|
return active;
|
|
110
242
|
}
|
|
111
243
|
|
|
244
|
+
undo(event, element) {
|
|
245
|
+
const operation = this.undoBuffer.undo();
|
|
246
|
+
|
|
247
|
+
if (operation !== null) {
|
|
248
|
+
const undoable = false;
|
|
249
|
+
|
|
250
|
+
this.applyOperation(operation);
|
|
251
|
+
|
|
252
|
+
this.intermediateHandler(event, element, undoable);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
redo(event, element) {
|
|
257
|
+
const operation = this.undoBuffer.redo();
|
|
258
|
+
|
|
259
|
+
if (operation !== null) {
|
|
260
|
+
const undoable = false;
|
|
261
|
+
|
|
262
|
+
this.applyOperation(operation);
|
|
263
|
+
|
|
264
|
+
this.intermediateHandler(event, element, undoable);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
112
268
|
getContent() {
|
|
113
269
|
const domElement = this.getDOMElement(),
|
|
114
270
|
{ value } = domElement,
|
|
@@ -124,71 +280,110 @@ export default class RichTextarea extends Element {
|
|
|
124
280
|
return selection;
|
|
125
281
|
}
|
|
126
282
|
|
|
127
|
-
|
|
283
|
+
getSelectedContent() {
|
|
284
|
+
const content = this.getContent(),
|
|
285
|
+
selection = this.getSelection(),
|
|
286
|
+
endPosition = selection.getEndPosition(),
|
|
287
|
+
startPosition = selection.getStartPosition(),
|
|
288
|
+
start = startPosition, ///
|
|
289
|
+
end = endPosition, ///
|
|
290
|
+
selectedContent = content.slice(start, end);
|
|
291
|
+
|
|
292
|
+
return selectedContent;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
hasContentChanged() {
|
|
296
|
+
const content = this.getContent(),
|
|
297
|
+
contentPreviousContent = (content === this.previousContent),
|
|
298
|
+
contentChanged = !contentPreviousContent;
|
|
299
|
+
|
|
300
|
+
return contentChanged;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
hasSelectionChanged() {
|
|
304
|
+
const selection = this.getSelection(),
|
|
305
|
+
selectionPreviousSelection = selection.isEqualTo(this.previousSelection),
|
|
306
|
+
selectionChanged = !selectionPreviousSelection; ///
|
|
307
|
+
|
|
308
|
+
return selectionChanged;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
setContent(content, setPreviousContent = true) {
|
|
128
312
|
const value = content, ///
|
|
129
|
-
previousContent = content, ///
|
|
130
313
|
domElement = this.getDOMElement();
|
|
131
314
|
|
|
132
315
|
Object.assign(domElement, {
|
|
133
316
|
value
|
|
134
317
|
});
|
|
135
318
|
|
|
136
|
-
|
|
319
|
+
if (setPreviousContent) {
|
|
320
|
+
this.previousContent = content; ///
|
|
321
|
+
}
|
|
137
322
|
}
|
|
138
323
|
|
|
139
|
-
setSelection(selection) {
|
|
324
|
+
setSelection(selection, setPreviousSelection = true) {
|
|
140
325
|
const selectionStartPosition = selection.getStartPosition(),
|
|
141
326
|
selectionEndPosition = selection.getEndPosition(),
|
|
142
327
|
selectionStart = selectionStartPosition, ///
|
|
143
328
|
selectionEnd = selectionEndPosition, ///
|
|
144
|
-
previousSelection = selection, ///
|
|
145
329
|
domElement = this.getDOMElement();
|
|
146
330
|
|
|
147
|
-
|
|
148
|
-
selectionStart,
|
|
149
|
-
selectionEnd
|
|
150
|
-
});
|
|
331
|
+
domElement.setSelectionRange(selectionStart, selectionEnd);
|
|
151
332
|
|
|
152
|
-
|
|
333
|
+
if (setPreviousSelection) {
|
|
334
|
+
this.previousSelection = selection; ///
|
|
335
|
+
}
|
|
153
336
|
}
|
|
154
337
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
changed = (contentChanged || selectionChanged);
|
|
338
|
+
applyOperation(operation) {
|
|
339
|
+
let content = this.getContent(),
|
|
340
|
+
selection = this.getSelection();
|
|
159
341
|
|
|
160
|
-
|
|
161
|
-
|
|
342
|
+
const transformedContent = operation.transformContent(content),
|
|
343
|
+
transformedSelection = operation.transformSelection(selection);
|
|
162
344
|
|
|
163
|
-
|
|
164
|
-
const content = this.getContent(),
|
|
165
|
-
previousContent = this.getPreviousContent(),
|
|
166
|
-
contentDifferentToPreviousContent = (content !== previousContent),
|
|
167
|
-
contentChanged = contentDifferentToPreviousContent; ///
|
|
345
|
+
content = transformedContent; ///
|
|
168
346
|
|
|
169
|
-
|
|
170
|
-
}
|
|
347
|
+
selection = transformedSelection; ///
|
|
171
348
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
previousSelection = this.getPreviousSelection(),
|
|
175
|
-
selectionDifferentToPreviousSelection = selection.isDifferentTo(previousSelection),
|
|
176
|
-
selectionChanged = selectionDifferentToPreviousSelection; ///
|
|
349
|
+
const setPreviousContent = false,
|
|
350
|
+
setPreviousSelection = false;
|
|
177
351
|
|
|
178
|
-
|
|
352
|
+
this.setContent(content, setPreviousContent);
|
|
353
|
+
|
|
354
|
+
this.setSelection(selection, setPreviousSelection);
|
|
179
355
|
}
|
|
180
356
|
|
|
181
|
-
|
|
182
|
-
|
|
357
|
+
transform(transformedPendingOperations) {
|
|
358
|
+
let content = this.getContent(),
|
|
359
|
+
selection = this.getSelection();
|
|
360
|
+
|
|
361
|
+
const operations = transformedPendingOperations, ///
|
|
362
|
+
transformedContent = transformContent(content, operations),
|
|
363
|
+
transformedSelection = transformSelection(selection, operations);
|
|
364
|
+
|
|
365
|
+
content = transformedContent; ///
|
|
366
|
+
|
|
367
|
+
selection = transformedSelection; ///
|
|
183
368
|
|
|
184
|
-
|
|
369
|
+
const setPreviousContent = false,
|
|
370
|
+
setPreviousSelection = false;
|
|
185
371
|
|
|
186
|
-
|
|
372
|
+
this.setContent(content, setPreviousContent);
|
|
187
373
|
|
|
188
|
-
this.
|
|
374
|
+
this.setSelection(selection, setPreviousSelection);
|
|
189
375
|
|
|
190
|
-
this.
|
|
376
|
+
this.undoBuffer.transform(transformedPendingOperations);
|
|
191
377
|
|
|
378
|
+
const event = null,
|
|
379
|
+
element = this,
|
|
380
|
+
undoable = false,
|
|
381
|
+
eventType = CHANGE_EVENT_TYPE;
|
|
382
|
+
|
|
383
|
+
this.intermediateHandler(event, element, undoable, eventType);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
activate() {
|
|
192
387
|
this.on(KEYDOWN_EVENT_TYPE, this.keyDownHandler, this);
|
|
193
388
|
|
|
194
389
|
this.on(INPUT_EVENT_TYPE, this.inputHandler, this);
|
|
@@ -203,16 +398,6 @@ export default class RichTextarea extends Element {
|
|
|
203
398
|
}
|
|
204
399
|
|
|
205
400
|
deactivate() {
|
|
206
|
-
const mouseDown = false;
|
|
207
|
-
|
|
208
|
-
this.setMouseDown(mouseDown);
|
|
209
|
-
|
|
210
|
-
window.off(`${BLUR_EVENT_TYPE} ${MOUSEUP_EVENT_TYPE} ${CONTEXTMENU_EVENT_TYPE}`, this.mouseUpHandler, this); ///
|
|
211
|
-
|
|
212
|
-
this.off(MOUSEDOWN_EVENT_TYPE, this.mouseDownHandler, this);
|
|
213
|
-
|
|
214
|
-
this.off(MOUSEMOVE_EVENT_TYPE, this.mouseMoveHandler, this);
|
|
215
|
-
|
|
216
401
|
this.off(KEYDOWN_EVENT_TYPE, this.keyDownHandler, this);
|
|
217
402
|
|
|
218
403
|
this.off(INPUT_EVENT_TYPE, this.inputHandler, this);
|
|
@@ -286,8 +471,12 @@ export default class RichTextarea extends Element {
|
|
|
286
471
|
const eventListeners = this.findEventListeners(eventType);
|
|
287
472
|
|
|
288
473
|
eventListeners.forEach((eventListener) => {
|
|
289
|
-
|
|
290
|
-
|
|
474
|
+
let { element } = eventListener;
|
|
475
|
+
|
|
476
|
+
const { handler } = eventListener,
|
|
477
|
+
handlerElement = element; ///
|
|
478
|
+
|
|
479
|
+
element = this; ///
|
|
291
480
|
|
|
292
481
|
if ((handler !== this.blurHandler) && (handler !== this.focusHandler) && (handler !== this.scrollHandler)) {
|
|
293
482
|
handler.call(handlerElement, ...remainingArguments, element);
|
|
@@ -295,88 +484,37 @@ export default class RichTextarea extends Element {
|
|
|
295
484
|
});
|
|
296
485
|
}
|
|
297
486
|
|
|
298
|
-
|
|
299
|
-
const {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
isMouseDown() {
|
|
305
|
-
const { mouseDown } = this.getState();
|
|
306
|
-
|
|
307
|
-
return mouseDown;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
getPreviousContent() {
|
|
311
|
-
const { previousContent } = this.getState();
|
|
312
|
-
|
|
313
|
-
return previousContent;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
getPreviousSelection() {
|
|
317
|
-
const { previousSelection } = this.getState();
|
|
487
|
+
didMount() {
|
|
488
|
+
const { onChange, onScroll, onFocus, onBlur } = this.properties,
|
|
489
|
+
changeHandler = onChange, ///
|
|
490
|
+
scrollHandler = onScroll, ///
|
|
491
|
+
focusHandler = onFocus, ///
|
|
492
|
+
blurHandler = onBlur; ///
|
|
318
493
|
|
|
319
|
-
|
|
320
|
-
|
|
494
|
+
const content = this.getContent(),
|
|
495
|
+
selection = this.getSelection();
|
|
321
496
|
|
|
322
|
-
|
|
323
|
-
this.updateState({
|
|
324
|
-
readOnly
|
|
325
|
-
});
|
|
326
|
-
}
|
|
497
|
+
this.previousContent = content; ///
|
|
327
498
|
|
|
328
|
-
|
|
329
|
-
this.updateState({
|
|
330
|
-
mouseDown
|
|
331
|
-
});
|
|
332
|
-
}
|
|
499
|
+
this.previousSelection = selection; ///
|
|
333
500
|
|
|
334
|
-
|
|
335
|
-
this.updateState({
|
|
336
|
-
previousContent
|
|
337
|
-
});
|
|
338
|
-
}
|
|
501
|
+
changeHandler && this.onChange(changeHandler, this);
|
|
339
502
|
|
|
340
|
-
|
|
341
|
-
this.updateState({
|
|
342
|
-
previousSelection
|
|
343
|
-
});
|
|
344
|
-
}
|
|
503
|
+
scrollHandler && this.onScroll(scrollHandler, this);
|
|
345
504
|
|
|
346
|
-
|
|
347
|
-
const readOnly = false,
|
|
348
|
-
mouseDown = false,
|
|
349
|
-
previousContent = null,
|
|
350
|
-
previousSelection = null;
|
|
505
|
+
focusHandler && this.onFocus(focusHandler, this);
|
|
351
506
|
|
|
352
|
-
this.
|
|
353
|
-
readOnly,
|
|
354
|
-
mouseDown,
|
|
355
|
-
previousContent,
|
|
356
|
-
previousSelection
|
|
357
|
-
});
|
|
358
|
-
}
|
|
507
|
+
blurHandler && this.onBlur(blurHandler, this);
|
|
359
508
|
|
|
360
|
-
|
|
361
|
-
const { onChange, onScroll, onFocus, onBlur } = this.properties,
|
|
362
|
-
changeHandler = onChange, ///
|
|
363
|
-
scrollHandler = onScroll, ///
|
|
364
|
-
focusHandler = onFocus, ///
|
|
365
|
-
blurHandler = onBlur; ///
|
|
509
|
+
this.on(CUT_EVENT_TYPE, this.cutHandler);
|
|
366
510
|
|
|
367
|
-
|
|
368
|
-
scrollHandler && this.onScroll(scrollHandler, this);
|
|
369
|
-
focusHandler && this.onFocus(focusHandler, this);
|
|
370
|
-
blurHandler && this.onBlur(blurHandler, this);
|
|
511
|
+
this.on(COPY_EVENT_TYPE, this.copyHandler);
|
|
371
512
|
|
|
372
|
-
|
|
373
|
-
selection = this.getSelection(),
|
|
374
|
-
previousContent = content, ///
|
|
375
|
-
previousSelection = selection; ///
|
|
513
|
+
this.on(PASTE_EVENT_TYPE, this.pasteHandler);
|
|
376
514
|
|
|
377
|
-
this.
|
|
515
|
+
this.on(CONTEXTMENU_EVENT_TYPE, this.contextmenuHandler);
|
|
378
516
|
|
|
379
|
-
this.
|
|
517
|
+
document.on(SELECTIONCHANGE_EVENT_TYPE, this.selectChangeHandler);
|
|
380
518
|
}
|
|
381
519
|
|
|
382
520
|
willUnmount() {
|
|
@@ -387,10 +525,23 @@ export default class RichTextarea extends Element {
|
|
|
387
525
|
blurHandler = onBlur; ///
|
|
388
526
|
|
|
389
527
|
changeHandler && this.offChange(changeHandler, this);
|
|
528
|
+
|
|
390
529
|
scrollHandler && this.offScroll(scrollHandler, this);
|
|
530
|
+
|
|
391
531
|
focusHandler && this.offFocus(focusHandler, this);
|
|
532
|
+
|
|
392
533
|
blurHandler && this.offBlur(blurHandler, this);
|
|
393
534
|
|
|
535
|
+
this.off(CUT_EVENT_TYPE, this.cutHandler);
|
|
536
|
+
|
|
537
|
+
this.off(COPY_EVENT_TYPE, this.copyHandler);
|
|
538
|
+
|
|
539
|
+
this.off(PASTE_EVENT_TYPE, this.pasteHandler);
|
|
540
|
+
|
|
541
|
+
this.off(CONTEXTMENU_EVENT_TYPE, this.contextmenuHandler);
|
|
542
|
+
|
|
543
|
+
document.off(SELECTIONCHANGE_EVENT_TYPE, this.selectChangeHandler);
|
|
544
|
+
|
|
394
545
|
const active = this.isActive();
|
|
395
546
|
|
|
396
547
|
if (active) {
|
|
@@ -398,10 +549,6 @@ export default class RichTextarea extends Element {
|
|
|
398
549
|
}
|
|
399
550
|
}
|
|
400
551
|
|
|
401
|
-
initialise() {
|
|
402
|
-
this.setInitialState();
|
|
403
|
-
}
|
|
404
|
-
|
|
405
552
|
static tagName = "textarea";
|
|
406
553
|
|
|
407
554
|
static ignoredProperties = [
|
|
@@ -414,4 +561,19 @@ export default class RichTextarea extends Element {
|
|
|
414
561
|
static defaultProperties = {
|
|
415
562
|
className: "rich"
|
|
416
563
|
};
|
|
564
|
+
|
|
565
|
+
static fromClass(Class, properties, ...remainingArguments) {
|
|
566
|
+
const focused = false,
|
|
567
|
+
readOnly = false,
|
|
568
|
+
undoBuffer = UndoBuffer.fromNothing(),
|
|
569
|
+
previousContent = null,
|
|
570
|
+
previousSelection = null,
|
|
571
|
+
richTextarea = Element.fromClass(Class, properties, focused, readOnly, undoBuffer, previousContent, previousSelection, ...remainingArguments);
|
|
572
|
+
|
|
573
|
+
return richTextarea;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
function defer(func) {
|
|
578
|
+
setTimeout(func, 0);
|
|
417
579
|
}
|