@zzish/math-rich-input 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,52 +1,71 @@
1
- import React from 'react'
2
- import { addStyles, EditableMathField } from 'react-mathquill'
3
- import SymbolButton from './SymbolButton'
4
- import { getSymbolsForButtonArea, getLatexInsertionParams} from './equationEditorButtonsHelper.js';
1
+ import React from "react";
2
+ import { addStyles, EditableMathField } from "react-mathquill";
3
+ import SymbolButton from "./SymbolButton";
4
+ import {
5
+ getSymbolsForButtonArea,
6
+ getLatexInsertionParams,
7
+ } from "./equationEditorButtonsHelper.js";
5
8
 
6
- import './EquationEditor.css';
9
+ import "./EquationEditor.css";
7
10
 
8
11
  // Katex setup
9
12
  import katex from "katex";
10
- const MARK = "_M_A_R_K_"
13
+ const MARK = "_M_A_R_K_";
11
14
 
12
15
  // MathQuill setup
13
- addStyles()
14
- const AUTO_OPERATOR_NAMES = 'sin cos tan sec cosec cot log ln lim min max'
15
-
16
+ addStyles();
17
+ const AUTO_OPERATOR_NAMES = "sin cos tan sec cosec cot log ln lim min max";
16
18
 
17
19
  // Recent button bar
18
- const RECENT_WEIGHT = 15
19
- const RECENT_DECAY_FACTOR = 0.95
20
- const RECENT_MAX = 11
21
- let GLOBAL_recentSymbols = []
22
- let GLOBAL_lastSymbols = ["","",""]
20
+ const RECENT_WEIGHT = 15;
21
+ const RECENT_DECAY_FACTOR = 0.95;
22
+ const RECENT_MAX = 11;
23
+ let GLOBAL_recentSymbols = [];
24
+ let GLOBAL_lastSymbols = ["", "", ""];
23
25
 
24
26
  // Genreal constants
25
- const MAX_BUTTON_ROWS = 5
26
- const TAB_NAMES = ["Common", "More", "Greek", "Chemistry", "Physics"]
27
- const BUTTON_AREA_NAMES = ["Common", "Operators", "Angles",
28
- "Misc", "Sets",
29
- "GreekLower", "GreekUpper",
30
- "Chemistry","Elements",
31
- "Physics1", "Physics2", "Physics3"]
32
- const TAB_NAMES_EXPERT = ["Common", "More", "Greek", "Expert"]
33
- const BUTTON_AREA_NAMES_EXPERT = ["Common", "Operators", "Angles",
34
- "Misc", "Sets",
35
- "GreekLower", "GreekUpper",
36
- "Expert","Matrices"]
37
- const TAB_STARTS_AT_AREA_NAMED = {"Common":"Common",
38
- "More":"Misc",
39
- "Greek":"GreekLower",
40
- "Chemistry":"Chemistry",
41
- "Physics":"Physics1",
42
- "Expert":"Expert"}
27
+ const MAX_BUTTON_ROWS = 5;
28
+ const TAB_NAMES = ["Common", "More", "Greek", "Chemistry", "Physics"];
29
+ const BUTTON_AREA_NAMES = [
30
+ "Common",
31
+ "Operators",
32
+ "Angles",
33
+ "Misc",
34
+ "Sets",
35
+ "GreekLower",
36
+ "GreekUpper",
37
+ "Chemistry",
38
+ "Elements",
39
+ "Physics1",
40
+ "Physics2",
41
+ "Physics3",
42
+ ];
43
+ const TAB_NAMES_EXPERT = ["Common", "More", "Greek", "Expert"];
44
+ const BUTTON_AREA_NAMES_EXPERT = [
45
+ "Common",
46
+ "Operators",
47
+ "Angles",
48
+ "Misc",
49
+ "Sets",
50
+ "GreekLower",
51
+ "GreekUpper",
52
+ "Expert",
53
+ "Matrices",
54
+ ];
55
+ const TAB_STARTS_AT_AREA_NAMED = {
56
+ Common: "Common",
57
+ More: "Misc",
58
+ Greek: "GreekLower",
59
+ Chemistry: "Chemistry",
60
+ Physics: "Physics1",
61
+ Expert: "Expert",
62
+ };
43
63
 
44
64
  let GLOBAL_buttonAreasWidths = null;
45
65
  let GLOBAL_buttonAreasWidthsExpert = null;
46
- let GLOBAL_last_selected_tab = TAB_NAMES[0]
66
+ let GLOBAL_last_selected_tab = TAB_NAMES[0];
47
67
 
