@zzish/math-rich-input 0.1.5 → 0.1.6
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.js +111 -82
- package/dist/math-rich-input.css +59 -56
- package/package.json +1 -1
- package/src/AccentBar.css +18 -10
- package/src/AccentBar.jsx +1007 -617
- package/src/EquationEditor.css +6 -0
- package/src/EquationEditorModal.css +13 -18
- package/src/MathRichInput.jsx +1239 -978
- package/src/Toolbar.css +20 -30
- package/src/Toolbar.jsx +177 -145
package/src/MathRichInput.jsx
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import React from
|
|
1
|
+
import React from "react";
|
|
2
2
|
|
|
3
3
|
import katex from "katex";
|
|
4
|
-
import {setupKatex} from "./katexHelper"
|
|
4
|
+
import { setupKatex } from "./katexHelper";
|
|
5
5
|
|
|
6
|
-
import EquationEditorModal from
|
|
7
|
-
import Toolbar from
|
|
6
|
+
import EquationEditorModal from "./EquationEditorModal";
|
|
7
|
+
import Toolbar from "./Toolbar";
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
10
|
isKatexNode,
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
removeEncodingIfPlainText,
|
|
13
13
|
rawTextToHtml,
|
|
14
14
|
getLatex,
|
|
15
|
-
setRangeParams,
|
|
15
|
+
setRangeParams,
|
|
16
16
|
getRangeParams,
|
|
17
17
|
getNodeTextLength,
|
|
18
18
|
findNodeWithIndex,
|
|
@@ -25,51 +25,50 @@ import {
|
|
|
25
25
|
replaceStringBeforeMarks,
|
|
26
26
|
insertCharacterBeforeMarks,
|
|
27
27
|
removeMarks,
|
|
28
|
-
replaceMarksWithMath
|
|
29
|
-
|
|
28
|
+
replaceMarksWithMath,
|
|
29
|
+
} from "./mathRichInputHelper";
|
|
30
30
|
|
|
31
|
-
import
|
|
32
|
-
import AccentBar from
|
|
31
|
+
import "./MathRichInput.css";
|
|
32
|
+
import AccentBar from "./AccentBar";
|
|
33
33
|
|
|
34
|
-
const MIME_TYPE_PLAIN_TEXT = "text/plain"
|
|
35
|
-
const MIME_TYPE_HTML = "text/html"
|
|
36
|
-
const MIME_TYPE_TEX = "application/x-tex"
|
|
37
|
-
const MIME_TYPE_ZZISH_HTML_MATH = "application/x-zzish-html-math"
|
|
34
|
+
const MIME_TYPE_PLAIN_TEXT = "text/plain";
|
|
35
|
+
const MIME_TYPE_HTML = "text/html";
|
|
36
|
+
const MIME_TYPE_TEX = "application/x-tex";
|
|
37
|
+
const MIME_TYPE_ZZISH_HTML_MATH = "application/x-zzish-html-math";
|
|
38
38
|
|
|
39
|
-
const SMALL_SPACE_CHAR_CODE = 8203
|
|
40
|
-
const SMALL_SPACE = String.fromCharCode(SMALL_SPACE_CHAR_CODE)
|
|
41
|
-
const SMALL_SPACE_LENGTH = SMALL_SPACE.length
|
|
39
|
+
const SMALL_SPACE_CHAR_CODE = 8203;
|
|
40
|
+
const SMALL_SPACE = String.fromCharCode(SMALL_SPACE_CHAR_CODE);
|
|
41
|
+
const SMALL_SPACE_LENGTH = SMALL_SPACE.length;
|
|
42
42
|
// const SMALL_SPACE_REG_EXP = new RegExp(SMALL_SPACE, "g")
|
|
43
43
|
|
|
44
|
-
const MARK = "_M_A_R_K_"
|
|
45
|
-
const MARK_REG_EXP = new RegExp(MARK, "g")
|
|
44
|
+
const MARK = "_M_A_R_K_";
|
|
45
|
+
const MARK_REG_EXP = new RegExp(MARK, "g");
|
|
46
46
|
|
|
47
47
|
// const LATEX_MARKER_START = "<annotation encoding=\"application/x-tex\">"
|
|
48
48
|
// const LATEX_MARKER_END = "</annotation>"
|
|
49
49
|
|
|
50
|
-
const MAX_HISTORY_LENGTH = 100
|
|
50
|
+
const MAX_HISTORY_LENGTH = 100;
|
|
51
51
|
|
|
52
52
|
const DEFAULT_OPTIONS = {
|
|
53
|
-
useExpertMode:false,
|
|
54
|
-
selectedTab: null
|
|
55
|
-
}
|
|
53
|
+
useExpertMode: false,
|
|
54
|
+
selectedTab: null,
|
|
55
|
+
};
|
|
56
56
|
|
|
57
57
|
export default class MathRichInput extends React.Component {
|
|
58
|
-
|
|
59
58
|
constructor(props) {
|
|
60
59
|
super(props);
|
|
61
60
|
this.state = {
|
|
62
61
|
showEquationEditor: false,
|
|
63
62
|
equationEditorLatex: "",
|
|
64
|
-
showAccentBar:false,
|
|
63
|
+
showAccentBar: false,
|
|
65
64
|
activeButtons: {
|
|
66
65
|
bold: false,
|
|
67
66
|
italic: false,
|
|
68
67
|
underline: false,
|
|
69
68
|
subscript: false,
|
|
70
|
-
superscript: false
|
|
69
|
+
superscript: false,
|
|
71
70
|
},
|
|
72
|
-
keyPressed:""
|
|
71
|
+
keyPressed: "",
|
|
73
72
|
};
|
|
74
73
|
|
|
75
74
|
// this.handleInput = this.handleInput.bind(this);
|
|
@@ -77,66 +76,81 @@ export default class MathRichInput extends React.Component {
|
|
|
77
76
|
// this.handleKeyUp = this.handleKeyUp.bind(this);
|
|
78
77
|
|
|
79
78
|
// Remember the last key pressed
|
|
80
|
-
this.keyPressed = null;
|
|
79
|
+
this.keyPressed = null;
|
|
81
80
|
this.keyPressStartTime = -1;
|
|
82
81
|
|
|
83
82
|
// This gets updated in coomponent did mount, used to position the toolbar correctly
|
|
84
|
-
this.translateToolbar = "";
|
|
83
|
+
this.translateToolbar = "";
|
|
85
84
|
|
|
86
85
|
// Whether the text contains HTML or Maths
|
|
87
|
-
this.isHtml = false
|
|
88
|
-
this.hasMath = false
|
|
86
|
+
this.isHtml = false;
|
|
87
|
+
this.hasMath = false;
|
|
89
88
|
|
|
90
89
|
// Elements that need to be set before the equation editor is shown
|
|
91
|
-
this.markedRawText = null
|
|
92
|
-
this.oldRangeParams = {
|
|
93
|
-
|
|
90
|
+
this.markedRawText = null;
|
|
91
|
+
this.oldRangeParams = {
|
|
92
|
+
startNodeIndex: 0,
|
|
93
|
+
startOffset: 0,
|
|
94
|
+
endNodeIndex: 0,
|
|
95
|
+
endOffset: 0,
|
|
96
|
+
};
|
|
97
|
+
this.moveCursorOnInsert = false;
|
|
94
98
|
|
|
95
99
|
// Elements defining the current state of range
|
|
96
|
-
this.rangeParamsToSetAfterComponentUpdate = null // Set this to update the selection after rendering
|
|
97
|
-
this.lastSetRangeParmas = null // This is set automatically each time the range params are set with setRangeParams
|
|
100
|
+
this.rangeParamsToSetAfterComponentUpdate = null; // Set this to update the selection after rendering
|
|
101
|
+
this.lastSetRangeParmas = null; // This is set automatically each time the range params are set with setRangeParams
|
|
98
102
|
|
|
99
|
-
this.lastSetActiveButtons = null
|
|
103
|
+
this.lastSetActiveButtons = null;
|
|
100
104
|
|
|
101
|
-
this.onChangeCallback = this.props.onChange
|
|
105
|
+
this.onChangeCallback = this.props.onChange;
|
|
102
106
|
|
|
103
107
|
// set the initialHistoryState the first time an action is done that allows us to identify the cursor position
|
|
104
108
|
// 1. When the first mouse click is released (see onMouseUp)
|
|
105
109
|
// 2. When the first key is pressed (see handleKeyDown)
|
|
106
|
-
this.initialHistoryState = null
|
|
107
|
-
this.undoHistory = []
|
|
108
|
-
this.redoHistory = []
|
|
110
|
+
this.initialHistoryState = null;
|
|
111
|
+
this.undoHistory = [];
|
|
112
|
+
this.redoHistory = [];
|
|
109
113
|
}
|
|
110
114
|
|
|
111
115
|
enableFontStyling() {
|
|
112
|
-
if (
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
116
|
+
if (
|
|
117
|
+
this.props.outputTex !== null &&
|
|
118
|
+
this.props.outputTex !== undefined &&
|
|
119
|
+
this.props.outputTex === true
|
|
120
|
+
)
|
|
121
|
+
return false;
|
|
122
|
+
else if (
|
|
123
|
+
this.props.enableFontStyling !== null &&
|
|
124
|
+
this.props.enableFontStyling !== undefined
|
|
125
|
+
)
|
|
126
|
+
return this.props.enableFontStyling;
|
|
127
|
+
else return true;
|
|
119
128
|
}
|
|
120
129
|
|
|
121
130
|
enableMultiline() {
|
|
122
|
-
if (
|
|
123
|
-
this.props.outputTex
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
131
|
+
if (
|
|
132
|
+
this.props.outputTex !== null &&
|
|
133
|
+
this.props.outputTex !== undefined &&
|
|
134
|
+
this.props.outputTex === true
|
|
135
|
+
)
|
|
136
|
+
return false;
|
|
137
|
+
else if (
|
|
138
|
+
this.props.enableMultiline !== null &&
|
|
139
|
+
this.props.enableMultiline !== undefined
|
|
140
|
+
)
|
|
141
|
+
return this.props.enableMultiline;
|
|
142
|
+
else return true;
|
|
129
143
|
}
|
|
130
144
|
|
|
131
145
|
enableHtml() {
|
|
132
|
-
let outputTex = this.props.outputTex ?? false
|
|
133
|
-
return !outputTex
|
|
146
|
+
let outputTex = this.props.outputTex ?? false;
|
|
147
|
+
return !outputTex;
|
|
134
148
|
}
|
|
135
149
|
|
|
136
150
|
enableMath() {
|
|
137
151
|
if (this.props.enableMath !== null && this.props.enableMath !== undefined)
|
|
138
|
-
return this.props.enableMath
|
|
139
|
-
return true
|
|
152
|
+
return this.props.enableMath;
|
|
153
|
+
return true;
|
|
140
154
|
}
|
|
141
155
|
|
|
142
156
|
// static isHtml(text) {
|
|
@@ -147,33 +161,34 @@ export default class MathRichInput extends React.Component {
|
|
|
147
161
|
// /<\s*sup[^>]*>(.*?)<\s*\/\s*sup\s*>/i.test(text) ||
|
|
148
162
|
// /<\s*sub[^>]*>(.*?)<\s*\/\s*sub\s*>/i.test(text)
|
|
149
163
|
// }
|
|
150
|
-
|
|
164
|
+
|
|
151
165
|
getMimeType(hasHtml, hasMath) {
|
|
152
|
-
let outputTex = this.props.outputTex ?? false
|
|
153
|
-
let outputPlainText = this.props.outputPlainText ?? false
|
|
154
|
-
|
|
166
|
+
let outputTex = this.props.outputTex ?? false;
|
|
167
|
+
let outputPlainText = this.props.outputPlainText ?? false;
|
|
168
|
+
|
|
155
169
|
if (outputTex) {
|
|
156
|
-
if (hasMath || !outputPlainText)
|
|
157
|
-
|
|
158
|
-
else
|
|
159
|
-
return MIME_TYPE_PLAIN_TEXT
|
|
170
|
+
if (hasMath || !outputPlainText) return MIME_TYPE_TEX;
|
|
171
|
+
else return MIME_TYPE_PLAIN_TEXT;
|
|
160
172
|
}
|
|
161
173
|
|
|
162
|
-
if (hasMath)
|
|
163
|
-
|
|
164
|
-
if (hasHtml || !outputPlainText)
|
|
165
|
-
return MIME_TYPE_HTML
|
|
174
|
+
if (hasMath) return MIME_TYPE_ZZISH_HTML_MATH;
|
|
175
|
+
if (hasHtml || !outputPlainText) return MIME_TYPE_HTML;
|
|
166
176
|
|
|
167
|
-
return MIME_TYPE_PLAIN_TEXT
|
|
177
|
+
return MIME_TYPE_PLAIN_TEXT;
|
|
168
178
|
}
|
|
169
179
|
|
|
170
180
|
_countNodeTypes = () => {
|
|
171
|
-
return countNodeTypes(this.editableDiv)
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
applyChangesToComponent = (
|
|
175
|
-
|
|
176
|
-
|
|
181
|
+
return countNodeTypes(this.editableDiv);
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
applyChangesToComponent = (
|
|
185
|
+
value,
|
|
186
|
+
mimeType,
|
|
187
|
+
rangeParams,
|
|
188
|
+
isExpertMode,
|
|
189
|
+
selectedTab
|
|
190
|
+
) => {
|
|
191
|
+
console.log("applyChangesToComponent");
|
|
177
192
|
|
|
178
193
|
// if (this.props.outputTex !== null && this.props.outputTex !== undefined && this.props.outputTex) {
|
|
179
194
|
// if (mimeType === MIME_TYPE_HTML) {
|
|
@@ -185,163 +200,179 @@ export default class MathRichInput extends React.Component {
|
|
|
185
200
|
// mimeType = MIME_TYPE_TEX
|
|
186
201
|
// }
|
|
187
202
|
// }
|
|
188
|
-
|
|
203
|
+
|
|
189
204
|
// rangeParams, isExpertMode and selectedTab can be null, in which case we will set them
|
|
190
|
-
if (rangeParams === null)
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
isExpertMode = options.isExpertMode
|
|
198
|
-
if (selectedTab === null)
|
|
199
|
-
selectedTab = options.selectedTab
|
|
200
|
-
|
|
205
|
+
if (rangeParams === null) rangeParams = this.lastSetRangeParams;
|
|
206
|
+
else this.rangeParamsToSetAfterComponentUpdate = rangeParams;
|
|
207
|
+
|
|
208
|
+
let options = this.props.options || DEFAULT_OPTIONS;
|
|
209
|
+
if (isExpertMode === null) isExpertMode = options.isExpertMode;
|
|
210
|
+
if (selectedTab === null) selectedTab = options.selectedTab;
|
|
211
|
+
|
|
201
212
|
// Add this to the history
|
|
202
|
-
this.undoHistory.push({value, mimeType, rangeParams})
|
|
203
|
-
if (this.undoHistory.length > MAX_HISTORY_LENGTH)
|
|
204
|
-
this.undoHistory.shift()
|
|
213
|
+
this.undoHistory.push({ value, mimeType, rangeParams });
|
|
214
|
+
if (this.undoHistory.length > MAX_HISTORY_LENGTH) this.undoHistory.shift();
|
|
205
215
|
|
|
206
216
|
// Call the parent handler to apply the changes
|
|
207
|
-
this.onChangeCallback({value, mimeType},
|
|
208
|
-
|
|
209
|
-
}
|
|
217
|
+
this.onChangeCallback({ value, mimeType }, { isExpertMode, selectedTab });
|
|
218
|
+
};
|
|
210
219
|
|
|
211
220
|
initialiseHistory = () => {
|
|
212
221
|
if (this.initialHistoryState == null)
|
|
213
|
-
this.initialHistoryState = {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
222
|
+
this.initialHistoryState = {
|
|
223
|
+
value: this.props.value,
|
|
224
|
+
mimeType: this.props.mimeType,
|
|
225
|
+
rangeParams: this._getRangeParams(),
|
|
226
|
+
};
|
|
227
|
+
};
|
|
217
228
|
|
|
218
229
|
resetHistoryRedo = () => {
|
|
219
|
-
this.redoHistory = []
|
|
220
|
-
}
|
|
230
|
+
this.redoHistory = [];
|
|
231
|
+
};
|
|
221
232
|
|
|
222
233
|
deepEqual = (v1, v2) => {
|
|
223
|
-
if (v1 === v2) return true
|
|
234
|
+
if (v1 === v2) return true;
|
|
235
|
+
|
|
236
|
+
if (
|
|
237
|
+
v1 == null ||
|
|
238
|
+
v2 == null ||
|
|
239
|
+
typeof v1 != "object" ||
|
|
240
|
+
typeof v2 != "object"
|
|
241
|
+
)
|
|
242
|
+
return false;
|
|
224
243
|
|
|
225
|
-
|
|
244
|
+
let v1keys = Object.keys(v1);
|
|
245
|
+
let v2keys = Object.keys(v2);
|
|
246
|
+
if (v1keys.length !== v2keys.length) return false;
|
|
226
247
|
|
|
227
|
-
let v1keys = Object.keys(v1)
|
|
228
|
-
let v2keys = Object.keys(v2)
|
|
229
|
-
if (v1keys.length !== v2keys.length) return false
|
|
230
|
-
|
|
231
248
|
for (let key of v1keys) {
|
|
232
|
-
if (!v2keys.includes(key) || !this.deepEqual(v1[key], v2[key]))
|
|
249
|
+
if (!v2keys.includes(key) || !this.deepEqual(v1[key], v2[key]))
|
|
250
|
+
return false;
|
|
233
251
|
}
|
|
234
|
-
return true
|
|
235
|
-
}
|
|
252
|
+
return true;
|
|
253
|
+
};
|
|
236
254
|
|
|
237
255
|
undo = () => {
|
|
238
|
-
console.log("undo")
|
|
239
|
-
console.log(this.undoHistory)
|
|
240
|
-
const currentState = this.undoHistory.pop()
|
|
241
|
-
|
|
242
|
-
let previousState = this.undoHistory.pop()
|
|
256
|
+
console.log("undo");
|
|
257
|
+
console.log(this.undoHistory);
|
|
258
|
+
const currentState = this.undoHistory.pop();
|
|
259
|
+
|
|
260
|
+
let previousState = this.undoHistory.pop();
|
|
243
261
|
if (previousState === null || previousState === undefined) {
|
|
244
|
-
previousState = this.initialHistoryState
|
|
262
|
+
previousState = this.initialHistoryState;
|
|
245
263
|
}
|
|
246
264
|
|
|
247
265
|
if (this.redoHistory.length > 0) {
|
|
248
|
-
let redoLast = this.redoHistory[this.redoHistory.length-1]
|
|
266
|
+
let redoLast = this.redoHistory[this.redoHistory.length - 1];
|
|
249
267
|
if (!this.deepEqual(redoLast, currentState))
|
|
250
|
-
this.redoHistory.push(currentState)
|
|
251
|
-
} else
|
|
252
|
-
this.redoHistory.push(currentState)
|
|
253
|
-
|
|
254
|
-
console.log(previousState)
|
|
268
|
+
this.redoHistory.push(currentState);
|
|
269
|
+
} else this.redoHistory.push(currentState);
|
|
255
270
|
|
|
256
|
-
|
|
257
|
-
|
|
271
|
+
console.log(previousState);
|
|
272
|
+
|
|
273
|
+
this.applyChangesToComponent(
|
|
274
|
+
previousState.value,
|
|
275
|
+
previousState.mimeType,
|
|
276
|
+
previousState.rangeParams
|
|
277
|
+
);
|
|
278
|
+
};
|
|
258
279
|
|
|
259
280
|
redo = () => {
|
|
260
|
-
const redoState = this.redoHistory.pop()
|
|
261
|
-
if (redoState !== null
|
|
262
|
-
this.applyChangesToComponent(
|
|
281
|
+
const redoState = this.redoHistory.pop();
|
|
282
|
+
if ((redoState !== null) & (redoState !== undefined)) {
|
|
283
|
+
this.applyChangesToComponent(
|
|
284
|
+
redoState.value,
|
|
285
|
+
redoState.mimeType,
|
|
286
|
+
redoState.rangeParams
|
|
287
|
+
);
|
|
263
288
|
}
|
|
264
|
-
}
|
|
289
|
+
};
|
|
265
290
|
|
|
266
291
|
setOldRangeParams(params) {
|
|
267
292
|
// console.log("Setting old range params: "+params.startNodeIndex+"->"+params.startOffset)
|
|
268
|
-
this.oldRangeParams = params
|
|
293
|
+
this.oldRangeParams = params;
|
|
269
294
|
}
|
|
270
295
|
|
|
271
296
|
getOldRangeParams() {
|
|
272
297
|
if (this.oldRangeParams === null || this.oldRangeParams === undefined)
|
|
273
|
-
return null
|
|
274
|
-
let params = {...this.oldRangeParams}
|
|
298
|
+
return null;
|
|
299
|
+
let params = { ...this.oldRangeParams };
|
|
275
300
|
// console.log("Getting old range params: "+params.startNodeIndex+"->"+params.startOffset)
|
|
276
|
-
return params
|
|
301
|
+
return params;
|
|
277
302
|
}
|
|
278
303
|
|
|
279
|
-
_getRangeParams(editableDiv=null) {
|
|
304
|
+
_getRangeParams(editableDiv = null) {
|
|
280
305
|
// console.log("_getRangeParams")
|
|
281
|
-
if (editableDiv === null)
|
|
282
|
-
|
|
283
|
-
let rangeParams = getRangeParams(editableDiv)
|
|
306
|
+
if (editableDiv === null) editableDiv = this.editableDiv;
|
|
307
|
+
let rangeParams = getRangeParams(editableDiv);
|
|
284
308
|
// console.log(rangeParams)
|
|
285
|
-
return rangeParams
|
|
309
|
+
return rangeParams;
|
|
286
310
|
}
|
|
287
311
|
|
|
288
312
|
_setRangeParams = (params) => {
|
|
289
313
|
try {
|
|
290
|
-
console.log("_setRangeParams")
|
|
291
|
-
console.log(params)
|
|
292
|
-
setRangeParams(this.editableDiv, params)
|
|
314
|
+
console.log("_setRangeParams");
|
|
315
|
+
console.log(params);
|
|
316
|
+
setRangeParams(this.editableDiv, params);
|
|
293
317
|
|
|
294
|
-
this.setOldRangeParams(params)
|
|
295
|
-
this.lastSetRangeParmas = params
|
|
318
|
+
this.setOldRangeParams(params);
|
|
319
|
+
this.lastSetRangeParmas = params;
|
|
296
320
|
} catch (error) {
|
|
297
|
-
console.error(error)
|
|
298
|
-
console.log(this.editableDiv.childNodes)
|
|
321
|
+
console.error(error);
|
|
322
|
+
console.log(this.editableDiv.childNodes);
|
|
299
323
|
}
|
|
300
|
-
}
|
|
324
|
+
};
|
|
301
325
|
|
|
302
326
|
_findNodeWithIndex(index) {
|
|
303
|
-
return findNodeWithIndex(this.editableDiv, index)
|
|
327
|
+
return findNodeWithIndex(this.editableDiv, index);
|
|
304
328
|
}
|
|
305
329
|
|
|
306
330
|
_findIndexOfNode(node) {
|
|
307
|
-
return findIndexOfNode(this.editableDiv, node)
|
|
331
|
+
return findIndexOfNode(this.editableDiv, node);
|
|
308
332
|
}
|
|
309
333
|
|
|
310
334
|
_findFirstTextNode() {
|
|
311
|
-
return findFirstTextNode(this.editableDiv)
|
|
335
|
+
return findFirstTextNode(this.editableDiv);
|
|
312
336
|
}
|
|
313
337
|
|
|
314
338
|
handleKeyDownBackspace = (e) => {
|
|
315
|
-
let rangeParams = this._getRangeParams()
|
|
316
|
-
let start_node_index = rangeParams.startNodeIndex
|
|
317
|
-
let end_node_index = rangeParams.endNodeIndex
|
|
318
|
-
let start_offset = rangeParams.startOffset
|
|
319
|
-
let end_offset = rangeParams.endOffset
|
|
320
|
-
|
|
321
|
-
if (start_node_index < 0)
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
let
|
|
326
|
-
|
|
339
|
+
let rangeParams = this._getRangeParams();
|
|
340
|
+
let start_node_index = rangeParams.startNodeIndex;
|
|
341
|
+
let end_node_index = rangeParams.endNodeIndex;
|
|
342
|
+
let start_offset = rangeParams.startOffset;
|
|
343
|
+
let end_offset = rangeParams.endOffset;
|
|
344
|
+
|
|
345
|
+
if (start_node_index < 0)
|
|
346
|
+
// Empty input field
|
|
347
|
+
return;
|
|
348
|
+
|
|
349
|
+
let startNode = this._findNodeWithIndex(start_node_index);
|
|
350
|
+
let endNode = this._findNodeWithIndex(end_node_index);
|
|
351
|
+
|
|
327
352
|
// Prevent backspace if start or end of selected region is in a katex node
|
|
328
353
|
if (isKatexNode(startNode) || isKatexNode(endNode)) {
|
|
329
|
-
console.error("Backspace inside latex node. This shouln't happen.")
|
|
330
|
-
e.preventDefault()
|
|
354
|
+
console.error("Backspace inside latex node. This shouln't happen.");
|
|
355
|
+
e.preventDefault();
|
|
331
356
|
}
|
|
332
357
|
|
|
333
358
|
// Handle special case of deleting last character when in bold etc text
|
|
334
359
|
// in order to resolve a bug
|
|
335
|
-
let deleteToEmpty = false
|
|
336
|
-
if (
|
|
337
|
-
|
|
360
|
+
let deleteToEmpty = false;
|
|
361
|
+
if (
|
|
362
|
+
start_node_index === 0 &&
|
|
363
|
+
start_offset === 1 &&
|
|
364
|
+
end_node_index === 0 &&
|
|
365
|
+
end_offset === 1
|
|
366
|
+
) {
|
|
338
367
|
if (!isKatexNode(startNode) && getNodeTextLength(startNode) === 1)
|
|
339
|
-
deleteToEmpty = true
|
|
368
|
+
deleteToEmpty = true;
|
|
340
369
|
}
|
|
341
370
|
if (start_node_index === 0 && start_offset === 0 && end_node_index !== 0) {
|
|
342
|
-
if (
|
|
343
|
-
|
|
344
|
-
|
|
371
|
+
if (
|
|
372
|
+
getNodeTextLength(endNode) === end_offset &&
|
|
373
|
+
this._findNodeWithIndex(end_node_index + 1) === null
|
|
374
|
+
)
|
|
375
|
+
deleteToEmpty = true;
|
|
345
376
|
}
|
|
346
377
|
|
|
347
378
|
if (deleteToEmpty) {
|
|
@@ -349,32 +380,37 @@ export default class MathRichInput extends React.Component {
|
|
|
349
380
|
startNodeIndex: 0,
|
|
350
381
|
startOffset: 0,
|
|
351
382
|
endNodeIndex: 0,
|
|
352
|
-
endOffset: 0
|
|
353
|
-
}
|
|
354
|
-
this.applyChangesToComponent(
|
|
355
|
-
|
|
356
|
-
|
|
383
|
+
endOffset: 0,
|
|
384
|
+
};
|
|
385
|
+
this.applyChangesToComponent(
|
|
386
|
+
"",
|
|
387
|
+
MIME_TYPE_PLAIN_TEXT,
|
|
388
|
+
new_rangeParams,
|
|
389
|
+
this.props.useExpertMode,
|
|
390
|
+
this.props.selectedTab
|
|
391
|
+
);
|
|
392
|
+
return;
|
|
357
393
|
}
|
|
358
394
|
|
|
359
395
|
// Treat backspace normally in the following situations
|
|
360
|
-
if (start_offset > 1)
|
|
361
|
-
|
|
362
|
-
if (
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
return
|
|
367
|
-
|
|
396
|
+
if (start_offset > 1) return;
|
|
397
|
+
if (start_node_index <= 0) return;
|
|
398
|
+
if (
|
|
399
|
+
start_node_index !== rangeParams.endNodeIndex ||
|
|
400
|
+
start_offset !== rangeParams.endOffset
|
|
401
|
+
)
|
|
402
|
+
return;
|
|
403
|
+
|
|
368
404
|
// At this point we must have start_offset === 0 or 1 and a previous node
|
|
369
405
|
|
|
370
|
-
let prevNode = this._findNodeWithIndex(start_node_index-1)
|
|
406
|
+
let prevNode = this._findNodeWithIndex(start_node_index - 1);
|
|
371
407
|
|
|
372
408
|
if (!isKatexNode(prevNode)) {
|
|
373
409
|
if (this.nodeStartsWithSmallSpace(startNode)) {
|
|
374
|
-
this.removeNewLine()
|
|
375
|
-
e.preventDefault()
|
|
410
|
+
this.removeNewLine();
|
|
411
|
+
e.preventDefault();
|
|
376
412
|
}
|
|
377
|
-
return
|
|
413
|
+
return;
|
|
378
414
|
}
|
|
379
415
|
|
|
380
416
|
// The previous node is a katex node
|
|
@@ -383,994 +419,1120 @@ export default class MathRichInput extends React.Component {
|
|
|
383
419
|
// console.log("Deleting content before: "+start_node_index+"->"+start_offset)
|
|
384
420
|
// console.log(rangeParams)
|
|
385
421
|
|
|
386
|
-
let node = prevNode
|
|
422
|
+
let node = prevNode;
|
|
387
423
|
let new_index = 0;
|
|
388
424
|
let new_offset = 0;
|
|
389
425
|
|
|
390
|
-
// Note that if startNodeIndex == 2, then that means that the latex node is at the start
|
|
426
|
+
// Note that if startNodeIndex == 2, then that means that the latex node is at the start
|
|
391
427
|
// of the whole input at index 1. This is because we insert a SMALL_SPACE
|
|
392
428
|
// at the beginning in index 0, if the whole input starts with a latex node
|
|
393
429
|
if (start_node_index === 2) {
|
|
394
430
|
if (this.inputStartsWithSmallSpace()) {
|
|
395
|
-
new_index = 0
|
|
396
|
-
new_offset = 0
|
|
431
|
+
new_index = 0;
|
|
432
|
+
new_offset = 0;
|
|
397
433
|
} else {
|
|
398
|
-
new_index = 0
|
|
399
|
-
new_offset = getNodeTextLength(this._findFirstTextNode())
|
|
434
|
+
new_index = 0;
|
|
435
|
+
new_offset = getNodeTextLength(this._findFirstTextNode());
|
|
400
436
|
}
|
|
401
437
|
} else {
|
|
402
|
-
new_index = start_node_index - 2
|
|
403
|
-
let new_node = this._findNodeWithIndex(new_index)
|
|
438
|
+
new_index = start_node_index - 2;
|
|
439
|
+
let new_node = this._findNodeWithIndex(new_index);
|
|
404
440
|
if (isKatexNode(new_node)) {
|
|
405
|
-
console.error("Two adjacent latex nodes. This should not happen!")
|
|
406
|
-
new_index = 0
|
|
407
|
-
new_offset = 0
|
|
441
|
+
console.error("Two adjacent latex nodes. This should not happen!");
|
|
442
|
+
new_index = 0;
|
|
443
|
+
new_offset = 0;
|
|
408
444
|
}
|
|
409
|
-
new_node = this._findNodeWithIndex(new_index)
|
|
410
|
-
new_offset = getNodeTextLength(new_node)
|
|
411
|
-
if (new_offset < 0)
|
|
412
|
-
new_offset = 0
|
|
445
|
+
new_node = this._findNodeWithIndex(new_index);
|
|
446
|
+
new_offset = getNodeTextLength(new_node);
|
|
447
|
+
if (new_offset < 0) new_offset = 0;
|
|
413
448
|
}
|
|
414
449
|
|
|
415
450
|
let new_rangeParams = {
|
|
416
451
|
startNodeIndex: new_index,
|
|
417
452
|
startOffset: new_offset,
|
|
418
453
|
endNodeIndex: new_index,
|
|
419
|
-
endOffset: new_offset
|
|
420
|
-
}
|
|
454
|
+
endOffset: new_offset,
|
|
455
|
+
};
|
|
421
456
|
|
|
422
457
|
// OK, time to delete the katex node!
|
|
423
|
-
node.parentNode.removeChild(node)
|
|
424
|
-
let raw_text = elementToMarkedRawText(
|
|
458
|
+
node.parentNode.removeChild(node);
|
|
459
|
+
let raw_text = elementToMarkedRawText(
|
|
460
|
+
this.editableDiv,
|
|
461
|
+
null,
|
|
462
|
+
0,
|
|
463
|
+
this.enableHtml()
|
|
464
|
+
);
|
|
425
465
|
// console.log("After deleting katex: "+raw_text)
|
|
426
466
|
|
|
427
|
-
let nodeCounts = this._countNodeTypes()
|
|
428
|
-
let mimeType = this.getMimeType(nodeCounts.html > 0, nodeCounts.math > 0)
|
|
429
|
-
raw_text = removeEncodingIfPlainText(raw_text, mimeType, this.enableHtml())
|
|
467
|
+
let nodeCounts = this._countNodeTypes();
|
|
468
|
+
let mimeType = this.getMimeType(nodeCounts.html > 0, nodeCounts.math > 0);
|
|
469
|
+
raw_text = removeEncodingIfPlainText(raw_text, mimeType, this.enableHtml());
|
|
470
|
+
|
|
471
|
+
this.applyChangesToComponent(
|
|
472
|
+
raw_text,
|
|
473
|
+
mimeType,
|
|
474
|
+
new_rangeParams,
|
|
475
|
+
this.props.useExpertMode,
|
|
476
|
+
this.props.selectedTab
|
|
477
|
+
);
|
|
430
478
|
|
|
431
|
-
this.applyChangesToComponent(raw_text, mimeType, new_rangeParams,
|
|
432
|
-
this.props.useExpertMode, this.props.selectedTab)
|
|
433
|
-
|
|
434
479
|
// Consume the event
|
|
435
|
-
e.preventDefault()
|
|
436
|
-
}
|
|
480
|
+
e.preventDefault();
|
|
481
|
+
};
|
|
437
482
|
|
|
438
483
|
nodeStartsWithSmallSpace(node) {
|
|
439
|
-
if(
|
|
440
|
-
node.nodeValue
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
484
|
+
if (
|
|
485
|
+
node.nodeValue !== null &&
|
|
486
|
+
node.nodeValue !== undefined &&
|
|
487
|
+
node.nodeValue.length > 0 &&
|
|
488
|
+
node.nodeValue.charAt(0) === SMALL_SPACE
|
|
489
|
+
)
|
|
490
|
+
return true;
|
|
491
|
+
|
|
492
|
+
return false;
|
|
444
493
|
}
|
|
445
494
|
|
|
446
495
|
inputStartsWithSmallSpace = () => {
|
|
447
|
-
return startsWithSmallSpace(this.editableDiv)
|
|
448
|
-
}
|
|
496
|
+
return startsWithSmallSpace(this.editableDiv);
|
|
497
|
+
};
|
|
449
498
|
|
|
450
499
|
handleKeyDownArrowLeft = (e) => {
|
|
451
|
-
let rangeParams = this._getRangeParams()
|
|
452
|
-
let index = rangeParams.startNodeIndex
|
|
453
|
-
let offset = rangeParams.startOffset
|
|
500
|
+
let rangeParams = this._getRangeParams();
|
|
501
|
+
let index = rangeParams.startNodeIndex;
|
|
502
|
+
let offset = rangeParams.startOffset;
|
|
454
503
|
|
|
455
504
|
// console.log("Old: "+index+"->"+offset)
|
|
456
|
-
|
|
505
|
+
|
|
457
506
|
// The user shouldn't be in a katex node, but lets deal with it anyway
|
|
458
|
-
let node = this._findNodeWithIndex(index)
|
|
507
|
+
let node = this._findNodeWithIndex(index);
|
|
459
508
|
if (isKatexNode(node)) {
|
|
460
|
-
console.warn("Cursor is inside katex node")
|
|
461
|
-
let new_index = index-1 // Jump out of the latex node
|
|
462
|
-
let prev_node = this._findNodeWithIndex(index-1)
|
|
463
|
-
let new_offset = getNodeTextLength(prev_node)
|
|
509
|
+
console.warn("Cursor is inside katex node");
|
|
510
|
+
let new_index = index - 1; // Jump out of the latex node
|
|
511
|
+
let prev_node = this._findNodeWithIndex(index - 1);
|
|
512
|
+
let new_offset = getNodeTextLength(prev_node);
|
|
464
513
|
|
|
465
514
|
let new_rangeParams = {
|
|
466
515
|
startNodeIndex: new_index,
|
|
467
516
|
startOffset: new_offset,
|
|
468
517
|
endNodeIndex: new_index,
|
|
469
|
-
endOffset: new_offset
|
|
470
|
-
}
|
|
471
|
-
this._setRangeParams(new_rangeParams)
|
|
472
|
-
e.preventDefault()
|
|
473
|
-
return
|
|
518
|
+
endOffset: new_offset,
|
|
519
|
+
};
|
|
520
|
+
this._setRangeParams(new_rangeParams);
|
|
521
|
+
e.preventDefault();
|
|
522
|
+
return;
|
|
474
523
|
}
|
|
475
524
|
|
|
476
|
-
if (offset > 2)
|
|
477
|
-
return
|
|
525
|
+
if (offset > 2) return;
|
|
478
526
|
|
|
479
|
-
let new_index = -1
|
|
480
|
-
let new_offset = -1
|
|
527
|
+
let new_index = -1;
|
|
528
|
+
let new_offset = -1;
|
|
481
529
|
|
|
482
530
|
// Deal with case of inserted small space at start of <p> element or after katex node
|
|
483
531
|
if (offset === 2) {
|
|
484
|
-
new_index = index
|
|
532
|
+
new_index = index;
|
|
485
533
|
if (this.nodeStartsWithSmallSpace(node)) {
|
|
486
|
-
if (index > 0 && isKatexNode(this._findNodeWithIndex(index-1)))
|
|
487
|
-
new_offset = 1
|
|
488
|
-
else
|
|
489
|
-
|
|
490
|
-
} else
|
|
491
|
-
new_offset = 1
|
|
534
|
+
if (index > 0 && isKatexNode(this._findNodeWithIndex(index - 1)))
|
|
535
|
+
new_offset = 1;
|
|
536
|
+
else new_offset = 0;
|
|
537
|
+
} else new_offset = 1;
|
|
492
538
|
}
|
|
493
|
-
|
|
539
|
+
|
|
494
540
|
if (offset === 1) {
|
|
495
541
|
if (this.nodeStartsWithSmallSpace(node)) {
|
|
496
542
|
if (index === 0) {
|
|
497
|
-
e.preventDefault()
|
|
498
|
-
return
|
|
543
|
+
e.preventDefault();
|
|
544
|
+
return;
|
|
499
545
|
}
|
|
500
|
-
let prev_node = this._findNodeWithIndex(index-1)
|
|
501
|
-
if (index >= 2 && isKatexNode(prev_node))
|
|
502
|
-
|
|
503
|
-
else
|
|
504
|
-
new_index = index - 1
|
|
546
|
+
let prev_node = this._findNodeWithIndex(index - 1);
|
|
547
|
+
if (index >= 2 && isKatexNode(prev_node)) new_index = index - 2;
|
|
548
|
+
else new_index = index - 1;
|
|
505
549
|
|
|
506
|
-
let new_node = this._findNodeWithIndex(new_index)
|
|
507
|
-
new_offset = getNodeTextLength(new_node)
|
|
550
|
+
let new_node = this._findNodeWithIndex(new_index);
|
|
551
|
+
new_offset = getNodeTextLength(new_node);
|
|
508
552
|
} else {
|
|
509
|
-
new_index = index
|
|
510
|
-
new_offset = 0
|
|
553
|
+
new_index = index;
|
|
554
|
+
new_offset = 0;
|
|
511
555
|
}
|
|
512
556
|
}
|
|
513
557
|
|
|
514
558
|
if (offset === 0) {
|
|
515
|
-
let prev_node = this._findNodeWithIndex(index-1)
|
|
516
|
-
if (index >= 2 && isKatexNode(prev_node))
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
let new_node = this._findNodeWithIndex(new_index)
|
|
521
|
-
new_offset = getNodeTextLength(new_node)
|
|
559
|
+
let prev_node = this._findNodeWithIndex(index - 1);
|
|
560
|
+
if (index >= 2 && isKatexNode(prev_node)) new_index = index - 2;
|
|
561
|
+
else new_index = index - 1;
|
|
562
|
+
let new_node = this._findNodeWithIndex(new_index);
|
|
563
|
+
new_offset = getNodeTextLength(new_node);
|
|
522
564
|
if (new_offset === 1) {
|
|
523
565
|
if (this.nodeStartsWithSmallSpace(new_node)) {
|
|
524
|
-
if (index > 0 && isKatexNode(this._findNodeWithIndex(index-1)))
|
|
525
|
-
new_offset = 1
|
|
526
|
-
else
|
|
527
|
-
new_offset = 0
|
|
566
|
+
if (index > 0 && isKatexNode(this._findNodeWithIndex(index - 1)))
|
|
567
|
+
new_offset = 1;
|
|
568
|
+
else new_offset = 0;
|
|
528
569
|
}
|
|
529
570
|
}
|
|
530
571
|
}
|
|
531
572
|
|
|
532
|
-
|
|
533
573
|
// Move cursor to start of field if in starting small space
|
|
534
|
-
if (
|
|
535
|
-
|
|
574
|
+
if (
|
|
575
|
+
new_index === 0 &&
|
|
576
|
+
new_offset === 1 &&
|
|
577
|
+
this.inputStartsWithSmallSpace()
|
|
578
|
+
) {
|
|
579
|
+
new_offset = 0;
|
|
536
580
|
}
|
|
537
581
|
|
|
538
|
-
if (new_index === -1 || new_offset === -1)
|
|
539
|
-
return
|
|
582
|
+
if (new_index === -1 || new_offset === -1) return;
|
|
540
583
|
|
|
541
584
|
let new_rangeParams = {
|
|
542
585
|
startNodeIndex: new_index,
|
|
543
586
|
startOffset: new_offset,
|
|
544
587
|
endNodeIndex: new_index,
|
|
545
|
-
endOffset: new_offset
|
|
546
|
-
}
|
|
547
|
-
this._setRangeParams(new_rangeParams)
|
|
588
|
+
endOffset: new_offset,
|
|
589
|
+
};
|
|
590
|
+
this._setRangeParams(new_rangeParams);
|
|
548
591
|
|
|
549
|
-
e.preventDefault()
|
|
550
|
-
}
|
|
592
|
+
e.preventDefault();
|
|
593
|
+
};
|
|
551
594
|
|
|
552
595
|
handleKeyDownArrowRight = (e) => {
|
|
553
596
|
// console.log("handleKeyDownArrowRight")
|
|
554
|
-
let rangeParams = this._getRangeParams()
|
|
555
|
-
let index = rangeParams.startNodeIndex
|
|
556
|
-
let offset = rangeParams.startOffset
|
|
597
|
+
let rangeParams = this._getRangeParams();
|
|
598
|
+
let index = rangeParams.startNodeIndex;
|
|
599
|
+
let offset = rangeParams.startOffset;
|
|
557
600
|
|
|
558
|
-
if (index < 0)
|
|
559
|
-
|
|
601
|
+
if (index < 0)
|
|
602
|
+
// Empty input field
|
|
603
|
+
return;
|
|
560
604
|
|
|
561
|
-
let node = this._findNodeWithIndex(index)
|
|
562
|
-
let length = getNodeTextLength(node)
|
|
605
|
+
let node = this._findNodeWithIndex(index);
|
|
606
|
+
let length = getNodeTextLength(node);
|
|
563
607
|
|
|
564
608
|
// The user shouldn't be in a katex node, but lets deal with it anyway
|
|
565
609
|
if (isKatexNode(node)) {
|
|
566
|
-
console.warn("Cursor is inside katex node")
|
|
567
|
-
let new_index = index+1 // Jump out of the latex node
|
|
568
|
-
let new_offset = SMALL_SPACE_LENGTH // As there will be a SMALL_SPACE at the start of the text node
|
|
610
|
+
console.warn("Cursor is inside katex node");
|
|
611
|
+
let new_index = index + 1; // Jump out of the latex node
|
|
612
|
+
let new_offset = SMALL_SPACE_LENGTH; // As there will be a SMALL_SPACE at the start of the text node
|
|
569
613
|
|
|
570
614
|
let new_rangeParams = {
|
|
571
615
|
startNodeIndex: new_index,
|
|
572
616
|
startOffset: new_offset,
|
|
573
617
|
endNodeIndex: new_index,
|
|
574
|
-
endOffset: new_offset
|
|
575
|
-
}
|
|
576
|
-
this._setRangeParams(new_rangeParams)
|
|
577
|
-
e.preventDefault()
|
|
578
|
-
return
|
|
618
|
+
endOffset: new_offset,
|
|
619
|
+
};
|
|
620
|
+
this._setRangeParams(new_rangeParams);
|
|
621
|
+
e.preventDefault();
|
|
622
|
+
return;
|
|
579
623
|
}
|
|
580
624
|
|
|
581
625
|
// Deal with case of inserted small space at start of <p> element
|
|
582
626
|
if (offset === 0) {
|
|
583
627
|
if (this.nodeStartsWithSmallSpace(node)) {
|
|
584
|
-
console.log("Offset = 0 and node starts with small space")
|
|
585
|
-
let new_index = -1
|
|
586
|
-
let new_offset = -1
|
|
587
|
-
|
|
628
|
+
console.log("Offset = 0 and node starts with small space");
|
|
629
|
+
let new_index = -1;
|
|
630
|
+
let new_offset = -1;
|
|
631
|
+
|
|
588
632
|
if (node.nodeValue.length > 1) {
|
|
589
|
-
new_index = index
|
|
590
|
-
new_offset = SMALL_SPACE_LENGTH + 1
|
|
633
|
+
new_index = index;
|
|
634
|
+
new_offset = SMALL_SPACE_LENGTH + 1;
|
|
591
635
|
} else {
|
|
592
|
-
new_index = index + 1
|
|
593
|
-
let next_node = this._findNodeWithIndex(new_index)
|
|
636
|
+
new_index = index + 1;
|
|
637
|
+
let next_node = this._findNodeWithIndex(new_index);
|
|
594
638
|
if (next_node !== null) {
|
|
595
639
|
if (isKatexNode(next_node)) {
|
|
596
|
-
new_index = index + 2
|
|
597
|
-
new_offset = SMALL_SPACE_LENGTH
|
|
640
|
+
new_index = index + 2;
|
|
641
|
+
new_offset = SMALL_SPACE_LENGTH;
|
|
598
642
|
} else {
|
|
599
|
-
new_index = index + 1
|
|
600
|
-
new_offset = 0
|
|
643
|
+
new_index = index + 1;
|
|
644
|
+
new_offset = 0;
|
|
601
645
|
}
|
|
602
646
|
} else {
|
|
603
|
-
new_index = index
|
|
604
|
-
new_offset = offset
|
|
605
|
-
}
|
|
647
|
+
new_index = index;
|
|
648
|
+
new_offset = offset;
|
|
649
|
+
}
|
|
606
650
|
}
|
|
607
651
|
let new_rangeParams = {
|
|
608
652
|
startNodeIndex: new_index,
|
|
609
653
|
startOffset: new_offset,
|
|
610
654
|
endNodeIndex: new_index,
|
|
611
|
-
endOffset: new_offset
|
|
612
|
-
}
|
|
613
|
-
console.log(new_rangeParams)
|
|
614
|
-
this._setRangeParams(new_rangeParams)
|
|
615
|
-
|
|
616
|
-
e.preventDefault()
|
|
617
|
-
return
|
|
655
|
+
endOffset: new_offset,
|
|
656
|
+
};
|
|
657
|
+
console.log(new_rangeParams);
|
|
658
|
+
this._setRangeParams(new_rangeParams);
|
|
659
|
+
|
|
660
|
+
e.preventDefault();
|
|
661
|
+
return;
|
|
618
662
|
}
|
|
619
663
|
}
|
|
620
664
|
|
|
621
|
-
|
|
622
665
|
// If at the end of a text node
|
|
623
|
-
if (
|
|
624
|
-
|
|
666
|
+
if (
|
|
667
|
+
offset === length ||
|
|
668
|
+
(index === 0 && this.inputStartsWithSmallSpace())
|
|
669
|
+
) {
|
|
670
|
+
let next_node = this._findNodeWithIndex(index + 1);
|
|
625
671
|
|
|
626
672
|
// If there is no next node, then we can't move, so do the default action
|
|
627
673
|
// If the next node is a normal node, do the default action
|
|
628
|
-
if (next_node === null || !isKatexNode(next_node))
|
|
629
|
-
return
|
|
674
|
+
if (next_node === null || !isKatexNode(next_node)) return;
|
|
630
675
|
|
|
631
|
-
let new_index = index+2 // Jump over the latex node
|
|
632
|
-
let new_offset = SMALL_SPACE_LENGTH // As there will be a SMALL_SPACE at the start of the text node
|
|
676
|
+
let new_index = index + 2; // Jump over the latex node
|
|
677
|
+
let new_offset = SMALL_SPACE_LENGTH; // As there will be a SMALL_SPACE at the start of the text node
|
|
633
678
|
|
|
634
679
|
let new_rangeParams = {
|
|
635
680
|
startNodeIndex: new_index,
|
|
636
681
|
startOffset: new_offset,
|
|
637
682
|
endNodeIndex: new_index,
|
|
638
|
-
endOffset: new_offset
|
|
639
|
-
}
|
|
640
|
-
this._setRangeParams(new_rangeParams)
|
|
683
|
+
endOffset: new_offset,
|
|
684
|
+
};
|
|
685
|
+
this._setRangeParams(new_rangeParams);
|
|
641
686
|
|
|
642
|
-
e.preventDefault()
|
|
643
|
-
return
|
|
687
|
+
e.preventDefault();
|
|
688
|
+
return;
|
|
644
689
|
}
|
|
645
|
-
}
|
|
690
|
+
};
|
|
646
691
|
|
|
647
692
|
editableDivIsPlainText = () => {
|
|
648
|
-
return
|
|
649
|
-
|
|
693
|
+
return (
|
|
694
|
+
this.editableDiv.childNodes === null ||
|
|
695
|
+
this.editableDiv.childNodes.length === 0
|
|
696
|
+
);
|
|
697
|
+
};
|
|
650
698
|
|
|
651
699
|
handleKeyDownDollar = (e) => {
|
|
652
|
-
|
|
653
700
|
// This method automatically converts text between a pair of typed dollars into
|
|
654
701
|
// a latex math component. It only does this when the second dollar is preceded by certain
|
|
655
702
|
// characters and NOT when the second dollar is preceded by a space.
|
|
656
|
-
//
|
|
657
|
-
// This is because when the user actually wants actual dollar symbols for ammounts
|
|
703
|
+
//
|
|
704
|
+
// This is because when the user actually wants actual dollar symbols for ammounts
|
|
658
705
|
// the dollar symbol will usually be preceded by a space, eg:
|
|
659
706
|
//
|
|
660
|
-
// "The pie was $3.50 and the cheese was $1.30"
|
|
707
|
+
// "The pie was $3.50 and the cheese was $1.30"
|
|
661
708
|
//
|
|
662
709
|
// will not be converted as the $1.30 is preceded by a space.
|
|
663
710
|
//
|
|
664
711
|
try {
|
|
665
|
-
let params = this._getRangeParams()
|
|
666
|
-
let node = this._findNodeWithIndex(params.startNodeIndex)
|
|
667
|
-
if (node.nodeType !== 3)
|
|
668
|
-
|
|
669
|
-
|
|
712
|
+
let params = this._getRangeParams();
|
|
713
|
+
let node = this._findNodeWithIndex(params.startNodeIndex);
|
|
714
|
+
if (node.nodeType !== 3)
|
|
715
|
+
// text node
|
|
716
|
+
return;
|
|
717
|
+
let text = node.nodeValue;
|
|
670
718
|
// Look for starting dollar to match this new second dollar
|
|
671
|
-
let first_dollar_pos = text.indexOf("$")
|
|
672
|
-
if (first_dollar_pos < 0)
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
let
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
719
|
+
let first_dollar_pos = text.indexOf("$");
|
|
720
|
+
if (first_dollar_pos < 0) return;
|
|
721
|
+
if (first_dollar_pos >= params.startOffset) return;
|
|
722
|
+
let second_dollar_pos = params.startOffset;
|
|
723
|
+
|
|
724
|
+
let c = text.charAt(second_dollar_pos - 1);
|
|
725
|
+
let convert_to_latex = false;
|
|
726
|
+
if (
|
|
727
|
+
(c >= "a" && c <= "z") ||
|
|
728
|
+
(c >= "A" && c <= "Z") ||
|
|
729
|
+
(c >= "0" && c <= "9") ||
|
|
730
|
+
c === ")" ||
|
|
731
|
+
c === "}"
|
|
732
|
+
) {
|
|
733
|
+
convert_to_latex = true;
|
|
685
734
|
}
|
|
686
|
-
if (!convert_to_latex)
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
node.nodeValue.substring(first_dollar_pos+1, second_dollar_pos) +
|
|
692
|
-
|
|
735
|
+
if (!convert_to_latex) return;
|
|
736
|
+
|
|
737
|
+
node.nodeValue =
|
|
738
|
+
node.nodeValue.substring(0, first_dollar_pos) +
|
|
739
|
+
MARK +
|
|
740
|
+
node.nodeValue.substring(first_dollar_pos + 1, second_dollar_pos) +
|
|
741
|
+
MARK +
|
|
742
|
+
node.nodeValue.substring(second_dollar_pos);
|
|
743
|
+
|
|
744
|
+
let raw_text = elementToMarkedRawText(
|
|
745
|
+
e.target,
|
|
746
|
+
null,
|
|
747
|
+
0,
|
|
748
|
+
this.enableHtml()
|
|
749
|
+
);
|
|
750
|
+
raw_text = raw_text.replace(MARK_REG_EXP, "$");
|
|
693
751
|
|
|
694
|
-
let raw_text = elementToMarkedRawText(e.target, null, 0, this.enableHtml())
|
|
695
|
-
raw_text = raw_text.replace(MARK_REG_EXP,"$")
|
|
696
|
-
|
|
697
752
|
// We are turning one node into three and want the cursor at the start of the third node
|
|
698
753
|
let new_rangeParams = {
|
|
699
754
|
startNodeIndex: params.startNodeIndex + 2,
|
|
700
755
|
startOffset: SMALL_SPACE_LENGTH,
|
|
701
756
|
endNodeIndex: params.startNodeIndex + 2,
|
|
702
|
-
endOffset: SMALL_SPACE_LENGTH
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
let nodeCounts = this._countNodeTypes()
|
|
706
|
-
let mimeType = this.getMimeType(nodeCounts.html > 0, true)
|
|
707
|
-
raw_text = removeEncodingIfPlainText(
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
757
|
+
endOffset: SMALL_SPACE_LENGTH,
|
|
758
|
+
};
|
|
759
|
+
|
|
760
|
+
let nodeCounts = this._countNodeTypes();
|
|
761
|
+
let mimeType = this.getMimeType(nodeCounts.html > 0, true);
|
|
762
|
+
raw_text = removeEncodingIfPlainText(
|
|
763
|
+
raw_text,
|
|
764
|
+
mimeType,
|
|
765
|
+
this.enableHtml()
|
|
766
|
+
);
|
|
767
|
+
|
|
768
|
+
this.applyChangesToComponent(
|
|
769
|
+
raw_text,
|
|
770
|
+
mimeType,
|
|
771
|
+
new_rangeParams,
|
|
772
|
+
this.props.useExpertMode,
|
|
773
|
+
this.props.selectedTab
|
|
774
|
+
);
|
|
714
775
|
} catch (error) {
|
|
715
|
-
console.error(error)
|
|
776
|
+
console.error(error);
|
|
716
777
|
}
|
|
717
778
|
|
|
718
|
-
e.preventDefault()
|
|
719
|
-
}
|
|
779
|
+
e.preventDefault();
|
|
780
|
+
};
|
|
720
781
|
|
|
721
782
|
showEquationEditorOnKeyDown = (e) => {
|
|
722
|
-
this.showEquationEditor(true)
|
|
723
|
-
e.preventDefault()
|
|
724
|
-
}
|
|
783
|
+
this.showEquationEditor(true);
|
|
784
|
+
e.preventDefault();
|
|
785
|
+
};
|
|
725
786
|
|
|
726
787
|
handleKeyDownEnter = (e) => {
|
|
727
788
|
try {
|
|
728
|
-
console.log("handleKeyDownEnter")
|
|
729
|
-
if (this.enableMultiline())
|
|
730
|
-
this.insertNewLine(e)
|
|
789
|
+
console.log("handleKeyDownEnter");
|
|
790
|
+
if (this.enableMultiline()) this.insertNewLine(e);
|
|
731
791
|
} catch (error) {
|
|
732
|
-
console.error(error)
|
|
792
|
+
console.error(error);
|
|
733
793
|
}
|
|
734
|
-
e.preventDefault()
|
|
735
|
-
}
|
|
794
|
+
e.preventDefault();
|
|
795
|
+
};
|
|
736
796
|
|
|
737
797
|
handleKeyDown = (e) => {
|
|
738
798
|
try {
|
|
739
799
|
// Lets set up or update the undo redo history
|
|
740
|
-
this.initialiseHistory()
|
|
800
|
+
this.initialiseHistory();
|
|
741
801
|
|
|
742
802
|
if ((e.key === "z" || e.key === "Z") && (e.ctrlKey || e.metaKey)) {
|
|
743
|
-
if (e.shiftKey)
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
e.preventDefault()
|
|
748
|
-
return
|
|
803
|
+
if (e.shiftKey) this.redo();
|
|
804
|
+
else this.undo();
|
|
805
|
+
e.preventDefault();
|
|
806
|
+
return;
|
|
749
807
|
}
|
|
750
|
-
|
|
751
|
-
if (!(e.ctrlKey || e.metaKey))
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
808
|
+
|
|
809
|
+
if (!(e.ctrlKey || e.metaKey)) this.resetHistoryRedo();
|
|
810
|
+
|
|
811
|
+
if (
|
|
812
|
+
(e.metaKey || e.ctrlKey) &&
|
|
813
|
+
(e.key === "b" ||
|
|
814
|
+
e.key === "i" ||
|
|
815
|
+
e.key === "u" ||
|
|
816
|
+
e.key === "6" ||
|
|
817
|
+
e.key === "^" ||
|
|
818
|
+
e.key === "-" ||
|
|
819
|
+
e.key === "_")
|
|
820
|
+
) {
|
|
758
821
|
if (!this.enableHtml()) {
|
|
759
|
-
e.preventDefault()
|
|
760
|
-
return
|
|
822
|
+
e.preventDefault();
|
|
823
|
+
return;
|
|
761
824
|
}
|
|
762
|
-
if (e.key === "b")
|
|
763
|
-
|
|
764
|
-
if (e.key === "
|
|
765
|
-
|
|
766
|
-
if (e.key === "u")
|
|
767
|
-
this.styleText(e, "Underline")
|
|
768
|
-
if (e.key === "6" || e.key === "^")
|
|
769
|
-
this.styleText(e, "Superscript")
|
|
825
|
+
if (e.key === "b") this.styleText(e, "Bold");
|
|
826
|
+
if (e.key === "i") this.styleText(e, "Italic");
|
|
827
|
+
if (e.key === "u") this.styleText(e, "Underline");
|
|
828
|
+
if (e.key === "6" || e.key === "^") this.styleText(e, "Superscript");
|
|
770
829
|
|
|
771
830
|
// don't apply subscript if it is the browser command key for "smaller"
|
|
772
|
-
if (
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
831
|
+
if (
|
|
832
|
+
/(Win)/i.test(window.navigator.platform) &&
|
|
833
|
+
e.ctrlKey &&
|
|
834
|
+
e.key === "-"
|
|
835
|
+
)
|
|
836
|
+
return;
|
|
837
|
+
if (
|
|
838
|
+
/(Mac)/i.test(window.navigator.platform) &&
|
|
839
|
+
e.metaKey &&
|
|
840
|
+
e.key === "-"
|
|
841
|
+
)
|
|
842
|
+
return;
|
|
776
843
|
// otherwise
|
|
777
|
-
if (e.key === "-" || e.key === "_")
|
|
778
|
-
this.styleText(e, "Subscript")
|
|
844
|
+
if (e.key === "-" || e.key === "_") this.styleText(e, "Subscript");
|
|
779
845
|
|
|
780
|
-
e.preventDefault()
|
|
781
|
-
return
|
|
846
|
+
e.preventDefault();
|
|
847
|
+
return;
|
|
782
848
|
}
|
|
783
849
|
|
|
784
|
-
|
|
785
850
|
// Ignore automatic key repeat presses on Windows so that we can show an accent bar on
|
|
786
851
|
// long key press
|
|
787
852
|
if (!/(Win)/i.test(window.navigator.platform)) {
|
|
788
853
|
if (e.key === this.keyPressed && this.keyPressStartTime > 0) {
|
|
789
|
-
if (
|
|
790
|
-
|
|
791
|
-
|
|
854
|
+
if (
|
|
855
|
+
e.key.length === 1 &&
|
|
856
|
+
(("a" <= e.key && e.key <= "z") ||
|
|
857
|
+
("A" <= e.key && e.key <= "Z") ||
|
|
792
858
|
e.key === "!" ||
|
|
793
|
-
e.key === "?")
|
|
794
|
-
|
|
795
|
-
|
|
859
|
+
e.key === "?")
|
|
860
|
+
) {
|
|
861
|
+
e.preventDefault();
|
|
862
|
+
return;
|
|
796
863
|
}
|
|
797
864
|
}
|
|
798
865
|
}
|
|
799
866
|
|
|
800
867
|
if (e.altKey && e.key === "Alt") {
|
|
801
|
-
let key = this.fetchAccentLetter()
|
|
802
|
-
if (
|
|
803
|
-
|
|
804
|
-
|
|
868
|
+
let key = this.fetchAccentLetter();
|
|
869
|
+
if (
|
|
870
|
+
key === "a" ||
|
|
871
|
+
key === "e" ||
|
|
872
|
+
key === "i" ||
|
|
873
|
+
key === "o" ||
|
|
874
|
+
key === "u" ||
|
|
875
|
+
key === "c" ||
|
|
876
|
+
key === "l" ||
|
|
877
|
+
key === "n" ||
|
|
878
|
+
key === "s" ||
|
|
879
|
+
key === "?" ||
|
|
880
|
+
key === "!"
|
|
881
|
+
) {
|
|
882
|
+
this.setState({ showAccentBar: !this.state.showAccentBar });
|
|
805
883
|
} else {
|
|
806
|
-
this.setState({showAccentBar:false})
|
|
884
|
+
this.setState({ showAccentBar: false });
|
|
807
885
|
}
|
|
808
|
-
return
|
|
886
|
+
return;
|
|
809
887
|
}
|
|
810
888
|
|
|
811
|
-
this.keyPressed = e.key // store for use in methods
|
|
812
|
-
this.setState({keyPressed:e.key})
|
|
889
|
+
this.keyPressed = e.key; // store for use in methods
|
|
890
|
+
this.setState({ keyPressed: e.key });
|
|
813
891
|
|
|
814
892
|
// Hide the accent bar if a key is typed except when it is an automatic key repeat press
|
|
815
|
-
// If it is automatic key repeat, then keyPressStartTime will be greater than 0
|
|
893
|
+
// If it is automatic key repeat, then keyPressStartTime will be greater than 0
|
|
816
894
|
// (keyPressStartTime is reset to -1 on key up)
|
|
817
|
-
if (this.keyPressStartTime < 0) {
|
|
818
|
-
this.keyPressStartTime = Date.now()
|
|
819
|
-
if (this.state.showAccentBar)
|
|
820
|
-
this.setState({showAccentBar:false})
|
|
895
|
+
if (this.keyPressStartTime < 0) {
|
|
896
|
+
this.keyPressStartTime = Date.now();
|
|
897
|
+
if (this.state.showAccentBar) this.setState({ showAccentBar: false });
|
|
821
898
|
}
|
|
822
899
|
|
|
823
900
|
if (e.key === "Backspace") {
|
|
824
|
-
this.handleKeyDownBackspace(e)
|
|
825
|
-
return
|
|
901
|
+
this.handleKeyDownBackspace(e);
|
|
902
|
+
return;
|
|
826
903
|
}
|
|
827
904
|
if (e.key === "ArrowLeft") {
|
|
828
|
-
this.handleKeyDownArrowLeft(e)
|
|
829
|
-
return
|
|
905
|
+
this.handleKeyDownArrowLeft(e);
|
|
906
|
+
return;
|
|
830
907
|
}
|
|
831
908
|
if (e.key === "ArrowRight") {
|
|
832
|
-
this.handleKeyDownArrowRight(e)
|
|
833
|
-
return
|
|
909
|
+
this.handleKeyDownArrowRight(e);
|
|
910
|
+
return;
|
|
834
911
|
}
|
|
835
912
|
if (e.key === "$") {
|
|
836
|
-
this.handleKeyDownDollar(e)
|
|
837
|
-
return
|
|
913
|
+
this.handleKeyDownDollar(e);
|
|
914
|
+
return;
|
|
838
915
|
}
|
|
839
916
|
|
|
840
917
|
// Implement special command + keys
|
|
841
918
|
if ((e.ctrlKey || e.metaKey) && e.key === "Enter") {
|
|
842
|
-
this.showEquationEditorOnKeyDown(e)
|
|
843
|
-
return
|
|
919
|
+
this.showEquationEditorOnKeyDown(e);
|
|
920
|
+
return;
|
|
844
921
|
} else if (/(Mac)/i.test(window.navigator.platform)) {
|
|
845
|
-
if (e.ctrlKey && e.key === "=") {
|
|
846
|
-
|
|
847
|
-
|
|
922
|
+
if (e.ctrlKey && e.key === "=") {
|
|
923
|
+
// CTRL+= inserts equation in Word on Mac
|
|
924
|
+
this.showEquationEditorOnKeyDown(e);
|
|
925
|
+
return;
|
|
848
926
|
}
|
|
849
927
|
} else if (/(Win)/i.test(window.navigator.platform)) {
|
|
850
|
-
if (e.altKey && e.key === "=") {
|
|
851
|
-
|
|
852
|
-
|
|
928
|
+
if (e.altKey && e.key === "=") {
|
|
929
|
+
// ALT+= inserts equation in Word on PC
|
|
930
|
+
this.showEquationEditorOnKeyDown(e);
|
|
931
|
+
return;
|
|
853
932
|
}
|
|
854
933
|
}
|
|
855
|
-
|
|
934
|
+
|
|
856
935
|
// Lets handle the enter key (new line) ourselves
|
|
857
936
|
if (e.key === "Enter") {
|
|
858
|
-
this.handleKeyDownEnter(e)
|
|
859
|
-
return
|
|
937
|
+
this.handleKeyDownEnter(e);
|
|
938
|
+
return;
|
|
860
939
|
}
|
|
861
940
|
|
|
862
941
|
// Show the accent bar on long key presses
|
|
863
942
|
if (/(Win)/i.test(window.navigator.platform)) {
|
|
864
|
-
let key= e.key.toLowerCase()
|
|
865
|
-
if (
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
943
|
+
let key = e.key.toLowerCase();
|
|
944
|
+
if (
|
|
945
|
+
key === "a" ||
|
|
946
|
+
key === "e" ||
|
|
947
|
+
key === "i" ||
|
|
948
|
+
key === "o" ||
|
|
949
|
+
key === "u" ||
|
|
950
|
+
key === "c" ||
|
|
951
|
+
key === "l" ||
|
|
952
|
+
key === "n" ||
|
|
953
|
+
key === "s" ||
|
|
954
|
+
key === "?" ||
|
|
955
|
+
key === "!"
|
|
956
|
+
) {
|
|
957
|
+
let _this = this;
|
|
958
|
+
setTimeout(function () {
|
|
959
|
+
console.log(Date.now() - _this.keyPressStartTime);
|
|
870
960
|
if (_this.keyPressStartTime > 0)
|
|
871
961
|
if (Date.now() - _this.keyPressStartTime > 450)
|
|
872
|
-
_this.setState({showAccentBar:true})
|
|
962
|
+
_this.setState({ showAccentBar: true });
|
|
873
963
|
}, 500);
|
|
874
964
|
}
|
|
875
965
|
}
|
|
876
|
-
|
|
966
|
+
|
|
877
967
|
// Stop editing if within rendered katex node, if somehow the cursor ends up there (it shouldn't)
|
|
878
|
-
let params = this._getRangeParams()
|
|
879
|
-
let startNode = this._findNodeWithIndex(params.startNodeIndex)
|
|
880
|
-
let endNode = this._findNodeWithIndex(params.endNodeIndex)
|
|
968
|
+
let params = this._getRangeParams();
|
|
969
|
+
let startNode = this._findNodeWithIndex(params.startNodeIndex);
|
|
970
|
+
let endNode = this._findNodeWithIndex(params.endNodeIndex);
|
|
881
971
|
if (!this.editableDivIsPlainText()) {
|
|
882
972
|
// console.log(params)
|
|
883
973
|
if (params.startNodeIndex === -1) {
|
|
884
|
-
console.error("Couldn't get range params")
|
|
885
|
-
return
|
|
974
|
+
console.error("Couldn't get range params");
|
|
975
|
+
return;
|
|
886
976
|
}
|
|
887
977
|
// console.log("Start node: "+startNode)
|
|
888
978
|
// console.log("End node: "+endNode)
|
|
889
|
-
|
|
979
|
+
|
|
890
980
|
if (isKatexNode(startNode) || isKatexNode(endNode)) {
|
|
891
|
-
console.error("User trying to edit inside latex node")
|
|
892
|
-
e.preventDefault()
|
|
893
|
-
return
|
|
981
|
+
console.error("User trying to edit inside latex node");
|
|
982
|
+
e.preventDefault();
|
|
983
|
+
return;
|
|
894
984
|
}
|
|
895
|
-
}
|
|
985
|
+
}
|
|
896
986
|
|
|
897
987
|
// Check if inserting character in element that starts with small space
|
|
898
|
-
if (
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
988
|
+
if (
|
|
989
|
+
e.key.length === 1 &&
|
|
990
|
+
params.startOffset === 0 &&
|
|
991
|
+
this.nodeStartsWithSmallSpace(startNode)
|
|
992
|
+
) {
|
|
993
|
+
this.replaceNextLetter(e.key);
|
|
994
|
+
e.preventDefault();
|
|
995
|
+
return;
|
|
902
996
|
}
|
|
903
|
-
|
|
904
997
|
} catch (error) {
|
|
905
|
-
console.error(error)
|
|
906
|
-
console.log(
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
998
|
+
console.error(error);
|
|
999
|
+
console.log(
|
|
1000
|
+
"Key pressed: " +
|
|
1001
|
+
(e.metaKey ? "META+" : "") +
|
|
1002
|
+
(e.ctrlKey ? "CTRL+" : "") +
|
|
1003
|
+
(e.altKey ? "ALT+" : "") +
|
|
1004
|
+
(e.shiftKey ? "SHIFT+" : "") +
|
|
1005
|
+
e.key
|
|
1006
|
+
);
|
|
913
1007
|
}
|
|
914
|
-
}
|
|
1008
|
+
};
|
|
915
1009
|
|
|
916
1010
|
handleKeyUp = (e) => {
|
|
917
1011
|
try {
|
|
918
|
-
this.keyPressed = e.key
|
|
919
|
-
this.keyPressStartTime = -1
|
|
1012
|
+
this.keyPressed = e.key;
|
|
1013
|
+
this.keyPressStartTime = -1;
|
|
920
1014
|
|
|
921
1015
|
// If the cursor is in a katex node, then move it to the next node (unless there is no
|
|
922
1016
|
// net node in which case move it to the previous node)
|
|
923
1017
|
if (e.key === "ArrowRight") {
|
|
924
|
-
let rangeParams = this._getRangeParams()
|
|
925
|
-
let index = rangeParams.startNodeIndex
|
|
1018
|
+
let rangeParams = this._getRangeParams();
|
|
1019
|
+
let index = rangeParams.startNodeIndex;
|
|
926
1020
|
|
|
927
1021
|
if (index >= 0) {
|
|
928
1022
|
if (isKatexNode(this._findNodeWithIndex(index))) {
|
|
929
|
-
let new_index = 0
|
|
930
|
-
let new_offset = 0
|
|
1023
|
+
let new_index = 0;
|
|
1024
|
+
let new_offset = 0;
|
|
931
1025
|
|
|
932
|
-
let nextNode = this._findNodeWithIndex(index+1)
|
|
1026
|
+
let nextNode = this._findNodeWithIndex(index + 1);
|
|
933
1027
|
if (nextNode === null) {
|
|
934
|
-
new_index = index + 1
|
|
935
|
-
new_offset = SMALL_SPACE_LENGTH // Nominally should be 0, but 1 due to inserted SMALL_SPACE
|
|
1028
|
+
new_index = index + 1;
|
|
1029
|
+
new_offset = SMALL_SPACE_LENGTH; // Nominally should be 0, but 1 due to inserted SMALL_SPACE
|
|
936
1030
|
} else {
|
|
937
|
-
new_index = index - 1
|
|
938
|
-
new_offset = getNodeTextLength(
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
1031
|
+
new_index = index - 1;
|
|
1032
|
+
new_offset = getNodeTextLength(
|
|
1033
|
+
this._findNodeWithIndex(new_index)
|
|
1034
|
+
);
|
|
1035
|
+
if (new_offset < 0) {
|
|
1036
|
+
console.error("Failed to get node text length");
|
|
1037
|
+
new_offset = 0;
|
|
943
1038
|
}
|
|
944
1039
|
}
|
|
945
1040
|
|
|
946
1041
|
let new_rangeParams = {
|
|
947
|
-
startNodeIndex:new_index,
|
|
1042
|
+
startNodeIndex: new_index,
|
|
948
1043
|
startOffset: new_offset,
|
|
949
1044
|
endNodeIndex: new_index,
|
|
950
|
-
endOffset: new_offset
|
|
951
|
-
}
|
|
952
|
-
this._setRangeParams(new_rangeParams)
|
|
1045
|
+
endOffset: new_offset,
|
|
1046
|
+
};
|
|
1047
|
+
this._setRangeParams(new_rangeParams);
|
|
953
1048
|
}
|
|
954
1049
|
}
|
|
955
1050
|
}
|
|
956
1051
|
|
|
957
1052
|
if (e.key === "ArrowLeft") {
|
|
958
|
-
let rangeParams = this._getRangeParams()
|
|
959
|
-
let index = rangeParams.startNodeIndex
|
|
1053
|
+
let rangeParams = this._getRangeParams();
|
|
1054
|
+
let index = rangeParams.startNodeIndex;
|
|
960
1055
|
|
|
961
1056
|
// If the cursor is in a katex node, then move it to the previous node (unless there is no
|
|
962
1057
|
// previous node in which case move it to the next node)
|
|
963
1058
|
if (index >= 0) {
|
|
964
1059
|
if (isKatexNode(this._findNodeWithIndex(index))) {
|
|
965
|
-
let new_index = 0
|
|
966
|
-
let new_offset = 0
|
|
1060
|
+
let new_index = 0;
|
|
1061
|
+
let new_offset = 0;
|
|
967
1062
|
|
|
968
1063
|
if (index - 1 >= 0) {
|
|
969
|
-
new_index = index - 1
|
|
970
|
-
new_offset = getNodeTextLength(
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
1064
|
+
new_index = index - 1;
|
|
1065
|
+
new_offset = getNodeTextLength(
|
|
1066
|
+
this._findNodeWithIndex(new_index)
|
|
1067
|
+
);
|
|
1068
|
+
if (new_offset < 0) {
|
|
1069
|
+
console.error("Failed to get node text length");
|
|
1070
|
+
new_offset = 0;
|
|
975
1071
|
}
|
|
976
1072
|
} else {
|
|
977
|
-
new_index = index + 1
|
|
978
|
-
new_offset = SMALL_SPACE_LENGTH
|
|
1073
|
+
new_index = index + 1;
|
|
1074
|
+
new_offset = SMALL_SPACE_LENGTH;
|
|
979
1075
|
}
|
|
980
1076
|
|
|
981
1077
|
let new_rangeParams = {
|
|
982
|
-
startNodeIndex:new_index,
|
|
1078
|
+
startNodeIndex: new_index,
|
|
983
1079
|
startOffset: new_offset,
|
|
984
1080
|
endNodeIndex: new_index,
|
|
985
|
-
endOffset: new_offset
|
|
986
|
-
}
|
|
1081
|
+
endOffset: new_offset,
|
|
1082
|
+
};
|
|
987
1083
|
// console.log(new_rangeParams)
|
|
988
|
-
this._setRangeParams(new_rangeParams)
|
|
1084
|
+
this._setRangeParams(new_rangeParams);
|
|
989
1085
|
}
|
|
990
1086
|
}
|
|
991
1087
|
}
|
|
992
1088
|
|
|
993
|
-
this.updateActiveButtons()
|
|
1089
|
+
this.updateActiveButtons();
|
|
994
1090
|
} catch (error) {
|
|
995
|
-
console.error(error)
|
|
1091
|
+
console.error(error);
|
|
996
1092
|
}
|
|
997
|
-
}
|
|
1093
|
+
};
|
|
998
1094
|
|
|
999
1095
|
handleInput = (event) => {
|
|
1000
1096
|
try {
|
|
1001
1097
|
// console.log("handleInput")
|
|
1002
|
-
let raw_text = elementToMarkedRawText(
|
|
1003
|
-
|
|
1098
|
+
let raw_text = elementToMarkedRawText(
|
|
1099
|
+
this.editableDiv,
|
|
1100
|
+
null,
|
|
1101
|
+
0,
|
|
1102
|
+
this.enableHtml()
|
|
1103
|
+
);
|
|
1104
|
+
const params = this._getRangeParams();
|
|
1004
1105
|
if (params === null || params === undefined)
|
|
1005
|
-
console.error("Could not get range params from input field")
|
|
1006
|
-
else if (
|
|
1007
|
-
|
|
1106
|
+
console.error("Could not get range params from input field");
|
|
1107
|
+
else if (
|
|
1108
|
+
params.startNodeIndex === null ||
|
|
1109
|
+
params.startNodeIndex === undefined
|
|
1110
|
+
)
|
|
1111
|
+
console.error(
|
|
1112
|
+
"Could not get range params from input field, startNodeIndex===" +
|
|
1113
|
+
params.startNodeIndex
|
|
1114
|
+
);
|
|
1008
1115
|
else {
|
|
1009
1116
|
// console.log("Current range params:")
|
|
1010
1117
|
// console.log(params)
|
|
1011
1118
|
}
|
|
1012
1119
|
|
|
1013
|
-
let nodeCounts = this._countNodeTypes()
|
|
1014
|
-
let mimeType = this.getMimeType(nodeCounts.html > 0, nodeCounts.math > 0)
|
|
1015
|
-
raw_text = removeEncodingIfPlainText(
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
this.
|
|
1120
|
+
let nodeCounts = this._countNodeTypes();
|
|
1121
|
+
let mimeType = this.getMimeType(nodeCounts.html > 0, nodeCounts.math > 0);
|
|
1122
|
+
raw_text = removeEncodingIfPlainText(
|
|
1123
|
+
raw_text,
|
|
1124
|
+
mimeType,
|
|
1125
|
+
this.enableHtml()
|
|
1126
|
+
);
|
|
1127
|
+
|
|
1128
|
+
this.applyChangesToComponent(
|
|
1129
|
+
raw_text,
|
|
1130
|
+
mimeType,
|
|
1131
|
+
params,
|
|
1132
|
+
this.props.useExpertMode,
|
|
1133
|
+
this.props.selectedTab
|
|
1134
|
+
);
|
|
1019
1135
|
} catch (error) {
|
|
1020
|
-
console.error(error)
|
|
1136
|
+
console.error(error);
|
|
1021
1137
|
}
|
|
1022
|
-
}
|
|
1138
|
+
};
|
|
1023
1139
|
|
|
1024
1140
|
updateActiveButtons = () => {
|
|
1025
1141
|
try {
|
|
1026
|
-
let rangeParams = this._getRangeParams()
|
|
1027
|
-
if (rangeParams.startNodeIndex < 0)
|
|
1028
|
-
|
|
1029
|
-
let
|
|
1030
|
-
let
|
|
1031
|
-
let
|
|
1032
|
-
let
|
|
1033
|
-
let
|
|
1034
|
-
let subscript = false
|
|
1142
|
+
let rangeParams = this._getRangeParams();
|
|
1143
|
+
if (rangeParams.startNodeIndex < 0) return;
|
|
1144
|
+
let node = this._findNodeWithIndex(rangeParams.startNodeIndex);
|
|
1145
|
+
let bold = false;
|
|
1146
|
+
let italic = false;
|
|
1147
|
+
let underline = false;
|
|
1148
|
+
let superscript = false;
|
|
1149
|
+
let subscript = false;
|
|
1035
1150
|
do {
|
|
1036
1151
|
if (node.nodeType === 1) {
|
|
1037
|
-
let nodeName = node.nodeName.toLowerCase()
|
|
1038
|
-
if (nodeName === "b" || nodeName === "strong")
|
|
1039
|
-
|
|
1040
|
-
else if (nodeName === "
|
|
1041
|
-
|
|
1042
|
-
else if (nodeName === "
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
break
|
|
1052
|
-
node = node.parentNode
|
|
1053
|
-
} while (node !== null)
|
|
1152
|
+
let nodeName = node.nodeName.toLowerCase();
|
|
1153
|
+
if (nodeName === "b" || nodeName === "strong") bold = true;
|
|
1154
|
+
else if (nodeName === "i" || nodeName === "em") italic = true;
|
|
1155
|
+
else if (nodeName === "u") underline = true;
|
|
1156
|
+
else if (nodeName === "sub") subscript = true;
|
|
1157
|
+
else if (nodeName === "sup") superscript = true;
|
|
1158
|
+
} else if (
|
|
1159
|
+
node.classList !== null &&
|
|
1160
|
+
node.classList !== undefined &&
|
|
1161
|
+
node.classList.contains("MathRichInput")
|
|
1162
|
+
)
|
|
1163
|
+
break;
|
|
1164
|
+
node = node.parentNode;
|
|
1165
|
+
} while (node !== null);
|
|
1054
1166
|
|
|
1055
|
-
let activeButtons = {bold, italic, underline, subscript, superscript}
|
|
1167
|
+
let activeButtons = { bold, italic, underline, subscript, superscript };
|
|
1056
1168
|
// console.log(activeButtons)
|
|
1057
1169
|
|
|
1058
|
-
let update = true
|
|
1170
|
+
let update = true;
|
|
1059
1171
|
if (this.lastSetActiveButtons !== null) {
|
|
1060
|
-
update = false
|
|
1061
|
-
for(var style in activeButtons) {
|
|
1062
|
-
if(activeButtons[style] !== this.lastSetActiveButtons[style]) {
|
|
1063
|
-
update = true
|
|
1064
|
-
break
|
|
1172
|
+
update = false;
|
|
1173
|
+
for (var style in activeButtons) {
|
|
1174
|
+
if (activeButtons[style] !== this.lastSetActiveButtons[style]) {
|
|
1175
|
+
update = true;
|
|
1176
|
+
break;
|
|
1065
1177
|
}
|
|
1066
1178
|
}
|
|
1067
1179
|
}
|
|
1068
1180
|
if (update) {
|
|
1069
|
-
this.lastSetActiveButtons = activeButtons
|
|
1070
|
-
this.setState({activeButtons:activeButtons})
|
|
1181
|
+
this.lastSetActiveButtons = activeButtons;
|
|
1182
|
+
this.setState({ activeButtons: activeButtons });
|
|
1071
1183
|
}
|
|
1072
1184
|
} catch (error) {
|
|
1073
|
-
console.error(error)
|
|
1185
|
+
console.error(error);
|
|
1074
1186
|
}
|
|
1075
|
-
}
|
|
1187
|
+
};
|
|
1076
1188
|
|
|
1077
|
-
componentDidMount(){
|
|
1189
|
+
componentDidMount() {
|
|
1078
1190
|
try {
|
|
1079
|
-
setupKatex()
|
|
1191
|
+
setupKatex();
|
|
1080
1192
|
|
|
1081
|
-
this.editableDiv.addEventListener(
|
|
1082
|
-
this.editableDiv.addEventListener(
|
|
1193
|
+
this.editableDiv.addEventListener("keydown", this.handleKeyDown);
|
|
1194
|
+
this.editableDiv.addEventListener("keyup", this.handleKeyUp);
|
|
1083
1195
|
} catch (error) {
|
|
1084
|
-
console.error(error)
|
|
1196
|
+
console.error(error);
|
|
1085
1197
|
}
|
|
1086
1198
|
}
|
|
1087
1199
|
|
|
1088
|
-
componentWillUnmount(){
|
|
1200
|
+
componentWillUnmount() {
|
|
1089
1201
|
try {
|
|
1090
|
-
this.editableDiv.removeEventListener(
|
|
1091
|
-
this.editableDiv.removeEventListener(
|
|
1202
|
+
this.editableDiv.removeEventListener("keydown", this.handleKeyDown);
|
|
1203
|
+
this.editableDiv.removeEventListener("keyup", this.handleKeyUp);
|
|
1092
1204
|
} catch (error) {
|
|
1093
|
-
console.error(error)
|
|
1205
|
+
console.error(error);
|
|
1094
1206
|
}
|
|
1095
1207
|
}
|
|
1096
1208
|
|
|
1097
1209
|
componentDidUpdate() {
|
|
1098
|
-
try {
|
|
1210
|
+
try {
|
|
1099
1211
|
// console.log("Component updated:")
|
|
1100
1212
|
// console.log(this.editableDiv.childNodes)
|
|
1101
|
-
if (
|
|
1102
|
-
|
|
1103
|
-
this.
|
|
1104
|
-
|
|
1105
|
-
this.
|
|
1213
|
+
if (
|
|
1214
|
+
this.rangeParamsToSetAfterComponentUpdate !== null &&
|
|
1215
|
+
this.rangeParamsToSetAfterComponentUpdate !== undefined
|
|
1216
|
+
) {
|
|
1217
|
+
this._setRangeParams(this.rangeParamsToSetAfterComponentUpdate);
|
|
1218
|
+
this.rangeParamsToSetAfterComponentUpdate = null;
|
|
1219
|
+
this.updateActiveButtons();
|
|
1106
1220
|
}
|
|
1107
1221
|
} catch (error) {
|
|
1108
|
-
console.error(error)
|
|
1222
|
+
console.error(error);
|
|
1109
1223
|
}
|
|
1110
1224
|
}
|
|
1111
1225
|
|
|
1112
|
-
showEquationEditor = (moveCursorOnInsert=false, node=null) => {
|
|
1226
|
+
showEquationEditor = (moveCursorOnInsert = false, node = null) => {
|
|
1113
1227
|
try {
|
|
1114
|
-
let rangeParams = this._getRangeParams()
|
|
1228
|
+
let rangeParams = this._getRangeParams();
|
|
1115
1229
|
if (rangeParams.startNodeIndex < 0) {
|
|
1116
|
-
console.error("Could not find position of cursor in node list")
|
|
1117
|
-
console.log(rangeParams)
|
|
1118
|
-
console.log(this.editableDiv.childNodes)
|
|
1119
|
-
|
|
1120
|
-
this.setOldRangeParams({
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1230
|
+
console.error("Could not find position of cursor in node list");
|
|
1231
|
+
console.log(rangeParams);
|
|
1232
|
+
console.log(this.editableDiv.childNodes);
|
|
1233
|
+
|
|
1234
|
+
this.setOldRangeParams({
|
|
1235
|
+
startNodeIndex: 2,
|
|
1236
|
+
startOffset: 1,
|
|
1237
|
+
endNodeIndex: 2,
|
|
1238
|
+
endOffset: 1,
|
|
1239
|
+
});
|
|
1240
|
+
this.markedRawText = MARK + " " + MARK;
|
|
1241
|
+
this.moveCursorOnInsert = moveCursorOnInsert;
|
|
1124
1242
|
this.setState({
|
|
1125
|
-
showEquationEditor:true,
|
|
1126
|
-
equationEditorLatex:""
|
|
1127
|
-
|
|
1128
|
-
return
|
|
1243
|
+
showEquationEditor: true,
|
|
1244
|
+
equationEditorLatex: "",
|
|
1245
|
+
});
|
|
1246
|
+
return;
|
|
1129
1247
|
}
|
|
1130
1248
|
|
|
1131
|
-
let latex = ""
|
|
1132
|
-
let offset = 0
|
|
1249
|
+
let latex = "";
|
|
1250
|
+
let offset = 0;
|
|
1133
1251
|
|
|
1134
|
-
if (node === null)
|
|
1135
|
-
node = this._findNodeWithIndex(rangeParams.startNodeIndex)
|
|
1252
|
+
if (node === null)
|
|
1253
|
+
node = this._findNodeWithIndex(rangeParams.startNodeIndex);
|
|
1136
1254
|
|
|
1137
1255
|
// console.log(rangeParams)
|
|
1138
1256
|
// console.log(this.editableDiv.childNodes)
|
|
1139
1257
|
// console.log(node)
|
|
1140
1258
|
|
|
1141
1259
|
if (node === null || node === undefined) {
|
|
1142
|
-
console.error(
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1260
|
+
console.error(
|
|
1261
|
+
"Could not find node with index: " + rangeParams.startNodeIndex
|
|
1262
|
+
);
|
|
1263
|
+
console.log("Child nodes:");
|
|
1264
|
+
console.log(this.editableDiv.childNodes);
|
|
1265
|
+
node = this._findFirstTextNode();
|
|
1266
|
+
offset = 0;
|
|
1147
1267
|
}
|
|
1148
|
-
|
|
1149
|
-
if (isKatexNode(node)){
|
|
1150
|
-
latex = getLatex(node)
|
|
1151
|
-
offset = 0
|
|
1152
|
-
this.editingExistingEquation = true
|
|
1153
|
-
this.editingNode = node
|
|
1268
|
+
|
|
1269
|
+
if (isKatexNode(node)) {
|
|
1270
|
+
latex = getLatex(node);
|
|
1271
|
+
offset = 0;
|
|
1272
|
+
this.editingExistingEquation = true;
|
|
1273
|
+
this.editingNode = node;
|
|
1154
1274
|
} else {
|
|
1155
|
-
latex = ""
|
|
1156
|
-
offset = rangeParams.startOffset
|
|
1157
|
-
this.editingExistingEquation = false
|
|
1158
|
-
this.editingNode = null
|
|
1275
|
+
latex = "";
|
|
1276
|
+
offset = rangeParams.startOffset;
|
|
1277
|
+
this.editingExistingEquation = false;
|
|
1278
|
+
this.editingNode = null;
|
|
1159
1279
|
}
|
|
1160
|
-
|
|
1161
|
-
this.markedRawText = elementToMarkedRawText(
|
|
1280
|
+
|
|
1281
|
+
this.markedRawText = elementToMarkedRawText(
|
|
1282
|
+
this.editableDiv,
|
|
1283
|
+
node,
|
|
1284
|
+
offset,
|
|
1285
|
+
this.enableHtml()
|
|
1286
|
+
);
|
|
1162
1287
|
// console.log("Marked text:"+this.markedRawText)
|
|
1163
|
-
this.moveCursorOnInsert = moveCursorOnInsert
|
|
1288
|
+
this.moveCursorOnInsert = moveCursorOnInsert;
|
|
1164
1289
|
this.setState({
|
|
1165
|
-
showEquationEditor:true,
|
|
1166
|
-
equationEditorLatex:latex
|
|
1167
|
-
|
|
1290
|
+
showEquationEditor: true,
|
|
1291
|
+
equationEditorLatex: latex,
|
|
1292
|
+
});
|
|
1168
1293
|
} catch (error) {
|
|
1169
|
-
console.error(error)
|
|
1294
|
+
console.error(error);
|
|
1170
1295
|
}
|
|
1171
|
-
}
|
|
1296
|
+
};
|
|
1172
1297
|
|
|
1173
|
-
handleMouseDown = (event) => {
|
|
1174
|
-
this.showEquationEditorOnMouseUp = false
|
|
1175
|
-
let node = null
|
|
1298
|
+
handleMouseDown = (event) => {
|
|
1299
|
+
this.showEquationEditorOnMouseUp = false;
|
|
1300
|
+
let node = null;
|
|
1176
1301
|
try {
|
|
1177
|
-
node = event.target
|
|
1178
|
-
let isLatex = false
|
|
1302
|
+
node = event.target;
|
|
1303
|
+
let isLatex = false;
|
|
1179
1304
|
do {
|
|
1180
1305
|
if (isKatexNode(node)) {
|
|
1181
|
-
isLatex = true
|
|
1182
|
-
break
|
|
1306
|
+
isLatex = true;
|
|
1307
|
+
break;
|
|
1183
1308
|
}
|
|
1184
|
-
node = node.parentNode
|
|
1185
|
-
} while (node !== this.editableDiv && node !== null)
|
|
1309
|
+
node = node.parentNode;
|
|
1310
|
+
} while (node !== this.editableDiv && node !== null);
|
|
1186
1311
|
|
|
1187
|
-
if (!isLatex)
|
|
1188
|
-
return
|
|
1312
|
+
if (!isLatex) return;
|
|
1189
1313
|
|
|
1190
|
-
this.showEquationEditorOnMouseUp = true
|
|
1314
|
+
this.showEquationEditorOnMouseUp = true;
|
|
1191
1315
|
// Save current range parameters so that we can restore them later if we wish
|
|
1192
|
-
this.setOldRangeParams(this._getRangeParams())
|
|
1316
|
+
this.setOldRangeParams(this._getRangeParams());
|
|
1193
1317
|
|
|
1194
1318
|
// this.editableDiv.focus()
|
|
1195
1319
|
// this.showEquationEditor(false, node)
|
|
1196
1320
|
|
|
1197
1321
|
// event.preventDefault()
|
|
1198
1322
|
} catch (error) {
|
|
1199
|
-
console.error(error)
|
|
1200
|
-
console.log(node)
|
|
1323
|
+
console.error(error);
|
|
1324
|
+
console.log(node);
|
|
1201
1325
|
}
|
|
1202
|
-
}
|
|
1326
|
+
};
|
|
1203
1327
|
|
|
1204
1328
|
handleMouseUp = (event) => {
|
|
1205
1329
|
try {
|
|
1206
|
-
this.initialiseHistory()
|
|
1330
|
+
this.initialiseHistory();
|
|
1331
|
+
|
|
1332
|
+
let params = this._getRangeParams();
|
|
1333
|
+
let startNode = this._findNodeWithIndex(params.startNodeIndex);
|
|
1334
|
+
let endNode = this._findNodeWithIndex(params.endNodeIndex);
|
|
1207
1335
|
|
|
1208
|
-
let params = this._getRangeParams()
|
|
1209
|
-
let startNode = this._findNodeWithIndex(params.startNodeIndex)
|
|
1210
|
-
let endNode = this._findNodeWithIndex(params.endNodeIndex)
|
|
1211
|
-
|
|
1212
1336
|
if (startNode === null || endNode === null) {
|
|
1213
|
-
console.warn("Start or end node was null")
|
|
1214
|
-
return
|
|
1337
|
+
console.warn("Start or end node was null");
|
|
1338
|
+
return;
|
|
1215
1339
|
}
|
|
1216
1340
|
|
|
1217
|
-
if (
|
|
1341
|
+
if (
|
|
1342
|
+
params.startNodeIndex === params.endNodeIndex &&
|
|
1218
1343
|
params.startOffset === params.endOffset &&
|
|
1219
|
-
this.showEquationEditorOnMouseUp
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1344
|
+
this.showEquationEditorOnMouseUp
|
|
1345
|
+
) {
|
|
1346
|
+
this.editableDiv.focus();
|
|
1347
|
+
this.showEquationEditor(false, startNode);
|
|
1348
|
+
return;
|
|
1349
|
+
}
|
|
1224
1350
|
|
|
1225
1351
|
// If our range starts or ends inside a katex node, move it out
|
|
1226
|
-
let new_rangeParams = null
|
|
1352
|
+
let new_rangeParams = null;
|
|
1227
1353
|
if (isKatexNode(startNode)) {
|
|
1228
|
-
if (new_rangeParams === null)
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1354
|
+
if (new_rangeParams === null) new_rangeParams = { ...params };
|
|
1355
|
+
if (
|
|
1356
|
+
params.startNodeIndex === params.endNodeIndex &&
|
|
1357
|
+
params.startOffset === params.endOffset
|
|
1358
|
+
) {
|
|
1359
|
+
new_rangeParams.startNodeIndex = params.startNodeIndex + 1;
|
|
1360
|
+
new_rangeParams.startOffset = SMALL_SPACE_LENGTH;
|
|
1234
1361
|
} else {
|
|
1235
|
-
new_rangeParams.startNodeIndex = params.startNodeIndex - 1
|
|
1236
|
-
let prev_node = this._findNodeWithIndex(params.startNodeIndex - 1)
|
|
1237
|
-
new_rangeParams.startOffset = getNodeTextLength(prev_node)
|
|
1362
|
+
new_rangeParams.startNodeIndex = params.startNodeIndex - 1;
|
|
1363
|
+
let prev_node = this._findNodeWithIndex(params.startNodeIndex - 1);
|
|
1364
|
+
new_rangeParams.startOffset = getNodeTextLength(prev_node);
|
|
1238
1365
|
}
|
|
1239
1366
|
}
|
|
1240
1367
|
if (isKatexNode(endNode)) {
|
|
1241
|
-
if (new_rangeParams === null)
|
|
1242
|
-
|
|
1243
|
-
new_rangeParams.
|
|
1244
|
-
new_rangeParams.endOffset = SMALL_SPACE_LENGTH
|
|
1368
|
+
if (new_rangeParams === null) new_rangeParams = { ...params };
|
|
1369
|
+
new_rangeParams.endNodeIndex = params.endNodeIndex + 1;
|
|
1370
|
+
new_rangeParams.endOffset = SMALL_SPACE_LENGTH;
|
|
1245
1371
|
}
|
|
1246
1372
|
|
|
1247
1373
|
if (new_rangeParams !== null) {
|
|
1248
|
-
this._setRangeParams(new_rangeParams)
|
|
1249
|
-
event.preventDefault()
|
|
1250
|
-
return
|
|
1374
|
+
this._setRangeParams(new_rangeParams);
|
|
1375
|
+
event.preventDefault();
|
|
1376
|
+
return;
|
|
1251
1377
|
}
|
|
1252
1378
|
|
|
1253
|
-
this.updateActiveButtons()
|
|
1379
|
+
this.updateActiveButtons();
|
|
1254
1380
|
} catch (error) {
|
|
1255
|
-
console.error(error)
|
|
1381
|
+
console.error(error);
|
|
1256
1382
|
}
|
|
1257
|
-
|
|
1258
|
-
}
|
|
1383
|
+
};
|
|
1259
1384
|
|
|
1260
1385
|
handleEquationEditorClose = () => {
|
|
1261
1386
|
try {
|
|
1262
|
-
this.setState({showEquationEditor:false}, () => {
|
|
1263
|
-
this.editableDiv.focus()
|
|
1387
|
+
this.setState({ showEquationEditor: false }, () => {
|
|
1388
|
+
this.editableDiv.focus();
|
|
1264
1389
|
// this._setRangeParams(getOldRangeParams)
|
|
1265
|
-
})
|
|
1390
|
+
});
|
|
1266
1391
|
} catch (error) {
|
|
1267
|
-
console.error(error)
|
|
1392
|
+
console.error(error);
|
|
1268
1393
|
}
|
|
1269
|
-
}
|
|
1394
|
+
};
|
|
1270
1395
|
|
|
1271
1396
|
handleEquationEditorInsert = (latex) => {
|
|
1272
1397
|
try {
|
|
1273
1398
|
// console.log("Inserting latex: "+latex)
|
|
1274
|
-
|
|
1275
|
-
let start_pos = this.markedRawText.indexOf(MARK)
|
|
1276
|
-
let end_pos = this.markedRawText.indexOf(MARK, start_pos + MARK.length)
|
|
1277
|
-
let oldRangeParams = this.getOldRangeParams()
|
|
1278
|
-
|
|
1399
|
+
|
|
1400
|
+
let start_pos = this.markedRawText.indexOf(MARK);
|
|
1401
|
+
let end_pos = this.markedRawText.indexOf(MARK, start_pos + MARK.length);
|
|
1402
|
+
let oldRangeParams = this.getOldRangeParams();
|
|
1403
|
+
|
|
1279
1404
|
// Handle case of empty string returned
|
|
1280
1405
|
if (latex === "") {
|
|
1281
1406
|
// console.log("Empty latex returned from equation editor")
|
|
1282
|
-
let new_raw_text =
|
|
1283
|
-
this.markedRawText.substring(0,start_pos) +
|
|
1284
|
-
this.markedRawText.substring(end_pos + MARK.length)
|
|
1407
|
+
let new_raw_text =
|
|
1408
|
+
this.markedRawText.substring(0, start_pos) +
|
|
1409
|
+
this.markedRawText.substring(end_pos + MARK.length);
|
|
1285
1410
|
|
|
1286
1411
|
// Delete node if it was a latex node
|
|
1287
|
-
let new_index = -1
|
|
1288
|
-
let new_offset = -1
|
|
1412
|
+
let new_index = -1;
|
|
1413
|
+
let new_offset = -1;
|
|
1289
1414
|
if (this.editingExistingEquation) {
|
|
1290
|
-
|
|
1291
|
-
let indexOfEditedNode = this._findIndexOfNode(this.editingNode)
|
|
1415
|
+
let indexOfEditedNode = this._findIndexOfNode(this.editingNode);
|
|
1292
1416
|
|
|
1293
1417
|
if (oldRangeParams.startNodeIndex === indexOfEditedNode + 1) {
|
|
1294
|
-
new_index = oldRangeParams.startNodeIndex-2
|
|
1295
|
-
new_offset = getNodeTextLength(this._findNodeWithIndex(new_index))
|
|
1418
|
+
new_index = oldRangeParams.startNodeIndex - 2;
|
|
1419
|
+
new_offset = getNodeTextLength(this._findNodeWithIndex(new_index));
|
|
1296
1420
|
} else if (oldRangeParams.startNodeIndex > indexOfEditedNode + 1) {
|
|
1297
|
-
new_index = oldRangeParams.startNodeIndex-2
|
|
1298
|
-
new_offset = oldRangeParams.startOffset
|
|
1421
|
+
new_index = oldRangeParams.startNodeIndex - 2;
|
|
1422
|
+
new_offset = oldRangeParams.startOffset;
|
|
1299
1423
|
} else {
|
|
1300
|
-
new_index = oldRangeParams.startNodeIndex
|
|
1301
|
-
new_offset = oldRangeParams.startOffset
|
|
1424
|
+
new_index = oldRangeParams.startNodeIndex;
|
|
1425
|
+
new_offset = oldRangeParams.startOffset;
|
|
1302
1426
|
}
|
|
1303
1427
|
}
|
|
1304
1428
|
|
|
1305
1429
|
let new_rangeParams = {
|
|
1306
|
-
startNodeIndex:new_index,
|
|
1307
|
-
startOffset:new_offset,
|
|
1308
|
-
endNodeIndex:new_index,
|
|
1309
|
-
endOffset:new_offset
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
let
|
|
1430
|
+
startNodeIndex: new_index,
|
|
1431
|
+
startOffset: new_offset,
|
|
1432
|
+
endNodeIndex: new_index,
|
|
1433
|
+
endOffset: new_offset,
|
|
1434
|
+
};
|
|
1435
|
+
this.setOldRangeParams(new_rangeParams);
|
|
1436
|
+
|
|
1437
|
+
let nodeCounts = this._countNodeTypes();
|
|
1438
|
+
let mimeType = null;
|
|
1314
1439
|
if (this.editingExistingEquation)
|
|
1315
|
-
mimeType = this.getMimeType(
|
|
1440
|
+
mimeType = this.getMimeType(
|
|
1441
|
+
nodeCounts.html > 0,
|
|
1442
|
+
nodeCounts.katex > 1
|
|
1443
|
+
);
|
|
1316
1444
|
else
|
|
1317
|
-
mimeType = this.getMimeType(
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1445
|
+
mimeType = this.getMimeType(
|
|
1446
|
+
nodeCounts.html > 0,
|
|
1447
|
+
nodeCounts.katex > 0
|
|
1448
|
+
);
|
|
1449
|
+
new_raw_text = removeEncodingIfPlainText(
|
|
1450
|
+
new_raw_text,
|
|
1451
|
+
mimeType,
|
|
1452
|
+
this.enableHtml()
|
|
1453
|
+
);
|
|
1454
|
+
|
|
1455
|
+
this.applyChangesToComponent(
|
|
1456
|
+
new_raw_text,
|
|
1457
|
+
mimeType,
|
|
1458
|
+
new_rangeParams,
|
|
1459
|
+
this.props.useExpertMode,
|
|
1460
|
+
this.props.selectedTab
|
|
1461
|
+
);
|
|
1462
|
+
this.setState({ showEquationEditor: false });
|
|
1463
|
+
return;
|
|
1324
1464
|
}
|
|
1325
1465
|
|
|
1326
1466
|
// Handle case of latex returned, in which case we update the katex node
|
|
1327
1467
|
// console.log("Latex returned from equation editor: "+latex)
|
|
1328
|
-
let new_raw_text = replaceMarksWithMath(
|
|
1329
|
-
|
|
1330
|
-
|
|
1468
|
+
let new_raw_text = replaceMarksWithMath(
|
|
1469
|
+
this.markedRawText,
|
|
1470
|
+
latex,
|
|
1471
|
+
this.enableHtml()
|
|
1472
|
+
);
|
|
1473
|
+
// let new_raw_text =
|
|
1474
|
+
// this.markedRawText.substring(0,start_pos) +
|
|
1331
1475
|
// RAW_TEXT_MATH_START_TAG + latex + RAW_TEXT_MATH_END_TAG +
|
|
1332
1476
|
// this.markedRawText.substring(end_pos + MARK.length)
|
|
1333
1477
|
|
|
1334
|
-
console.log(
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1478
|
+
console.log(
|
|
1479
|
+
"Old cursor pos: " +
|
|
1480
|
+
oldRangeParams.startNodeIndex +
|
|
1481
|
+
"->" +
|
|
1482
|
+
oldRangeParams.startOffset
|
|
1483
|
+
);
|
|
1484
|
+
console.log("Old raw text: " + this.props.value);
|
|
1485
|
+
console.log("Old raw text length: " + this.props.value.length);
|
|
1486
|
+
console.log("Old marked raw text:" + this.markedRawText);
|
|
1487
|
+
console.log("New raw text: " + new_raw_text);
|
|
1488
|
+
|
|
1489
|
+
let new_rangeParams = this.getOldRangeParams();
|
|
1341
1490
|
if (this.moveCursorOnInsert) {
|
|
1342
|
-
if (this.props.value === "")
|
|
1491
|
+
if (this.props.value === "")
|
|
1492
|
+
// Special case of previously empty text input
|
|
1343
1493
|
new_rangeParams = {
|
|
1344
|
-
startNodeIndex:2,
|
|
1345
|
-
startOffset:SMALL_SPACE_LENGTH,
|
|
1346
|
-
endNodeIndex:2,
|
|
1347
|
-
endOffset:SMALL_SPACE_LENGTH
|
|
1348
|
-
|
|
1494
|
+
startNodeIndex: 2,
|
|
1495
|
+
startOffset: SMALL_SPACE_LENGTH,
|
|
1496
|
+
endNodeIndex: 2,
|
|
1497
|
+
endOffset: SMALL_SPACE_LENGTH,
|
|
1498
|
+
};
|
|
1499
|
+
// normal case
|
|
1500
|
+
else
|
|
1349
1501
|
new_rangeParams = {
|
|
1350
|
-
startNodeIndex:oldRangeParams.startNodeIndex+2,
|
|
1351
|
-
startOffset:SMALL_SPACE_LENGTH,
|
|
1352
|
-
endNodeIndex:oldRangeParams.startNodeIndex+2,
|
|
1353
|
-
endOffset:SMALL_SPACE_LENGTH
|
|
1502
|
+
startNodeIndex: oldRangeParams.startNodeIndex + 2,
|
|
1503
|
+
startOffset: SMALL_SPACE_LENGTH,
|
|
1504
|
+
endNodeIndex: oldRangeParams.startNodeIndex + 2,
|
|
1505
|
+
endOffset: SMALL_SPACE_LENGTH,
|
|
1506
|
+
};
|
|
1354
1507
|
}
|
|
1355
1508
|
// console.log("New cursor pos: "+new_rangeParams.startNodeIndex+"->"+new_rangeParams.startOffset)
|
|
1356
|
-
this.setOldRangeParams(new_rangeParams)
|
|
1357
|
-
|
|
1358
|
-
let nodeCounts = this._countNodeTypes()
|
|
1359
|
-
let mimeType = this.getMimeType(nodeCounts.html > 0, true)
|
|
1360
|
-
new_raw_text = removeEncodingIfPlainText(
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1509
|
+
this.setOldRangeParams(new_rangeParams);
|
|
1510
|
+
|
|
1511
|
+
let nodeCounts = this._countNodeTypes();
|
|
1512
|
+
let mimeType = this.getMimeType(nodeCounts.html > 0, true);
|
|
1513
|
+
new_raw_text = removeEncodingIfPlainText(
|
|
1514
|
+
new_raw_text,
|
|
1515
|
+
mimeType,
|
|
1516
|
+
this.enableHtml()
|
|
1517
|
+
);
|
|
1518
|
+
|
|
1519
|
+
this.applyChangesToComponent(
|
|
1520
|
+
new_raw_text,
|
|
1521
|
+
mimeType,
|
|
1522
|
+
new_rangeParams,
|
|
1523
|
+
this.props.useExpertMode,
|
|
1524
|
+
this.props.selectedTab
|
|
1525
|
+
);
|
|
1526
|
+
this.setState({ showEquationEditor: false });
|
|
1365
1527
|
} catch (error) {
|
|
1366
|
-
console.error(error)
|
|
1528
|
+
console.error(error);
|
|
1367
1529
|
}
|
|
1368
|
-
}
|
|
1530
|
+
};
|
|
1369
1531
|
|
|
1370
1532
|
// findEditableDiv = (node) => {
|
|
1371
1533
|
// if (node === null)
|
|
1372
1534
|
// return null
|
|
1373
|
-
// if (node.classList !== null && node.classList !== undefined &&
|
|
1535
|
+
// if (node.classList !== null && node.classList !== undefined &&
|
|
1374
1536
|
// node.classList.contains("MathRichInput"))
|
|
1375
1537
|
// return node
|
|
1376
1538
|
// return this.findEditableDiv(node.parentNode);
|
|
@@ -1378,294 +1540,393 @@ export default class MathRichInput extends React.Component {
|
|
|
1378
1540
|
|
|
1379
1541
|
styleText = (event, style) => {
|
|
1380
1542
|
try {
|
|
1381
|
-
style = style.toLowerCase()
|
|
1382
|
-
let success = document.execCommand(style,false, null)
|
|
1383
|
-
let buttonState = this.state.activeButtons[style]
|
|
1384
|
-
if (buttonState === null || buttonState === undefined)
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
new_activeButtons
|
|
1390
|
-
|
|
1391
|
-
return success
|
|
1543
|
+
style = style.toLowerCase();
|
|
1544
|
+
let success = document.execCommand(style, false, null);
|
|
1545
|
+
let buttonState = this.state.activeButtons[style];
|
|
1546
|
+
if (buttonState === null || buttonState === undefined) return success;
|
|
1547
|
+
|
|
1548
|
+
buttonState = !buttonState;
|
|
1549
|
+
let new_activeButtons = { ...this.state.activeButtons };
|
|
1550
|
+
new_activeButtons[style] = buttonState;
|
|
1551
|
+
this.setState({ activeButtons: new_activeButtons });
|
|
1552
|
+
return success;
|
|
1392
1553
|
} catch (error) {
|
|
1393
|
-
console.error(error)
|
|
1554
|
+
console.error(error);
|
|
1394
1555
|
}
|
|
1395
|
-
}
|
|
1556
|
+
};
|
|
1396
1557
|
|
|
1397
1558
|
handleToolbarButtonClick = (event, buttonName) => {
|
|
1398
|
-
console.log("button name: ",buttonName)
|
|
1559
|
+
console.log("button name: ", buttonName);
|
|
1399
1560
|
try {
|
|
1400
1561
|
if (buttonName === "Equation") {
|
|
1401
|
-
this.showEquationEditor(true)
|
|
1562
|
+
this.showEquationEditor(true);
|
|
1402
1563
|
}
|
|
1403
|
-
let style = buttonName
|
|
1404
|
-
let success = this.styleText(event, style)
|
|
1405
|
-
if (!success)
|
|
1406
|
-
console.warn("execCommand returned false: "+style)
|
|
1564
|
+
let style = buttonName;
|
|
1565
|
+
let success = this.styleText(event, style);
|
|
1566
|
+
if (!success) console.warn("execCommand returned false: " + style);
|
|
1407
1567
|
} catch (error) {
|
|
1408
|
-
console.error(error)
|
|
1568
|
+
console.error(error);
|
|
1409
1569
|
}
|
|
1410
|
-
}
|
|
1570
|
+
};
|
|
1411
1571
|
|
|
1412
1572
|
fetchAccentLetter = (event) => {
|
|
1413
1573
|
try {
|
|
1414
|
-
let rangeParams = this._getRangeParams()
|
|
1574
|
+
let rangeParams = this._getRangeParams();
|
|
1415
1575
|
if (rangeParams === null) {
|
|
1416
|
-
console.error("Cound not get range params")
|
|
1417
|
-
return null
|
|
1576
|
+
console.error("Cound not get range params");
|
|
1577
|
+
return null;
|
|
1418
1578
|
}
|
|
1419
|
-
let node = this._findNodeWithIndex(rangeParams.endNodeIndex)
|
|
1420
|
-
let offset = rangeParams.endOffset
|
|
1579
|
+
let node = this._findNodeWithIndex(rangeParams.endNodeIndex);
|
|
1580
|
+
let offset = rangeParams.endOffset;
|
|
1421
1581
|
|
|
1422
|
-
let raw_text = elementToMarkedRawText(
|
|
1582
|
+
let raw_text = elementToMarkedRawText(
|
|
1583
|
+
this.editableDiv,
|
|
1584
|
+
node,
|
|
1585
|
+
offset,
|
|
1586
|
+
this.enableHtml()
|
|
1587
|
+
);
|
|
1423
1588
|
|
|
1424
|
-
return getCharacterBeforeMarks(raw_text)
|
|
1589
|
+
return getCharacterBeforeMarks(raw_text);
|
|
1425
1590
|
} catch (error) {
|
|
1426
|
-
console.error(error)
|
|
1591
|
+
console.error(error);
|
|
1427
1592
|
}
|
|
1428
|
-
}
|
|
1593
|
+
};
|
|
1429
1594
|
|
|
1430
1595
|
insertRawText = (event, new_text) => {
|
|
1431
1596
|
try {
|
|
1432
|
-
let rangeParams = this._getRangeParams()
|
|
1433
|
-
let node = this._findNodeWithIndex(rangeParams.endNodeIndex)
|
|
1434
|
-
let offset = rangeParams.endOffset
|
|
1435
|
-
|
|
1436
|
-
let raw_text = elementToMarkedRawText(
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
new_rangeParams
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1597
|
+
let rangeParams = this._getRangeParams();
|
|
1598
|
+
let node = this._findNodeWithIndex(rangeParams.endNodeIndex);
|
|
1599
|
+
let offset = rangeParams.endOffset;
|
|
1600
|
+
|
|
1601
|
+
let raw_text = elementToMarkedRawText(
|
|
1602
|
+
this.editableDiv,
|
|
1603
|
+
node,
|
|
1604
|
+
offset,
|
|
1605
|
+
this.enableHtml()
|
|
1606
|
+
);
|
|
1607
|
+
let new_raw_text = null;
|
|
1608
|
+
let new_rangeParams = { ...rangeParams };
|
|
1609
|
+
new_raw_text = removeMarks(
|
|
1610
|
+
insertCharacterBeforeMarks(raw_text, new_text)
|
|
1611
|
+
);
|
|
1612
|
+
if (
|
|
1613
|
+
rangeParams.startNodeIndex === rangeParams.endNodeIndex &&
|
|
1614
|
+
rangeParams.startOffset === rangeParams.endOffset
|
|
1615
|
+
)
|
|
1616
|
+
new_rangeParams.startOffset =
|
|
1617
|
+
new_rangeParams.startOffset + new_text.length;
|
|
1618
|
+
new_rangeParams.endOffset = new_rangeParams.endOffset + new_text.length;
|
|
1619
|
+
|
|
1620
|
+
new_raw_text = removeEncodingIfPlainText(
|
|
1621
|
+
new_raw_text,
|
|
1622
|
+
this.state.mimeType,
|
|
1623
|
+
this.enableHtml()
|
|
1624
|
+
);
|
|
1625
|
+
|
|
1626
|
+
this.applyChangesToComponent(
|
|
1627
|
+
new_raw_text,
|
|
1628
|
+
this.state.mimeType,
|
|
1629
|
+
new_rangeParams,
|
|
1630
|
+
this.props.useExpertMode,
|
|
1631
|
+
this.props.selectedTab
|
|
1632
|
+
);
|
|
1449
1633
|
} catch (error) {
|
|
1450
|
-
console.error(error)
|
|
1451
|
-
}
|
|
1452
|
-
}
|
|
1634
|
+
console.error(error);
|
|
1635
|
+
}
|
|
1636
|
+
};
|
|
1453
1637
|
|
|
1454
1638
|
removeNewLine = () => {
|
|
1455
1639
|
try {
|
|
1456
|
-
let rangeParams = this._getRangeParams()
|
|
1457
|
-
let node = this._findNodeWithIndex(rangeParams.endNodeIndex)
|
|
1458
|
-
let prevNode = this._findNodeWithIndex(rangeParams.endNodeIndex-1)
|
|
1459
|
-
let offset = rangeParams.endOffset
|
|
1460
|
-
|
|
1461
|
-
let raw_text = elementToMarkedRawText(
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1640
|
+
let rangeParams = this._getRangeParams();
|
|
1641
|
+
let node = this._findNodeWithIndex(rangeParams.endNodeIndex);
|
|
1642
|
+
let prevNode = this._findNodeWithIndex(rangeParams.endNodeIndex - 1);
|
|
1643
|
+
let offset = rangeParams.endOffset;
|
|
1644
|
+
|
|
1645
|
+
let raw_text = elementToMarkedRawText(
|
|
1646
|
+
this.editableDiv,
|
|
1647
|
+
node,
|
|
1648
|
+
offset,
|
|
1649
|
+
this.enableHtml()
|
|
1650
|
+
);
|
|
1651
|
+
let new_raw_text = null;
|
|
1652
|
+
new_raw_text = removeMarks(
|
|
1653
|
+
replaceStringBeforeMarks(raw_text, "</p><p>", "")
|
|
1654
|
+
);
|
|
1655
|
+
|
|
1656
|
+
let new_rangeParams = { ...rangeParams };
|
|
1657
|
+
let new_offset = getNodeTextLength(prevNode);
|
|
1658
|
+
new_rangeParams.startNodeIndex = rangeParams.startNodeIndex - 1;
|
|
1659
|
+
new_rangeParams.startOffset = new_offset;
|
|
1660
|
+
new_rangeParams.endNodeIndex = rangeParams.endNodeIndex - 1;
|
|
1661
|
+
new_rangeParams.endOffset = new_offset;
|
|
1662
|
+
|
|
1663
|
+
console.log("About to apply new range params");
|
|
1664
|
+
console.log(new_rangeParams);
|
|
1665
|
+
console.log("Old nodes");
|
|
1666
|
+
console.log(this.editableDiv.childNodes);
|
|
1667
|
+
|
|
1668
|
+
new_raw_text = removeEncodingIfPlainText(
|
|
1669
|
+
new_raw_text,
|
|
1670
|
+
this.state.mimeType,
|
|
1671
|
+
this.enableHtml()
|
|
1672
|
+
);
|
|
1673
|
+
|
|
1674
|
+
this.applyChangesToComponent(
|
|
1675
|
+
new_raw_text,
|
|
1676
|
+
this.state.mimeType,
|
|
1677
|
+
new_rangeParams,
|
|
1678
|
+
this.props.useExpertMode,
|
|
1679
|
+
this.props.selectedTab
|
|
1680
|
+
);
|
|
1481
1681
|
} catch (error) {
|
|
1482
|
-
console.error(error)
|
|
1483
|
-
}
|
|
1484
|
-
}
|
|
1682
|
+
console.error(error);
|
|
1683
|
+
}
|
|
1684
|
+
};
|
|
1485
1685
|
|
|
1486
1686
|
insertNewLine = () => {
|
|
1487
1687
|
try {
|
|
1488
|
-
let rangeParams = this._getRangeParams()
|
|
1489
|
-
let node = this._findNodeWithIndex(rangeParams.endNodeIndex)
|
|
1490
|
-
let offset = rangeParams.endOffset
|
|
1491
|
-
|
|
1492
|
-
let raw_text = elementToMarkedRawText(
|
|
1493
|
-
|
|
1494
|
-
|
|
1688
|
+
let rangeParams = this._getRangeParams();
|
|
1689
|
+
let node = this._findNodeWithIndex(rangeParams.endNodeIndex);
|
|
1690
|
+
let offset = rangeParams.endOffset;
|
|
1691
|
+
|
|
1692
|
+
let raw_text = elementToMarkedRawText(
|
|
1693
|
+
this.editableDiv,
|
|
1694
|
+
node,
|
|
1695
|
+
offset,
|
|
1696
|
+
this.enableHtml()
|
|
1697
|
+
);
|
|
1698
|
+
let new_raw_text = null;
|
|
1699
|
+
let new_rangeParams = { ...rangeParams };
|
|
1495
1700
|
|
|
1496
1701
|
if (this.enableHtml()) {
|
|
1497
|
-
new_raw_text = removeMarks(
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
new_rangeParams.
|
|
1504
|
-
new_rangeParams.
|
|
1702
|
+
new_raw_text = removeMarks(
|
|
1703
|
+
insertCharacterBeforeMarks(raw_text, "</p><p>")
|
|
1704
|
+
);
|
|
1705
|
+
if (new_raw_text.substring(0, 3).toLowerCase() !== "<p>")
|
|
1706
|
+
new_raw_text = "<p>" + new_raw_text + "</p>";
|
|
1707
|
+
|
|
1708
|
+
new_rangeParams.startNodeIndex = rangeParams.startNodeIndex + 1;
|
|
1709
|
+
new_rangeParams.startOffset = 0;
|
|
1710
|
+
new_rangeParams.endNodeIndex = rangeParams.endNodeIndex + 1;
|
|
1711
|
+
new_rangeParams.endOffset = 0;
|
|
1505
1712
|
} else {
|
|
1506
|
-
new_raw_text = removeMarks(insertCharacterBeforeMarks(raw_text, "\n"))
|
|
1507
|
-
new_rangeParams.startOffset
|
|
1508
|
-
new_rangeParams.endOffset
|
|
1713
|
+
new_raw_text = removeMarks(insertCharacterBeforeMarks(raw_text, "\n"));
|
|
1714
|
+
new_rangeParams.startOffset++;
|
|
1715
|
+
new_rangeParams.endOffset++;
|
|
1509
1716
|
}
|
|
1510
1717
|
|
|
1511
|
-
|
|
1512
|
-
console.log(
|
|
1513
|
-
console.log(
|
|
1514
|
-
console.log(
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1718
|
+
console.log("About to apply new range params");
|
|
1719
|
+
console.log(new_rangeParams);
|
|
1720
|
+
console.log("Old nodes");
|
|
1721
|
+
console.log(this.editableDiv.childNodes);
|
|
1722
|
+
|
|
1723
|
+
new_raw_text = removeEncodingIfPlainText(
|
|
1724
|
+
new_raw_text,
|
|
1725
|
+
this.state.mimeType,
|
|
1726
|
+
this.enableHtml()
|
|
1727
|
+
);
|
|
1728
|
+
|
|
1729
|
+
this.applyChangesToComponent(
|
|
1730
|
+
new_raw_text,
|
|
1731
|
+
this.state.mimeType,
|
|
1732
|
+
new_rangeParams,
|
|
1733
|
+
this.props.useExpertMode,
|
|
1734
|
+
this.props.selectedTab
|
|
1735
|
+
);
|
|
1521
1736
|
} catch (error) {
|
|
1522
|
-
console.error(error)
|
|
1523
|
-
}
|
|
1524
|
-
}
|
|
1737
|
+
console.error(error);
|
|
1738
|
+
}
|
|
1739
|
+
};
|
|
1525
1740
|
|
|
1526
1741
|
replaceNextLetter = (new_char) => {
|
|
1527
1742
|
try {
|
|
1528
|
-
console.log("Replace next letter")
|
|
1529
|
-
let rangeParams = this._getRangeParams()
|
|
1530
|
-
let node = this._findNodeWithIndex(rangeParams.endNodeIndex)
|
|
1531
|
-
let offset = rangeParams.endOffset+1 // next letter
|
|
1532
|
-
|
|
1533
|
-
let raw_text = elementToMarkedRawText(
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
new_rangeParams
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1743
|
+
console.log("Replace next letter");
|
|
1744
|
+
let rangeParams = this._getRangeParams();
|
|
1745
|
+
let node = this._findNodeWithIndex(rangeParams.endNodeIndex);
|
|
1746
|
+
let offset = rangeParams.endOffset + 1; // next letter
|
|
1747
|
+
|
|
1748
|
+
let raw_text = elementToMarkedRawText(
|
|
1749
|
+
this.editableDiv,
|
|
1750
|
+
node,
|
|
1751
|
+
offset,
|
|
1752
|
+
this.enableHtml()
|
|
1753
|
+
);
|
|
1754
|
+
let new_raw_text = null;
|
|
1755
|
+
let new_rangeParams = { ...rangeParams };
|
|
1756
|
+
new_raw_text = removeMarks(
|
|
1757
|
+
insertCharacterBeforeMarks(raw_text, new_char)
|
|
1758
|
+
);
|
|
1759
|
+
if (
|
|
1760
|
+
rangeParams.startNodeIndex === rangeParams.endNodeIndex &&
|
|
1761
|
+
rangeParams.startOffset === rangeParams.endOffset
|
|
1762
|
+
)
|
|
1763
|
+
new_rangeParams.startOffset =
|
|
1764
|
+
new_rangeParams.startOffset + new_char.length + 1;
|
|
1765
|
+
new_rangeParams.endOffset =
|
|
1766
|
+
new_rangeParams.endOffset + new_char.length + 1;
|
|
1767
|
+
|
|
1768
|
+
new_raw_text = removeEncodingIfPlainText(
|
|
1769
|
+
new_raw_text,
|
|
1770
|
+
this.state.mimeType,
|
|
1771
|
+
this.enableHtml()
|
|
1772
|
+
);
|
|
1773
|
+
this.applyChangesToComponent(
|
|
1774
|
+
new_raw_text,
|
|
1775
|
+
this.state.mimeType,
|
|
1776
|
+
new_rangeParams,
|
|
1777
|
+
this.props.useExpertMode,
|
|
1778
|
+
this.props.selectedTab
|
|
1779
|
+
);
|
|
1545
1780
|
} catch (error) {
|
|
1546
|
-
console.error(error)
|
|
1781
|
+
console.error(error);
|
|
1547
1782
|
}
|
|
1548
|
-
}
|
|
1783
|
+
};
|
|
1549
1784
|
|
|
1550
1785
|
insertAccentLetter = (event, old_char, new_char) => {
|
|
1551
1786
|
try {
|
|
1552
|
-
let rangeParams = this._getRangeParams()
|
|
1553
|
-
let node = this._findNodeWithIndex(rangeParams.endNodeIndex)
|
|
1554
|
-
let offset = rangeParams.endOffset
|
|
1555
|
-
|
|
1556
|
-
let raw_text = elementToMarkedRawText(
|
|
1557
|
-
|
|
1558
|
-
|
|
1787
|
+
let rangeParams = this._getRangeParams();
|
|
1788
|
+
let node = this._findNodeWithIndex(rangeParams.endNodeIndex);
|
|
1789
|
+
let offset = rangeParams.endOffset;
|
|
1790
|
+
|
|
1791
|
+
let raw_text = elementToMarkedRawText(
|
|
1792
|
+
this.editableDiv,
|
|
1793
|
+
node,
|
|
1794
|
+
offset,
|
|
1795
|
+
this.enableHtml()
|
|
1796
|
+
);
|
|
1797
|
+
let new_raw_text = null;
|
|
1798
|
+
let new_rangeParams = { ...rangeParams };
|
|
1559
1799
|
if (old_char === null) {
|
|
1560
|
-
new_raw_text = removeMarks(
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1800
|
+
new_raw_text = removeMarks(
|
|
1801
|
+
insertCharacterBeforeMarks(raw_text, new_char)
|
|
1802
|
+
);
|
|
1803
|
+
if (
|
|
1804
|
+
rangeParams.startNodeIndex === rangeParams.endNodeIndex &&
|
|
1805
|
+
rangeParams.startOffset === rangeParams.endOffset
|
|
1806
|
+
)
|
|
1807
|
+
new_rangeParams.startOffset =
|
|
1808
|
+
new_rangeParams.startOffset + new_char.length;
|
|
1809
|
+
new_rangeParams.endOffset = new_rangeParams.endOffset + new_char.length;
|
|
1810
|
+
} else
|
|
1811
|
+
new_raw_text = removeMarks(
|
|
1812
|
+
replaceCharacterBeforeMarks(raw_text, new_char)
|
|
1813
|
+
);
|
|
1814
|
+
|
|
1815
|
+
new_raw_text = removeEncodingIfPlainText(
|
|
1816
|
+
new_raw_text,
|
|
1817
|
+
this.state.mimeType,
|
|
1818
|
+
this.enableHtml()
|
|
1819
|
+
);
|
|
1820
|
+
this.applyChangesToComponent(
|
|
1821
|
+
new_raw_text,
|
|
1822
|
+
this.state.mimeType,
|
|
1823
|
+
new_rangeParams,
|
|
1824
|
+
this.props.useExpertMode,
|
|
1825
|
+
this.props.selectedTab
|
|
1826
|
+
);
|
|
1572
1827
|
} catch (error) {
|
|
1573
|
-
console.error(error)
|
|
1828
|
+
console.error(error);
|
|
1574
1829
|
}
|
|
1575
|
-
}
|
|
1830
|
+
};
|
|
1576
1831
|
|
|
1577
1832
|
handleAccentButtonClick = (event, oldCharacter, newCharacter) => {
|
|
1578
1833
|
try {
|
|
1579
|
-
this.insertAccentLetter(event, oldCharacter, newCharacter)
|
|
1580
|
-
this.setState({showAccentBar:false})
|
|
1834
|
+
this.insertAccentLetter(event, oldCharacter, newCharacter);
|
|
1835
|
+
this.setState({ showAccentBar: false });
|
|
1581
1836
|
} catch (error) {
|
|
1582
|
-
console.error(error)
|
|
1837
|
+
console.error(error);
|
|
1583
1838
|
}
|
|
1584
|
-
}
|
|
1585
|
-
|
|
1839
|
+
};
|
|
1586
1840
|
|
|
1587
1841
|
handleFocus = (event) => {
|
|
1588
1842
|
// console.log("handleFocus")
|
|
1589
1843
|
try {
|
|
1590
|
-
this._setRangeParams(this.getOldRangeParams())
|
|
1591
|
-
this.setState({hasFocus:true})
|
|
1844
|
+
this._setRangeParams(this.getOldRangeParams());
|
|
1845
|
+
this.setState({ hasFocus: true });
|
|
1592
1846
|
} catch (error) {
|
|
1593
|
-
console.error(error)
|
|
1847
|
+
console.error(error);
|
|
1594
1848
|
}
|
|
1595
|
-
}
|
|
1849
|
+
};
|
|
1596
1850
|
|
|
1597
1851
|
handleBlur = (event) => {
|
|
1598
1852
|
try {
|
|
1599
|
-
this.setState({hasFocus:false, showAccentBar:false})
|
|
1853
|
+
this.setState({ hasFocus: false, showAccentBar: false });
|
|
1600
1854
|
} catch (error) {
|
|
1601
|
-
console.error(error)
|
|
1855
|
+
console.error(error);
|
|
1602
1856
|
}
|
|
1603
|
-
}
|
|
1604
|
-
|
|
1857
|
+
};
|
|
1858
|
+
|
|
1605
1859
|
render() {
|
|
1606
|
-
console.log("Rendering MathRichInput. Latex: "+this.props.value)
|
|
1860
|
+
console.log("Rendering MathRichInput. Latex: " + this.props.value);
|
|
1607
1861
|
|
|
1608
|
-
if (this.props.value === undefined
|
|
1609
|
-
console.error(
|
|
1610
|
-
console.log(this.props)
|
|
1862
|
+
if (this.props.value === undefined) {
|
|
1863
|
+
console.error('MathRichInput must have prop called "text"');
|
|
1864
|
+
console.log(this.props);
|
|
1611
1865
|
}
|
|
1612
1866
|
|
|
1613
|
-
const html = rawTextToHtml(
|
|
1867
|
+
const html = rawTextToHtml(
|
|
1868
|
+
katex,
|
|
1869
|
+
this.props.value || "",
|
|
1870
|
+
this.props.mimeType
|
|
1871
|
+
);
|
|
1614
1872
|
|
|
1615
|
-
let useClassName = "MathRichInput-Container" // Don't change this name - used by various components to find node
|
|
1873
|
+
let useClassName = "MathRichInput-Container"; // Don't change this name - used by various components to find node
|
|
1616
1874
|
if (this.props.className)
|
|
1617
|
-
useClassName = this.props.className + " " + useClassName
|
|
1618
|
-
|
|
1619
|
-
let accentLetter = null
|
|
1620
|
-
if (this.state.showAccentBar)
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1875
|
+
useClassName = this.props.className + " " + useClassName;
|
|
1876
|
+
|
|
1877
|
+
let accentLetter = null;
|
|
1878
|
+
if (this.state.showAccentBar) accentLetter = this.fetchAccentLetter(null);
|
|
1879
|
+
|
|
1880
|
+
return (
|
|
1881
|
+
<>
|
|
1882
|
+
<div className={useClassName}>
|
|
1883
|
+
<div className="MathRichInput-scrollview">
|
|
1884
|
+
{this.state.hasFocus && (
|
|
1885
|
+
<Toolbar
|
|
1886
|
+
className="Toolbar"
|
|
1887
|
+
enableMath={this.enableMath()}
|
|
1888
|
+
enableFontStyling={this.enableFontStyling()}
|
|
1889
|
+
style={this.translateToolbar}
|
|
1890
|
+
keyPressed={this.state.keyPressed}
|
|
1891
|
+
activeButtons={this.state.activeButtons}
|
|
1892
|
+
onButtonClick={this.handleToolbarButtonClick}
|
|
1893
|
+
fetchAccentLetter={this.fetchAccentLetter}
|
|
1894
|
+
insertAccentLetter={this.insertAccentLetter}
|
|
1895
|
+
/>
|
|
1896
|
+
)}
|
|
1897
|
+
{this.state.showAccentBar && (
|
|
1898
|
+
<AccentBar
|
|
1899
|
+
compactMode={true}
|
|
1900
|
+
accentLetter={accentLetter}
|
|
1901
|
+
keyPressed={this.state.keyPressed}
|
|
1902
|
+
fetchAccentLetter={this.fetchAccentLetter}
|
|
1903
|
+
onButtonClick={(e, oldCharacter, newCharacter) =>
|
|
1904
|
+
this.handleAccentButtonClick(e, oldCharacter, newCharacter)
|
|
1905
|
+
}
|
|
1906
|
+
/>
|
|
1907
|
+
)}
|
|
1908
|
+
<span
|
|
1909
|
+
className="MathRichInput" // Don't change this name - used to various components to find node
|
|
1910
|
+
contentEditable="true"
|
|
1911
|
+
ref={(r) => (this.editableDiv = r)}
|
|
1912
|
+
onInput={this.handleInput}
|
|
1913
|
+
onMouseDown={this.handleMouseDown}
|
|
1914
|
+
onMouseUp={this.handleMouseUp}
|
|
1915
|
+
onFocus={this.handleFocus}
|
|
1916
|
+
onBlur={this.handleBlur}
|
|
1917
|
+
dangerouslySetInnerHTML={{ __html: html }}
|
|
1918
|
+
></span>
|
|
1919
|
+
</div>
|
|
1660
1920
|
</div>
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1921
|
+
{this.state.showEquationEditor && (
|
|
1922
|
+
<EquationEditorModal
|
|
1923
|
+
ref={(r) => (this.equationEditorModal = r)}
|
|
1924
|
+
handleClose={this.handleEquationEditorClose}
|
|
1925
|
+
handleInsert={this.handleEquationEditorInsert}
|
|
1926
|
+
latex={this.state.equationEditorLatex}
|
|
1927
|
+
/>
|
|
1928
|
+
)}
|
|
1929
|
+
</>
|
|
1930
|
+
);
|
|
1670
1931
|
}
|
|
1671
|
-
}
|
|
1932
|
+
}
|