48
68
  export default class EquationEditor extends React.Component {
49
-
50
69
  constructor(props) {
51
70
  super(props);
52
71
  this.state = {
@@ -56,19 +75,19 @@ export default class EquationEditor extends React.Component {
56
75
  recentSymbolsCount: 0,
57
76
  };
58
77
 
59
- this.mathQuill = null
60
- this.handleInsertCallback = props.handleInsert
61
- this.handleCancelCallback = props.handleCancel
78
+ this.mathQuill = null;
79
+ this.handleInsertCallback = props.handleInsert;
80
+ this.handleCancelCallback = props.handleCancel;
62
81
  }
63
82
 
64
83
  handleInsert = () => {
65
- this.handleInsertCallback(this.state.latex)
66
- }
84
+ this.handleInsertCallback(this.state.latex);
85
+ };
67
86
 
68
87
  handleCancel = () => {
69
- this.handleCancelCallback()
70
- }
71
-
88
+ this.handleCancelCallback();
89
+ };
90
+
72
91
  prettifyLatex(latex) {
73
92
  // NB: replaceAll not suported on safari
74
93
  // console.log("Before: "+latex)
@@ -84,295 +103,288 @@ export default class EquationEditor extends React.Component {
84
103
  // latex = latex.replaceAll(" "," ")
85
104
  // latex = latex.trim()
86
105
  // console.log("Prettified: "+latex)
87
- return latex
106
+ return latex;
88
107
  }
89
108
 
90
109
  handleChange = (mathQuill) => {
91
- this.setState({latex:mathQuill.latex(),
92
- pretty:false})
93
- }
110
+ this.setState({ latex: mathQuill.latex(), pretty: false });
111
+ };
94
112
 
95
113
  handleKeyDown = (e) => {
96
114
  // console.log(e.key)
97
115
  try {
98
116
  if (!this.props.useExpertMode && e.key === "Enter") {
99
- this.handleInsertCallback(this.state.latex)
100
- e.preventDefault()
117
+ this.handleInsertCallback(this.state.latex);
118
+ e.preventDefault();
101
119
  }
102
120
  } catch (error) {
103
- console.error(error)
121
+ console.error(error);
104
122
  }
105
- }
123
+ };
106
124
 
107
125
  updateRecentSymbols(symbol) {
108
- let recentSymbols = GLOBAL_recentSymbols
109
- let symbolIndex = -1
110
- let minIndex = -1
111
- let min = 999999
126
+ let recentSymbols = GLOBAL_recentSymbols;
127
+ let symbolIndex = -1;
128
+ let minIndex = -1;
129
+ let min = 999999;
112
130
  for (let i = 0; i < recentSymbols.length; i++) {
113
- if (recentSymbols[i].name === symbol)
114
- symbolIndex = i
131
+ if (recentSymbols[i].name === symbol) symbolIndex = i;
115
132
  if (recentSymbols[i].count > 0)
116
- recentSymbols[i].count = recentSymbols[i].count * RECENT_DECAY_FACTOR
133
+ recentSymbols[i].count = recentSymbols[i].count * RECENT_DECAY_FACTOR;
117
134
  if (recentSymbols[i].count <= min) {
118
- min = recentSymbols[i].count
119
- minIndex = i
135
+ min = recentSymbols[i].count;
136
+ minIndex = i;
120
137
  }
121
138
  }
122
139
  if (symbolIndex >= 0) {
123
- recentSymbols[symbolIndex].count = recentSymbols[symbolIndex].count + RECENT_WEIGHT
140
+ recentSymbols[symbolIndex].count =
141
+ recentSymbols[symbolIndex].count + RECENT_WEIGHT;
124
142
  } else {
125
143
  if (recentSymbols.length >= RECENT_MAX) {
126
- recentSymbols.splice(minIndex, 1)
144
+ recentSymbols.splice(minIndex, 1);
127
145
  }
128
- recentSymbols.push({name:symbol, count:RECENT_WEIGHT})
146
+ recentSymbols.push({ name: symbol, count: RECENT_WEIGHT });
129
147
  }
130
148
 
131
149
  // recentSymbols.sort((a, b) => b.count - a.count) // Order max to min
132
150
 
133
- GLOBAL_recentSymbols = recentSymbols
134
- GLOBAL_lastSymbols.pop()
135
- GLOBAL_lastSymbols.unshift(symbol)
151
+ GLOBAL_recentSymbols = recentSymbols;
152
+ GLOBAL_lastSymbols.pop();
153
+ GLOBAL_lastSymbols.unshift(symbol);
136
154
 
137
-
138
- this.setState({recentSymbolsCount:this.state.recentSymbolsCount + 1})
155
+ this.setState({ recentSymbolsCount: this.state.recentSymbolsCount + 1 });
139
156
  }
140
157
 
141
158
  handleInsertSymbol = (symbol) => {
142
- if (this.props.useExpertMode)
143
- this.handleInsertSymbolKatex(symbol)
144
- else
145
- this.handleInsertSymbolMathQuill(symbol)
146
- }
159
+ if (this.props.useExpertMode) this.handleInsertSymbolKatex(symbol);
160
+ else this.handleInsertSymbolMathQuill(symbol);
161
+ };
147
162
 
148
163
  isLetter = (char) => {
149
- return ('a' <= char && char <= 'z') || ('A' <= char && char <= 'Z')
150
- }
164
+ return ("a" <= char && char <= "z") || ("A" <= char && char <= "Z");
165
+ };
151
166
 
152
167
  // Returns:
153
168
  // 1. the provided pos if pos is not inside a latex tag
154
169
  // 2. a new pos if pos is close to the start or end of a tag (within 2 characters)
155
170
  // 3. -1 if pos is not close to the start or end of a tag
156
171
  movePosIfInsideTag(latex, pos) {
157
- if (pos === 0 || pos === latex.length)
158
- return pos
172
+ if (pos === 0 || pos === latex.length) return pos;
159
173
 
160
- let c = latex.charAt(pos)
161
- if (!this.isLetter(c))
162
- return pos
163
- let cm1 = latex.charAt(pos-1)
164
- if (!this.isLetter(cm1) && cm1 !== "\\")
165
- return pos-1
174
+ let c = latex.charAt(pos);
175
+ if (!this.isLetter(c)) return pos;
176
+ let cm1 = latex.charAt(pos - 1);
177
+ if (!this.isLetter(cm1) && cm1 !== "\\") return pos - 1;
166
178
 
167
179
  // We are inside a latex tag, let's move out of it
168
- if (pos === 1)
169
- return 0
170
- if (pos === latex.length-1)
171
- return latex.length
172
-
173
- if (latex.charAt(pos-1) === "\\")
174
- return pos-1
175
- if (!this.isLetter(latex.charAt(pos+1)))
176
- return pos+1
177
- if (latex.charAt(pos-2) === "\\")
178
- return pos-2
179
- if (!this.isLetter(latex.charAt(pos+2)))
180
- return pos+2
181
-
182
- return -1
180
+ if (pos === 1) return 0;
181
+ if (pos === latex.length - 1) return latex.length;
182
+
183
+ if (latex.charAt(pos - 1) === "\\") return pos - 1;
184
+ if (!this.isLetter(latex.charAt(pos + 1))) return pos + 1;
185
+ if (latex.charAt(pos - 2) === "\\") return pos - 2;
186
+ if (!this.isLetter(latex.charAt(pos + 2))) return pos + 2;
187
+
188
+ return -1;
183
189
  }
184
190
 
185
191
  handleInsertSymbolKatex = (symbol) => {
186
- let oldLatex = null
187
- let start = -1
188
- let end = -1
192
+ let oldLatex = null;
193
+ let start = -1;
194
+ let end = -1;
189
195
  try {
190
- this.updateRecentSymbols(symbol)
191
- oldLatex = this.latexInput.value
192
- start = this.latexInput.selectionStart
193
- end = this.latexInput.selectionEnd
194
-
195
- start = this.movePosIfInsideTag(oldLatex, start)
196
- end = this.movePosIfInsideTag(oldLatex, end)
197
- if (start === -1 || end === -1 ) {
198
- console.log("Can't insert as cursor position or start or end of selection is inside a tag")
199
- return
196
+ this.updateRecentSymbols(symbol);
197
+ oldLatex = this.latexInput.value;
198
+ start = this.latexInput.selectionStart;
199
+ end = this.latexInput.selectionEnd;
200
+
201
+ start = this.movePosIfInsideTag(oldLatex, start);
202
+ end = this.movePosIfInsideTag(oldLatex, end);
203
+ if (start === -1 || end === -1) {
204
+ console.log(
205
+ "Can't insert as cursor position or start or end of selection is inside a tag"
206
+ );
207
+ return;
200
208
  }
201
209
 
202
210
  // if (this.latexInput !== document.activeElement)
203
- this.latexInput.focus()
211
+ this.latexInput.focus();
204
212
 
205
- let insertParams = getLatexInsertionParams(symbol)
206
- let insert = insertParams.latexWithMarks
207
- console.log("Insert params: ")
208
- console.log(insertParams)
209
- console.log(start+":"+end)
210
- console.log(oldLatex)
213
+ let insertParams = getLatexInsertionParams(symbol);
214
+ let insert = insertParams.latexWithMarks;
215
+ console.log("Insert params: ");
216
+ console.log(insertParams);
217
+ console.log(start + ":" + end);
218
+ console.log(oldLatex);
211
219
 
212
220
  // Move text before cursor into latex if double mark exists in latex
213
- let pos = insert.indexOf("##")
221
+ let pos = insert.indexOf("##");
214
222
  if (pos >= 0) {
215
223
  if (start !== end) {
216
- insert = insert.replace("##", oldLatex.substring(start, end))
217
- console.log("insert: "+insert)
218
- oldLatex = oldLatex.substring(0,start) + oldLatex.substring(end)
219
- end = start
224
+ insert = insert.replace("##", oldLatex.substring(start, end));
225
+ console.log("insert: " + insert);
226
+ oldLatex = oldLatex.substring(0, start) + oldLatex.substring(end);
227
+ end = start;
220
228
  } else if (start > 0) {
221
- insert = insert.replace("##", oldLatex.charAt(start-1))
222
- oldLatex = oldLatex.substring(0,start-1) + oldLatex.substring(start)
223
- start = start -1
224
- end = start
229
+ insert = insert.replace("##", oldLatex.charAt(start - 1));
230
+ oldLatex =
231
+ oldLatex.substring(0, start - 1) + oldLatex.substring(start);
232
+ start = start - 1;
233
+ end = start;
225
234
  } else {
226
- insert = insert.replace("##", "#")
235
+ insert = insert.replace("##", "#");
227
236
  }
228
237
  }
229
238
  // Move text before cursor into latex if selection made and single mark exists in latex
230
239
  // or otherwise delete selected text
231
240
  if (start !== end) {
232
- pos = insert.indexOf("#")
233
- if (pos >=0)
234
- insert = insert.replace("#", oldLatex.substring(start, end))
235
-
236
- oldLatex = oldLatex.substring(0,start) + oldLatex.substring(end)
237
- end = start
241
+ pos = insert.indexOf("#");
242
+ if (pos >= 0)
243
+ insert = insert.replace("#", oldLatex.substring(start, end));
244
+
245
+ oldLatex = oldLatex.substring(0, start) + oldLatex.substring(end);
246
+ end = start;
238
247
  }
239
248
 
240
249
  // Remove any extra marks after the first mark
241
- insert = insert.replace("#",MARK)
242
- insert = insert.replaceAll("#","")
243
- insert = insert.replace(MARK,"#")
250
+ insert = insert.replace("#", MARK);
251
+ insert = insert.replaceAll("#", "");
252
+ insert = insert.replace(MARK, "#");
244
253
 
245
254
  // Construct new latex
246
- let newLatex =
247
- oldLatex.substring(0,start) +
255
+ let newLatex =
256
+ oldLatex.substring(0, start) +
248
257
  insert +
249
258
  MARK +
250
- oldLatex.substring(start)
251
- let newSelectionStart = newLatex.indexOf(MARK)
252
- newLatex = newLatex.substring(0,newSelectionStart) +
253
- newLatex.substring(newSelectionStart+MARK.length)
254
-
255
- // Move cursor position back to mark in inserted text if applicable
256
- pos = insert.indexOf("#")
259
+ oldLatex.substring(start);
260
+ let newSelectionStart = newLatex.indexOf(MARK);
261
+ newLatex =
262
+ newLatex.substring(0, newSelectionStart) +
263
+ newLatex.substring(newSelectionStart + MARK.length);
264
+
265
+ // Move cursor position back to mark in inserted text if applicable
266
+ pos = insert.indexOf("#");
257
267
  if (pos > 0) {
258
- newSelectionStart = newLatex.lastIndexOf("#",newSelectionStart)
259
- newLatex = newLatex.substring(0,newSelectionStart)+newLatex.substring(newSelectionStart+1)
268
+ newSelectionStart = newLatex.lastIndexOf("#", newSelectionStart);
269
+ newLatex =
270
+ newLatex.substring(0, newSelectionStart) +
271
+ newLatex.substring(newSelectionStart + 1);
260
272
  }
261
273
 
262
- this.setState({latex:newLatex},
263
- () => {
264
- this.latexInput.selectionStart = newSelectionStart
265
- this.latexInput.selectionEnd = newSelectionStart
266
- this.latexInput.focus()
267
- })
274
+ this.setState({ latex: newLatex }, () => {
275
+ this.latexInput.selectionStart = newSelectionStart;
276
+ this.latexInput.selectionEnd = newSelectionStart;
277
+ this.latexInput.focus();
278
+ });
268
279
  } catch (error) {
269
- console.error(error)
270
- console.log("Inserting: "+symbol)
271
- console.log("into: "+this.latexInput.value)
272
- console.log("at: "+start+":"+end)
280
+ console.error(error);
281
+ console.log("Inserting: " + symbol);
282
+ console.log("into: " + this.latexInput.value);
283
+ console.log("at: " + start + ":" + end);
273
284
  }
274
- }
275
-
285
+ };
276
286
 
277
287
  handleInsertSymbolMathQuill = (symbol) => {
278
288
  try {
279
- this.updateRecentSymbols(symbol)
289
+ this.updateRecentSymbols(symbol);
280
290
 
281
- let insert = getLatexInsertionParams(symbol)
291
+ let insert = getLatexInsertionParams(symbol);
282
292
  if (insert === null || insert === undefined) {
283
- console.err("Could not get latex insertion parameters for symbol: "+symbol)
284
- this.mathQuill.focus()
285
- return
293
+ console.err(
294
+ "Could not get latex insertion parameters for symbol: " + symbol
295
+ );
296
+ this.mathQuill.focus();
297
+ return;
286
298
  }
287
299
 
288
- if (insert.typedText)
289
- this.mathQuill.typedText(insert.mathQuillLatex)
290
- else
291
- this.mathQuill.write(insert.mathQuillLatex)
300
+ if (insert.typedText) this.mathQuill.typedText(insert.mathQuillLatex);
301
+ else this.mathQuill.write(insert.mathQuillLatex);
292
302
 
293
- this.mathQuill.focus()
303
+ this.mathQuill.focus();
294
304
 
295
305
  for (let i = 0; i < insert.moveCursor; i++)
296
- this.mathQuill.keystroke('Right')
306
+ this.mathQuill.keystroke("Right");
297
307
  for (let i = 0; i > insert.moveCursor; i--)
298
- this.mathQuill.keystroke('Left')
308
+ this.mathQuill.keystroke("Left");
299
309
  } catch (error) {
300
- console.error(error)
301
- console.log("Symbol: "+symbol)
310
+ console.error(error);
311
+ console.log("Symbol: " + symbol);
302
312
  }
303
- }
313
+ };
304
314
 
305
315
  handleSelectTab = (tab) => {
306
- if (!this.props.useExpertMode)
307
- this.mathQuill.focus()
308
- else
309
- this.latexInput.focus()
310
-
311
- GLOBAL_last_selected_tab = tab
312
- this.setState({selectedTab:tab},
313
- () =>
314
- {
315
- let buttonAreas = this.symbolButtonAreasInnerContainer.childNodes
316
- for (let i = 0; i < buttonAreas.length; i++) {
317
- if (buttonAreas[i].id === TAB_STARTS_AT_AREA_NAMED[tab]) {
318
- buttonAreas[i].scrollIntoView({behavior:"smooth", inline:"start"})
319
- }
316
+ if (!this.props.useExpertMode) this.mathQuill.focus();
317
+ else this.latexInput.focus();
318
+
319
+ GLOBAL_last_selected_tab = tab;
320
+ this.setState({ selectedTab: tab }, () => {
321
+ let buttonAreas = this.symbolButtonAreasInnerContainer.childNodes;
322
+ for (let i = 0; i < buttonAreas.length; i++) {
323
+ if (buttonAreas[i].id === TAB_STARTS_AT_AREA_NAMED[tab]) {
324
+ buttonAreas[i].scrollIntoView({
325
+ behavior: "smooth",
326
+ inline: "start",
327
+ });
320
328
  }
321
- })
322
- }
329
+ }
330
+ });
331
+ };
323
332
 
324
333
  mathquillDidMount(mathQuill) {
325
- this.mathQuill = mathQuill
326
- mathQuill.focus()
334
+ this.mathQuill = mathQuill;
335
+ mathQuill.focus();
327
336
  }
328
337
 
329
- componentDidMount(){
338
+ componentDidMount() {
330
339
  // let thisComponentNode = ReactDOM.findDOMNode(this);
331
- this.equationEditorDiv.addEventListener('keydown',this.handleKeyDown);
340
+ this.equationEditorDiv.addEventListener("keydown", this.handleKeyDown);
332
341
 
333
342
  // Restore scroll position for tab to last selected
334
- let buttonAreas = this.symbolButtonAreasInnerContainer.childNodes
343
+ let buttonAreas = this.symbolButtonAreasInnerContainer.childNodes;
335
344
  for (let i = 0; i < buttonAreas.length; i++) {
336
- if (buttonAreas[i].id === TAB_STARTS_AT_AREA_NAMED[GLOBAL_last_selected_tab]) {
337
- buttonAreas[i].scrollIntoView({behavior:"auto", inline:"start"})
345
+ if (
346
+ buttonAreas[i].id === TAB_STARTS_AT_AREA_NAMED[GLOBAL_last_selected_tab]
347
+ ) {
348
+ buttonAreas[i].scrollIntoView({ behavior: "auto", inline: "start" });
338
349
  }
339
350
  }
340
351
  }
341
352
 
342
- componentWillUnmount(){
353
+ componentWillUnmount() {
343
354
  // let thisComponentNode = ReactDOM.findDOMNode(this);
344
- this.equationEditorDiv.removeEventListener('keydown',this.handleKeyDown);
355
+ this.equationEditorDiv.removeEventListener("keydown", this.handleKeyDown);
345
356
  }
346
357
 
347
358
  isMobile() {
348
359
  return (
349
- (window.innerHeight > window.innerWidth) &&
350
- (window.innerHeight < 820)) || (window.innerHeight < 500)
360
+ (window.innerHeight > window.innerWidth && window.innerHeight < 820) ||
361
+ window.innerHeight < 500
362
+ );
351
363
  }
352
364
 
353
- isTouchDevice() {
354
- return ( 'ontouchstart' in window ) ||
355
- ( navigator.maxTouchPoints > 0 ) ||
356
- ( navigator.msMaxTouchPoints > 0 );
365
+ isTouchDevice() {
366
+ return (
367
+ "ontouchstart" in window ||
368
+ navigator.maxTouchPoints > 0 ||
369
+ navigator.msMaxTouchPoints > 0
370
+ );
357
371
  }
358
372
 
359
373
  handleCursorLeft = () => {
360
- this.mathQuill.keystroke('Left')
361
- this.mathQuill.focus()
362
- }
374
+ this.mathQuill.keystroke("Left");
375
+ this.mathQuill.focus();
376
+ };
363
377
 
364
378
  handleCursorRight = () => {
365
- this.mathQuill.keystroke('Right')
366
- this.mathQuill.focus()
367
- }
379
+ this.mathQuill.keystroke("Right");
380
+ this.mathQuill.focus();
381
+ };
368
382
 
369
383
  handleLatexInputChange = (event) => {
370
- this.setState({latex:event.target.value,
371
- pretty:true})
372
- }
384
+ this.setState({ latex: event.target.value, pretty: true });
385
+ };
373
386
 
374
387
  renderLatexString = (latex) => {
375
-
376
388
  const options = {
377
389
  children: "",
378
390
  displayMode: false,
@@ -385,199 +397,235 @@ export default class EquationEditor extends React.Component {
385
397
  minRuleThickness: 0,
386
398
  colorIsTextColor: false,
387
399
  strict: "warn",
388
- trust: false
389
- }
400
+ trust: false,
401
+ };
390
402
 
391
403
  try {
392
- // returns HTML markup
393
- return katex.renderToString(latex, options);
404
+ // returns HTML markup
405
+ return katex.renderToString(latex, options);
394
406
  } catch (err) {
395
- console.error("Could not convert latex string to html: ", latex);
396
- return "Error: Unable to render latex";
407
+ console.error("Could not convert latex string to html: ", latex);
408
+ return "Error: Unable to render latex";
397
409
  }
398
410
  };
399
411
 
400
412
  render() {
401
- console.log("Rendering EquationEditor. Latex: "+this.state.latex)
402
- let katexHtml = null
403
- let prettyLatex = null
413
+ console.log("Rendering EquationEditor. Latex: " + this.state.latex);
414
+ let katexHtml = null;
415
+ let prettyLatex = null;
404
416
  if (this.props.useExpertMode) {
405
- katexHtml = this.renderLatexString(this.state.latex)
406
- if (this.state.pretty)
407
- prettyLatex = this.state.latex
417
+ katexHtml = this.renderLatexString(this.state.latex);
418
+ if (this.state.pretty) prettyLatex = this.state.latex;
408
419
  else {
409
- prettyLatex = this.prettifyLatex(this.state.latex)
420
+ prettyLatex = this.prettifyLatex(this.state.latex);
410
421
  }
411
422
  }
412
423
 
413
- let tabNames = TAB_NAMES
414
- let buttonAreaNames = BUTTON_AREA_NAMES
415
- let buttonAreaWidths = GLOBAL_buttonAreasWidths
424
+ let tabNames = TAB_NAMES;
425
+ let buttonAreaNames = BUTTON_AREA_NAMES;
426
+ let buttonAreaWidths = GLOBAL_buttonAreasWidths;
416
427
  if (this.props.useExpertMode) {
417
- tabNames = TAB_NAMES_EXPERT
418
- buttonAreaNames = BUTTON_AREA_NAMES_EXPERT
419
- buttonAreaWidths = GLOBAL_buttonAreasWidthsExpert
428
+ tabNames = TAB_NAMES_EXPERT;
429
+ buttonAreaNames = BUTTON_AREA_NAMES_EXPERT;
430
+ buttonAreaWidths = GLOBAL_buttonAreasWidthsExpert;
420
431
  }
421
432
 
422
- const recentButtons = GLOBAL_recentSymbols.slice(0,RECENT_MAX).map((symbol, index) => {
423
- return (
424
- <SymbolButton
433
+ const recentButtons = GLOBAL_recentSymbols.slice(0, RECENT_MAX).map(
434
+ (symbol, index) => {
435
+ return (
436
+ <SymbolButton
425
437
  className="SymbolButton"
426
- key={"recent=symbol-"+index}
438
+ key={"recent=symbol-" + index}
427
439
  symbol={symbol.name}
428
440
  shouldUpdate={true}
429
441
  highlight={
430
- symbol.name === GLOBAL_lastSymbols[0] ? "0" :
431
- symbol.name === GLOBAL_lastSymbols[1] ? "1" :
432
- symbol.name === GLOBAL_lastSymbols[2] ? "2" : "none"
442
+ symbol.name === GLOBAL_lastSymbols[0]
443
+ ? "0"
444
+ : symbol.name === GLOBAL_lastSymbols[1]
445
+ ? "1"
446
+ : symbol.name === GLOBAL_lastSymbols[2]
447
+ ? "2"
448
+ : "none"
433
449
  }
434
450
  handleClick={(latex) => this.handleInsertSymbol(symbol.name)}
435
451
  />
436
- )
437
- })
452
+ );
453
+ }
454
+ );
438
455
 
439
456
  if (buttonAreaWidths === null) {
440
- let widths = []
457
+ let widths = [];
441
458
  for (let i = 0; i < buttonAreaNames.length; i++) {
442
- widths[i] = Math.ceil(getSymbolsForButtonArea(buttonAreaNames[i]).length/MAX_BUTTON_ROWS)
459
+ widths[i] = Math.ceil(
460
+ getSymbolsForButtonArea(buttonAreaNames[i]).length / MAX_BUTTON_ROWS
461
+ );
443
462
  }
444
463
  buttonAreaWidths = widths;
445
464
  }
446
-
465
+
447
466
  const buttonAreasButtons = buttonAreaNames.map((buttonArea, index) => {
448
- return (
449
- getSymbolsForButtonArea(buttonArea).map((symbol, index) => {
450
- return (
451
- <SymbolButton
452
- className="SymbolButton"
453
- key={buttonArea+"-symbol-"+index}
454
- highlight={buttonArea.toLowerCase()}
455
- symbol={symbol}
456
- handleClick={() => this.handleInsertSymbol(symbol)}
457
- />
458
- )
459
- }
460
- )
461
- )})
467
+ return getSymbolsForButtonArea(buttonArea).map((symbol, index) => {
468
+ return (
469
+ <SymbolButton
470
+ className="SymbolButton"
471
+ key={buttonArea + "-symbol-" + index}
472
+ highlight={buttonArea.toLowerCase()}
473
+ symbol={symbol}
474
+ handleClick={() => this.handleInsertSymbol(symbol)}
475
+ />
476
+ );
477
+ });
478
+ });
462
479
 
463
- return <div className="EquationEditor"
464
- ref={(r) => this.equationEditorDiv = r}
465
- >
466
- {/* Normal mode. Add cursor move buttons for mobile devices as they don't have
480
+ return (
481
+ <div className="EquationEditor" ref={(r) => (this.equationEditorDiv = r)}>
482
+ {/* Normal mode. Add cursor move buttons for mobile devices as they don't have
467
483
  cursor keys in the soft keyboard. */}
468
- { !this.props.useExpertMode &&
469
- <div className="editableAndCursorButtonsWrapper">
470
- { this.isTouchDevice() &&
471
- <button
472
- className="cursorButton"
473
- onClick={(t) => this.handleCursorLeft()}>
474
- {"\u25C1"}
475
- </button>
476
- }
477
-
478
- <div
479
- ref={(r) => this.editableWrapper = r}
480
- className="editableWrapper">
481
- <div className="centerBox">
482
- <EditableMathField
483
- className="editable"
484
- latex={this.state.latex}
485
- placeholder="Type equation .."
486
- config={{
487
- autoOperatorNames: AUTO_OPERATOR_NAMES
488
- }}
489
- mathquillDidMount={mathQuill => this.mathquillDidMount(mathQuill)}
490
- onChange={(mathQuill) => this.handleChange(mathQuill)}
491
- />
492
- { this.state.latex.length=== 0 &&
493
- <div className="editable-placeholder">Type equation</div>}
484
+ {!this.props.useExpertMode && (
485
+ <div className="editableAndCursorButtonsWrapper">
486
+ {this.isTouchDevice() && (
487
+ <button
488
+ className="cursorButton"
489
+ onClick={(t) => this.handleCursorLeft()}
490
+ >
491
+ {"\u25C1"}
492
+ </button>
493
+ )}
494
+
495
+ <div
496
+ ref={(r) => (this.editableWrapper = r)}
497
+ className="editableWrapper"
498
+ >
499
+ <div className="centerBox">
500
+ <EditableMathField
501
+ className="editable"
502
+ latex={this.state.latex}
503
+ placeholder="Type equation .."
504
+ config={{
505
+ autoOperatorNames: AUTO_OPERATOR_NAMES,
506
+ }}
507
+ mathquillDidMount={(mathQuill) =>
508
+ this.mathquillDidMount(mathQuill)
509
+ }
510
+ onChange={(mathQuill) => this.handleChange(mathQuill)}
511
+ />
512
+ {this.state.latex.length === 0 && (
513
+ <div className="editable-placeholder">Type equation</div>
514
+ )}
515
+ </div>
494
516
  </div>
495
- </div>
496
517
 
497
- { this.isTouchDevice() &&
498
- <button
499
- className="cursorButton"
500
- onClick={(t) => this.handleCursorRight()}>
501
- {"\u25B7"}
502
- </button>
503
- }
504
- </div>}
505
-
506
- { /* Expert mode */}
507
- { this.props.useExpertMode &&
508
- <div className="latexInputAreaWrapper">
509
- <textarea className="latexInput"
510
- autoFocus
511
- placeholder="Type latex"
512
- spellCheck="false"
513
- ref={(r) => this.latexInput = r}
514
- onChange={this.handleLatexInputChange}
515
- value={prettyLatex}>
516
- </textarea>
517
- <div className="katexRenderedInput"
518
- dangerouslySetInnerHTML={{__html: katexHtml}}
519
- />
520
- </div>
521
- }
522
-
518
+ {this.isTouchDevice() && (
519
+ <button
520
+ className="cursorButton"
521
+ onClick={(t) => this.handleCursorRight()}
522
+ >
523
+ {"\u25B7"}
524
+ </button>
525
+ )}
526
+ </div>
527
+ )}
528
+
529
+ {/* Expert mode */}
530
+ {this.props.useExpertMode && (
531
+ <div className="latexInputAreaWrapper">
532
+ <textarea
533
+ className="latexInput"
534
+ autoFocus
535
+ placeholder="Type latex"
536
+ spellCheck="false"
537
+ ref={(r) => (this.latexInput = r)}
538
+ onChange={this.handleLatexInputChange}
539
+ value={prettyLatex}
540
+ ></textarea>
541
+ <div
542
+ className="katexRenderedInput"
543
+ dangerouslySetInnerHTML={{ __html: katexHtml }}
544
+ />
545
+ </div>
546
+ )}
523
547
 
524
- {/* Cancel and submit button row. Cancel button is only shown on mobile devices as
548
+ {/* Cancel and submit button row. Cancel button is only shown on mobile devices as
525
549
  there may be no visible background to click on to close the modal. */}
526
- { this.isMobile() &&
550
+ {this.isMobile() && (
551
+ <button
552
+ className="cancelButton"
553
+ type="button"
554
+ onClick={this.handleCancel}
555
+ >
556
+ Cancel
557
+ </button>
558
+ )}
527
559
  <button
528
- className="cancelButton"
529
- type="button" onClick={this.handleCancel}>
530
- Cancel
560
+ className="insertButton"
561
+ type="button"
562
+ onClick={this.handleInsert}
563
+ >
564
+ Insert
531
565
  </button>
532
- }
533
- <button
534
- className="insertButton"
535
- type="button" onClick={this.handleInsert}>
536
- Insert
537
- </button>
538
-
539
-
540
- {/* Recent symbols button bar */}
541
- { !this.isMobile() && <div className="recentSymbolsButtonArea">
542
- { GLOBAL_recentSymbols.length > 0 && GLOBAL_recentSymbols.length < 6 &&
543
- <span className="recentSymbols-recentText-active">Recent:</span> }
544
- { GLOBAL_recentSymbols.length === 0 &&
545
- <span className="recentSymbols-recentText-not-active">Recent:</span>}
546
- { recentButtons }
547
- </div>
548
- }
549
566
 
567
+ {/* Recent symbols button bar */}
568
+ {!this.isMobile() && (
569
+ <div className="recentSymbolsButtonArea">
570
+ {GLOBAL_recentSymbols.length > 0 &&
571
+ GLOBAL_recentSymbols.length < 6 && (
572
+ <span className="recentSymbols-recentText-active">Recent:</span>
573
+ )}
574
+ {GLOBAL_recentSymbols.length === 0 && (
575
+ <span className="recentSymbols-recentText-not-active">
576
+ Recent:
577
+ </span>
578
+ )}
579
+ {recentButtons}
580
+ </div>
581
+ )}
582
+
583
+ {/* Symbol buttons area */}
584
+ <div>
585
+ <div className="tabBar">
586
+ {tabNames.map((tab, index) => {
587
+ return (
588
+ <span key={"tabBar-" + tab}>
589
+ {this.state.selectedTab === tab ? (
590
+ <span className="tab-selected" selected={true}>
591
+ {tab}
592
+ </span>
593
+ ) : (
594
+ <span
595
+ className="tab"
596
+ onClick={(t) => this.handleSelectTab(tab)}
597
+ >
598
+ {tab}
599
+ </span>
600
+ )}{" "}
601
+ </span>
602
+ );
603
+ })}
604
+ </div>
550
605
 
551
- {/* Symbol buttons area */}
552
- <div>
553
- <div className="tabBar">
554
- { tabNames.map((tab, index) => {
555
- return (
556
- <span key={"tabBar-"+tab}>
557
- { this.state.selectedTab === tab
558
- ? <span className="tab-selected" selected={true}>{tab}</span>
559
- : <span className="tab" onClick={(t) => this.handleSelectTab(tab)}>{tab}</span>
560
- } </span>
561
- )})
562
- }
563
- </div>
564
-
565
- <div className="symbolButtonAreasOuterContainer">
566
- <div className="symbolButtonAreasInnerContainer"
567
- ref={(r) => this.symbolButtonAreasInnerContainer = r}
568
- >
569
- { buttonAreasButtons.map((button, index) => {
570
- return (
571
- <div
572
- id={buttonAreaNames[index]}
573
- key={buttonAreaNames[index]}
574
- className={"symbolButtonArea-"+buttonAreaWidths[index]}>
575
- {button}
576
- </div> )})
577
- }
606
+ <div className="symbolButtonAreasOuterContainer">
607
+ <div
608
+ className="symbolButtonAreasInnerContainer"
609
+ ref={(r) => (this.symbolButtonAreasInnerContainer = r)}
610
+ >
611
+ {buttonAreasButtons.map((button, index) => {
612
+ return (
613
+ <div
614
+ id={buttonAreaNames[index]}
615
+ key={buttonAreaNames[index]}
616
+ className={
617
+ "symbolButtonArea symbolButtonArea-" +
618
+ buttonAreaWidths[index]
619
+ }
620
+ >
621
+ {button}
622
+ </div>
623
+ );
624
+ })}
625
+ </div>
578
626
  </div>
579
627
  </div>
580
628
  </div>
581
- </div>
629
+ );
582
630
  }
583
- }
631
+ }