@zzish/math-rich-input 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -40
- package/dist/index.js +0 -2
- package/package.json +1 -1
- package/rollup.config.js +1 -1
- package/src/MathRichArea.jsx +8 -3
- package/src/MathRichInput.jsx +30 -10
- package/src/index.js +8 -4
- package/src/mathRichInputHelper.js +82 -28
- package/src/mimeTypeHelper.js +3 -0
package/README.md
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
# MathRichInput
|
|
2
2
|
|
|
3
|
-
This project is a
|
|
4
|
-
|
|
5
|
-
1. Ability to render, insert and edit equations in the input field
|
|
6
|
-
2. A toolbar that appears on focus:
|
|
7
|
-
- Buttons for bold, italic, underline, subscript and superscript
|
|
8
|
-
- Button for accents
|
|
9
|
-
- Button for inserting equations
|
|
3
|
+
This project is a `MathRichInput` component that allows users to edit a "text area" with the following key features:
|
|
10
4
|
|
|
5
|
+
1. Ability to render, insert and edit mathematical equations in the input field
|
|
6
|
+
2. A toolbar that appears on focus with:
|
|
7
|
+
- Five buttons for bold, italic, underline, subscript and superscript
|
|
8
|
+
- A button for accents and other special characters
|
|
9
|
+
- A button to bring up a WYSIWIG equation editor and insert equations
|
|
11
10
|
|
|
12
11
|
## Usage
|
|
13
12
|
|
|
@@ -71,6 +70,21 @@ export default class App extends Component {
|
|
|
71
70
|
/>
|
|
72
71
|
}
|
|
73
72
|
```
|
|
73
|
+
### Legacy usage
|
|
74
|
+
|
|
75
|
+
By default the `MathRichInput` will output content in html via the `onChange` callback method. You can force it to output tex and plain text instead using the `outputTex` and `outputPlainText` properties as follows:
|
|
76
|
+
|
|
77
|
+
```js
|
|
78
|
+
<MathRichInput
|
|
79
|
+
outputTex={true}
|
|
80
|
+
outputPlainText={true}
|
|
81
|
+
value={this.state.value}
|
|
82
|
+
mimeType={this.state.mimeType}
|
|
83
|
+
options={this.state.options}
|
|
84
|
+
onChange={this.handleInputChange}
|
|
85
|
+
/>
|
|
86
|
+
```
|
|
87
|
+
|
|
74
88
|
|
|
75
89
|
### Rendering content created using MathRichInput with MathRichArea
|
|
76
90
|
|
|
@@ -82,91 +96,106 @@ export default class App extends Component {
|
|
|
82
96
|
|
|
83
97
|
See the section on MathRichArea below for more information and alternative ways to render.
|
|
84
98
|
|
|
85
|
-
|
|
99
|
+
## Mime types
|
|
86
100
|
|
|
87
|
-
In basic usage, the MathRichInput will attempt to work out the appropriate mime type for the inital value property if supplied. However, it is good practice to explicitly set the initial mime type when it is known. For normal usage you can simply set the mime type to application/x-zzish-html-math
|
|
101
|
+
In basic usage, the `MathRichInput` will attempt to work out the appropriate mime type for the inital value property if not supplied. However, it is good practice to explicitly set the initial mime type when it is known. For normal usage of `MathRichInput` using default settings, you can simply set the mime type to `application/x-zzish-html-math`. You only need to read further if you have preexisting content in `text/plain` or `application/x-tex` mime types.
|
|
88
102
|
|
|
89
103
|
The four supported mime types are:
|
|
90
104
|
|
|
91
|
-
1. text/plain
|
|
92
|
-
2.
|
|
93
|
-
3.
|
|
94
|
-
4. application/x-
|
|
105
|
+
1. `text/plain`
|
|
106
|
+
2. `application/x-tex`
|
|
107
|
+
3. `text/html`
|
|
108
|
+
4. `application/x-zzish-html-math`
|
|
109
|
+
|
|
110
|
+
2 and 4 support math equations.
|
|
111
|
+
|
|
112
|
+
Content in the `application/x-tex` mime type contains maths in tex equation format between a pair of $ symbols, or pairs of escaped round or square brackets, `\( \)` or `\[ \]`.
|
|
113
|
+
|
|
114
|
+
Content in the `application/x-zzish-html-math` contains maths in tex equation format between a pair of `<math></math>` tags.
|
|
95
115
|
|
|
96
|
-
|
|
116
|
+
Here are examples of content in the two types:
|
|
97
117
|
|
|
98
118
|
* "Find all solutions for $x$ when $x^2 + 4x - 2 = \sqrt{9}$"
|
|
99
119
|
* "Find `<b>`all`</b>` solutions for `<math>`x`</math>` when `<math>`x^2 + 4x - 2 = \sqrt{9}`</math>`"
|
|
100
120
|
|
|
101
|
-
Note that the application/x-zzish-html-math mime type allows for text with full html formatting richness including `<p></p>`,`<b></b>`,`<i></i>`,`<u></u>`,`<sup></sup>` and `<sub></sub>` tags.
|
|
121
|
+
Note that the `application/x-zzish-html-math` mime type allows for text with full html formatting richness including `<p></p>`,`<b></b>`,`<i></i>`,`<u></u>`,`<sup></sup>` and `<sub></sub>` tags.
|
|
102
122
|
|
|
103
|
-
The MathRichInput supports the four mime types above, but the key consideration for developers is choosing witheter to set the mime-type initially to one of application/x-tex or application/x-zzish-html-math
|
|
123
|
+
The MathRichInput supports the four mime types above, but the key consideration for developers is choosing witheter to set the mime-type initially to one of `plain/text`, `application/x-tex` or `application/x-zzish-html-math`.
|
|
104
124
|
|
|
105
|
-
If your content is only ever created using this MathRichInput component, then you can safely always set the mimeType to application/x-zzish-html-math
|
|
125
|
+
If your content is only ever created using this `MathRichInput` component with default settings, then you can safely always set the mimeType to `application/x-zzish-html-math`. This is because, by default, the component will only ever output content as `text/html` or `application/x-zzish-html-math` and the `application/x-zzish-html-math` mime type is a superset of the `text/html` mime type.
|
|
106
126
|
|
|
107
|
-
If, however, you have some legacy content in tex/latex format, you should set the mimeType
|
|
127
|
+
If, however, you have some legacy content in plain text or tex/latex format, you should ideally set the mimeType as appropriate. If you are unsure as to the type of your content, then you can leave the mime type unset and the `MathRichInput` will choose the best mime-type automatically. It will generally make good choices, but it will make the wrong choice on plain text such as the following:
|
|
108
128
|
|
|
109
|
-
|
|
129
|
+
* "To bold text in html you should put the text betweeen `<b>` and `<\b>` tags"
|
|
110
130
|
|
|
111
|
-
|
|
112
|
-
2. text/html
|
|
113
|
-
3. application/x-zzish-html-math
|
|
131
|
+
In this example, the automatic detection will assume this is html, as it will identify the bold html tags. It will thus bold the word 'and'. It is not possible for the automatic detection to determine that this was in fact plain text.
|
|
114
132
|
|
|
115
|
-
|
|
133
|
+
Whatever the value and mime type of any initial content provided, the input field will always return the content in one of the two html mime types by default (via the onChange callback method):
|
|
116
134
|
|
|
117
|
-
|
|
135
|
+
1. `text/html`
|
|
136
|
+
3. `application/x-zzish-html-math`
|
|
118
137
|
|
|
119
|
-
|
|
138
|
+
These mime types should ideally be stored along with the value and supplied back to the `MathRichInput` and `MathRichArea` in future.
|
|
139
|
+
|
|
140
|
+
If you desire the output to be `tex\latex`, then pass the parameter `outputTex={true}`. When you choose to output in tex, font styling (eg. bold) and multiline are disabled for users.
|
|
141
|
+
|
|
142
|
+
By default, any output content that does not contain multiple lines (i.e. `<p></p>` tags), any html font styling (e.g. `<b></b>`), or any math elements will still be returned as `text\html` and any special html characters will be converted to their html codings (for example `<` will be converted to `>`). If required you can choose to have content that does not need any html or math formatting returned as plain text using `outputPlainText={true}`.
|
|
143
|
+
|
|
144
|
+
In general, unless you have a *very* good reason to, you should not set `outputTex={true}` or `outputPlainText={true}` and you should have your content returned as html (`text/html`) or html math (`application/x-zzish-html-math`) as happens with the default settings.
|
|
145
|
+
|
|
146
|
+
## Options
|
|
120
147
|
|
|
121
148
|
The options property is used to return the current state of the equation editor so that if the user closes and reopens the equation editor, the state is remembered. In particular it allows you to store whether the user:
|
|
122
149
|
|
|
123
150
|
* Is using the equation editor in expert mode
|
|
124
|
-
* Has selected a specific
|
|
151
|
+
* Has selected a specific symbols tab
|
|
125
152
|
|
|
126
153
|
Note that normally options should be a global object with the same options used across all input fields. This is so that the user does not need to reselect expert mode and/or select the same tab each time they reopen the equation editor.
|
|
127
154
|
|
|
128
|
-
The options property can be
|
|
155
|
+
The options property can be initialised to null rather than set explicitly as above. The options can be saved against the user's persistent user settings if desired.
|
|
129
156
|
|
|
130
157
|
#### Other properties
|
|
131
158
|
|
|
132
159
|
##### enableFontStyling
|
|
133
160
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
Set enableFontStyling={false} to:
|
|
161
|
+
Set `enableFontStyling={false}` to:
|
|
137
162
|
|
|
138
163
|
* Disable the bold, italic, underline, subscript and superscript buttons on the toolbar
|
|
139
164
|
* Disalbe CTRL-B and other font styling hot keys
|
|
140
165
|
|
|
141
166
|
##### enableMultiline
|
|
142
167
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
Set enableMultiline={false} to:
|
|
168
|
+
Set `enableMultiline={false}` to:
|
|
146
169
|
|
|
147
170
|
* Disable new lines being entered by pressing the return key
|
|
148
171
|
|
|
149
172
|
##### enableMath
|
|
150
173
|
|
|
151
|
-
Set enableMath={false} to:
|
|
174
|
+
Set `enableMath={false}` to:
|
|
152
175
|
|
|
153
176
|
* Disable the equation editor button on the toolbar
|
|
154
177
|
|
|
155
178
|
##### outputTex
|
|
156
179
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
Set outputTex={true} to:
|
|
180
|
+
Set `outputTex={true}` to:
|
|
160
181
|
|
|
161
182
|
* Force output to be in tex (math equations are enclosed in a pair of $ symbols)
|
|
162
183
|
|
|
163
|
-
As a side effect, this also implicitly sets enableMultiline and enableFontStyling to false (see above).
|
|
184
|
+
As a side effect, this also implicitly sets `enableMultiline` and `enableFontStyling` to false (see above).
|
|
185
|
+
|
|
186
|
+
##### outputPlainText
|
|
187
|
+
|
|
188
|
+
Set `outputPlainText={true}` to:
|
|
189
|
+
|
|
190
|
+
* Force output to be in plain text when the input text contains no html and no maths
|
|
191
|
+
|
|
192
|
+
Note that this does not disable multiline or font styling
|
|
164
193
|
|
|
165
194
|
##### editable
|
|
166
195
|
|
|
167
196
|
(not yet implemented)
|
|
168
197
|
|
|
169
|
-
Set editable={false} to purely render the value and not allow it to be edited by the user. Note that normally you would use the non-editable MathRichArea component to purely render values (it is a much lighter component).
|
|
198
|
+
Set `editable={false}` to purely render the value and not allow it to be edited by the user. Note that normally you would use the non-editable MathRichArea component to purely render values (it is a much lighter component).
|
|
170
199
|
|
|
171
200
|
## MathRichArea
|
|
172
201
|
|
|
@@ -187,7 +216,7 @@ For example, assuming that you had a page containing some content:
|
|
|
187
216
|
<div className="question">{this.state.questionText}</div>
|
|
188
217
|
<div className="answer">{this.state.answerText}</div>
|
|
189
218
|
```
|
|
190
|
-
where the question and answer text was simple text in
|
|
219
|
+
where the question and answer text was simple text in any one of the four supported mime types.
|
|
191
220
|
|
|
192
221
|
Simply add the following code:
|
|
193
222
|
|
package/dist/index.js
CHANGED
|
@@ -23031,6 +23031,4 @@ var MathRichArea = /*#__PURE__*/function (_React$Component) {
|
|
|
23031
23031
|
return MathRichArea;
|
|
23032
23032
|
}(React.Component);
|
|
23033
23033
|
|
|
23034
|
-
console.log("hello charles");
|
|
23035
|
-
|
|
23036
23034
|
export { MathRichArea, MathRichInput, renderMathInNode };
|
package/package.json
CHANGED
package/rollup.config.js
CHANGED
package/src/MathRichArea.jsx
CHANGED
|
@@ -3,7 +3,7 @@ import React from 'react'
|
|
|
3
3
|
import katex from "katex";
|
|
4
4
|
import {setupKatex} from "./katexHelper"
|
|
5
5
|
import {rawTextToHtml} from './mathRichInputHelper'
|
|
6
|
-
import {MIME_TYPE_TEX, MIME_TYPE_HTML, MIME_TYPE_ZZISH_HTML_MATH,
|
|
6
|
+
import {MIME_TYPE_TEX, MIME_TYPE_HTML, MIME_TYPE_ZZISH_HTML_MATH,
|
|
7
7
|
isTextLatexMath, isTextHtml, isTextHtmlMath} from './mimeTypeHelper'
|
|
8
8
|
|
|
9
9
|
|
|
@@ -96,8 +96,13 @@ export default class MathRichArea extends React.Component {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
render() {
|
|
99
|
-
|
|
99
|
+
// console.log("Mime type: "+this.props.mimeType)
|
|
100
|
+
let html = rawTextToHtml(katex, this.props.children, this.props.mimeType)
|
|
101
|
+
// console.log("html: "+html)
|
|
100
102
|
|
|
101
103
|
return <span dangerouslySetInnerHTML={{__html: html}}></span>
|
|
102
104
|
}
|
|
103
|
-
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
package/src/MathRichInput.jsx
CHANGED
|
@@ -9,6 +9,7 @@ import Toolbar from './Toolbar'
|
|
|
9
9
|
import {
|
|
10
10
|
isKatexNode,
|
|
11
11
|
elementToMarkedRawText,
|
|
12
|
+
removeEncodingIfPlainText,
|
|
12
13
|
rawTextToHtml,
|
|
13
14
|
getLatex,
|
|
14
15
|
setRangeParams,
|
|
@@ -147,18 +148,23 @@ export default class MathRichInput extends React.Component {
|
|
|
147
148
|
// /<\s*sub[^>]*>(.*?)<\s*\/\s*sub\s*>/i.test(text)
|
|
148
149
|
// }
|
|
149
150
|
|
|
150
|
-
getMimeType(
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
} else {
|
|
157
|
-
if (hasMath)
|
|
151
|
+
getMimeType(hasHtml, hasMath) {
|
|
152
|
+
let outputTex = this.props.outputTex ?? false
|
|
153
|
+
let outputPlainText = this.props.outputPlainText ?? false
|
|
154
|
+
|
|
155
|
+
if (outputTex) {
|
|
156
|
+
if (hasMath || !outputPlainText)
|
|
158
157
|
return MIME_TYPE_TEX
|
|
159
158
|
else
|
|
160
159
|
return MIME_TYPE_PLAIN_TEXT
|
|
161
|
-
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (hasMath)
|
|
163
|
+
return MIME_TYPE_ZZISH_HTML_MATH
|
|
164
|
+
if (hasHtml || !outputPlainText)
|
|
165
|
+
return MIME_TYPE_HTML
|
|
166
|
+
|
|
167
|
+
return MIME_TYPE_PLAIN_TEXT
|
|
162
168
|
}
|
|
163
169
|
|
|
164
170
|
_countNodeTypes = () => {
|
|
@@ -420,6 +426,7 @@ export default class MathRichInput extends React.Component {
|
|
|
420
426
|
|
|
421
427
|
let nodeCounts = this._countNodeTypes()
|
|
422
428
|
let mimeType = this.getMimeType(nodeCounts.html > 0, nodeCounts.math > 0)
|
|
429
|
+
raw_text = removeEncodingIfPlainText(raw_text, mimeType, this.enableHtml())
|
|
423
430
|
|
|
424
431
|
this.applyChangesToComponent(raw_text, mimeType, new_rangeParams,
|
|
425
432
|
this.props.useExpertMode, this.props.selectedTab)
|
|
@@ -697,6 +704,7 @@ export default class MathRichInput extends React.Component {
|
|
|
697
704
|
|
|
698
705
|
let nodeCounts = this._countNodeTypes()
|
|
699
706
|
let mimeType = this.getMimeType(nodeCounts.html > 0, true)
|
|
707
|
+
raw_text = removeEncodingIfPlainText(raw_text, mimeType, this.enableHtml())
|
|
700
708
|
|
|
701
709
|
this.applyChangesToComponent(raw_text,
|
|
702
710
|
mimeType,
|
|
@@ -991,7 +999,7 @@ export default class MathRichInput extends React.Component {
|
|
|
991
999
|
handleInput = (event) => {
|
|
992
1000
|
try {
|
|
993
1001
|
// console.log("handleInput")
|
|
994
|
-
|
|
1002
|
+
let raw_text = elementToMarkedRawText(this.editableDiv, null, 0, this.enableHtml())
|
|
995
1003
|
const params = this._getRangeParams()
|
|
996
1004
|
if (params === null || params === undefined)
|
|
997
1005
|
console.error("Could not get range params from input field")
|
|
@@ -1004,6 +1012,8 @@ export default class MathRichInput extends React.Component {
|
|
|
1004
1012
|
|
|
1005
1013
|
let nodeCounts = this._countNodeTypes()
|
|
1006
1014
|
let mimeType = this.getMimeType(nodeCounts.html > 0, nodeCounts.math > 0)
|
|
1015
|
+
raw_text = removeEncodingIfPlainText(raw_text, mimeType, this.enableHtml())
|
|
1016
|
+
|
|
1007
1017
|
this.applyChangesToComponent(raw_text, mimeType, params,
|
|
1008
1018
|
this.props.useExpertMode, this.props.selectedTab)
|
|
1009
1019
|
} catch (error) {
|
|
@@ -1305,6 +1315,7 @@ export default class MathRichInput extends React.Component {
|
|
|
1305
1315
|
mimeType = this.getMimeType(nodeCounts.html > 0, nodeCounts.katex > 1)
|
|
1306
1316
|
else
|
|
1307
1317
|
mimeType = this.getMimeType(nodeCounts.html > 0, nodeCounts.katex > 0)
|
|
1318
|
+
new_raw_text = removeEncodingIfPlainText(new_raw_text, mimeType, this.enableHtml())
|
|
1308
1319
|
|
|
1309
1320
|
this.applyChangesToComponent(new_raw_text, mimeType, new_rangeParams,
|
|
1310
1321
|
this.props.useExpertMode, this.props.selectedTab)
|
|
@@ -1346,6 +1357,7 @@ export default class MathRichInput extends React.Component {
|
|
|
1346
1357
|
|
|
1347
1358
|
let nodeCounts = this._countNodeTypes()
|
|
1348
1359
|
let mimeType = this.getMimeType(nodeCounts.html > 0, true)
|
|
1360
|
+
new_raw_text = removeEncodingIfPlainText(new_raw_text, mimeType, this.enableHtml())
|
|
1349
1361
|
|
|
1350
1362
|
this.applyChangesToComponent(new_raw_text, mimeType, new_rangeParams,
|
|
1351
1363
|
this.props.useExpertMode, this.props.selectedTab)
|
|
@@ -1430,6 +1442,8 @@ export default class MathRichInput extends React.Component {
|
|
|
1430
1442
|
new_rangeParams.startOffset = new_rangeParams.startOffset + new_text.length
|
|
1431
1443
|
new_rangeParams.endOffset = new_rangeParams.endOffset + new_text.length
|
|
1432
1444
|
|
|
1445
|
+
new_raw_text = removeEncodingIfPlainText(new_raw_text, this.state.mimeType, this.enableHtml())
|
|
1446
|
+
|
|
1433
1447
|
this.applyChangesToComponent(new_raw_text, this.state.mimeType, new_rangeParams,
|
|
1434
1448
|
this.props.useExpertMode, this.props.selectedTab)
|
|
1435
1449
|
} catch (error) {
|
|
@@ -1460,6 +1474,8 @@ export default class MathRichInput extends React.Component {
|
|
|
1460
1474
|
console.log("Old nodes")
|
|
1461
1475
|
console.log(this.editableDiv.childNodes)
|
|
1462
1476
|
|
|
1477
|
+
new_raw_text = removeEncodingIfPlainText(new_raw_text, this.state.mimeType, this.enableHtml())
|
|
1478
|
+
|
|
1463
1479
|
this.applyChangesToComponent(new_raw_text, this.state.mimeType, new_rangeParams,
|
|
1464
1480
|
this.props.useExpertMode, this.props.selectedTab)
|
|
1465
1481
|
} catch (error) {
|
|
@@ -1498,6 +1514,8 @@ export default class MathRichInput extends React.Component {
|
|
|
1498
1514
|
console.log("Old nodes")
|
|
1499
1515
|
console.log(this.editableDiv.childNodes)
|
|
1500
1516
|
|
|
1517
|
+
new_raw_text = removeEncodingIfPlainText(new_raw_text, this.state.mimeType, this.enableHtml())
|
|
1518
|
+
|
|
1501
1519
|
this.applyChangesToComponent(new_raw_text, this.state.mimeType, new_rangeParams,
|
|
1502
1520
|
this.props.useExpertMode, this.props.selectedTab)
|
|
1503
1521
|
} catch (error) {
|
|
@@ -1521,6 +1539,7 @@ export default class MathRichInput extends React.Component {
|
|
|
1521
1539
|
new_rangeParams.startOffset = new_rangeParams.startOffset + new_char.length + 1
|
|
1522
1540
|
new_rangeParams.endOffset = new_rangeParams.endOffset + new_char.length + 1
|
|
1523
1541
|
|
|
1542
|
+
new_raw_text = removeEncodingIfPlainText(new_raw_text, this.state.mimeType, this.enableHtml())
|
|
1524
1543
|
this.applyChangesToComponent(new_raw_text, this.state.mimeType, new_rangeParams,
|
|
1525
1544
|
this.props.useExpertMode, this.props.selectedTab)
|
|
1526
1545
|
} catch (error) {
|
|
@@ -1547,6 +1566,7 @@ export default class MathRichInput extends React.Component {
|
|
|
1547
1566
|
else
|
|
1548
1567
|
new_raw_text = removeMarks(replaceCharacterBeforeMarks(raw_text, new_char))
|
|
1549
1568
|
|
|
1569
|
+
new_raw_text = removeEncodingIfPlainText(new_raw_text, this.state.mimeType, this.enableHtml())
|
|
1550
1570
|
this.applyChangesToComponent(new_raw_text, this.state.mimeType, new_rangeParams,
|
|
1551
1571
|
this.props.useExpertMode, this.props.selectedTab)
|
|
1552
1572
|
} catch (error) {
|
package/src/index.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import MathRichInput from "./MathRichInput";
|
|
2
|
+
import MathRichArea from "./MathRichArea";
|
|
3
|
+
import { renderMathInNode } from "./MathRichArea";
|
|
5
4
|
|
|
5
|
+
export {
|
|
6
|
+
MathRichInput,
|
|
7
|
+
MathRichArea,
|
|
8
|
+
renderMathInNode
|
|
9
|
+
}
|
|
@@ -1,22 +1,34 @@
|
|
|
1
1
|
import { determineMimeType } from './mimeTypeHelper'
|
|
2
2
|
|
|
3
|
-
export const RAW_TEXT_MATH_START_TAG_TEX = "
|
|
4
|
-
export const RAW_TEXT_MATH_END_TAG_TEX = "
|
|
3
|
+
export const RAW_TEXT_MATH_START_TAG_TEX = "\\["
|
|
4
|
+
export const RAW_TEXT_MATH_END_TAG_TEX = "\\]"
|
|
5
5
|
export const RAW_TEXT_MATH_START_TAG_HTML_MATH = "<math>"
|
|
6
6
|
export const RAW_TEXT_MATH_END_TAG_HTML_MATH = "</math>"
|
|
7
7
|
|
|
8
8
|
const INLINE_TEX_REG_EXP = /\$\$[\s\S]+?\$\$|\\\[[\s\S]+?\\\]|\\\([\s\S]+?\\\)|\$[^$\\]*(?:\\.[^$\\]*)*\$/g;
|
|
9
9
|
const BLOCK_TEX_REG_EXP = /\$\$[\s\S]+?\$\$|\\\[[\s\S]+?\\\]/g;
|
|
10
10
|
|
|
11
|
+
// const INLINE_TEX_REG_EXP = /(?<!\\)\$[\s\S]+?(?<!\\)\$/g
|
|
12
|
+
|
|
13
|
+
// In general, (?<!Y)X matches an X that is not preceded by a Y. so (?<!\\)\$
|
|
14
|
+
|
|
15
|
+
// const INLINE_TEX_REG_EXP = /(?<!\\)(?:((?<!\$)\${1,2}(?!\$))|(\\\()|(\\\[)|(\\begin\{equation\}))(?(1)(.*?)(?<!\\)(?<!\$)\1(?!\$)|(?:(.*(?R)?.*)(?<!\\)(?:(?(2)\\\)|(?(3)\\\]|\\end\{equation\})))))/
|
|
16
|
+
|
|
17
|
+
|
|
11
18
|
// const HTML_MATH_REG_EXP = /<math>.*?<\/math>/gi;
|
|
12
19
|
const HTML_MATH_REG_EXP = /<math>[\s\S]*?<\/math>/gi;
|
|
13
20
|
|
|
14
21
|
const SPAN_OPEN_BASE = "<span class=\"base\">"
|
|
15
22
|
const SPAN_CLOSE = "</span>"
|
|
16
23
|
|
|
17
|
-
const MARK =
|
|
24
|
+
const MARK = String.fromCharCode(0)
|
|
25
|
+
// const MARK = "_M_A_R_K_"
|
|
18
26
|
const MARK_REG_EXP = new RegExp(MARK, "g")
|
|
19
27
|
|
|
28
|
+
const TEMP_CHAR = String.fromCharCode(1)
|
|
29
|
+
const TEMP_CHAR_REG_EXP = new RegExp(TEMP_CHAR, "g")
|
|
30
|
+
const DOLLAR_SLASH_REG_EXP = /\\\$/g
|
|
31
|
+
|
|
20
32
|
const SMALL_SPACE_CHAR_CODE = 8203
|
|
21
33
|
const SMALL_SPACE = String.fromCharCode(SMALL_SPACE_CHAR_CODE)
|
|
22
34
|
const SMALL_SPACE_REG_EXP = new RegExp(SMALL_SPACE, "g")
|
|
@@ -195,7 +207,6 @@ export function getLatex(node) {
|
|
|
195
207
|
// <annotation encoding="application/x-tex">L' = {L}{\sqrt{1-\frac{v^2}{c^2}}}</annotation>
|
|
196
208
|
let annotation = getFirstDescendentByTagName(node, "annotation")
|
|
197
209
|
let latex = annotation.childNodes[0].nodeValue
|
|
198
|
-
latex = decodeLatex(latex)
|
|
199
210
|
return latex
|
|
200
211
|
} catch (error) {
|
|
201
212
|
console.error(error)
|
|
@@ -211,7 +222,7 @@ function encodeToHtml(text) {
|
|
|
211
222
|
text = text.replace(/</g,"<")
|
|
212
223
|
text = text.replace(/'/g,"'")
|
|
213
224
|
text = text.replace(/"/g,""")
|
|
214
|
-
text = text.replace(/\$/g,"$")
|
|
225
|
+
text = text.replace(/\$/g,"$")
|
|
215
226
|
return text
|
|
216
227
|
}
|
|
217
228
|
|
|
@@ -247,38 +258,57 @@ var decodeFromHtml = (function() {
|
|
|
247
258
|
// }
|
|
248
259
|
|
|
249
260
|
// Note we don't need to encode it so do nothing here
|
|
250
|
-
function
|
|
261
|
+
function encodeToLatex(text) {
|
|
251
262
|
// console.log("Pre-encoded: "+text)
|
|
263
|
+
text = text.replace(/\$/g,"\\$")
|
|
252
264
|
// console.log("Post-encoded: "+text)
|
|
253
265
|
return text
|
|
254
266
|
}
|
|
255
267
|
|
|
256
268
|
// Note we don't need to decode it so do nothing here
|
|
257
|
-
function
|
|
269
|
+
function decodeFromLatex(text) {
|
|
258
270
|
// console.log("Pre-decoded: "+text)
|
|
271
|
+
text = text.replace(/\\\$/g,"$")
|
|
259
272
|
// console.log("Post-decoded: "+text)
|
|
260
273
|
return text
|
|
261
274
|
}
|
|
262
275
|
|
|
263
|
-
function
|
|
276
|
+
export function removeEncodingIfPlainText(text, mimeType, useHtmlMath) {
|
|
277
|
+
if (mimeType !== MIME_TYPE_PLAIN_TEXT)
|
|
278
|
+
return text
|
|
279
|
+
|
|
280
|
+
if (useHtmlMath)
|
|
281
|
+
return decodeFromHtml(text)
|
|
282
|
+
else
|
|
283
|
+
return decodeFromLatex(text)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function addText(arrayOfText, text, mark, offset, useHtmlMath=true) {
|
|
264
287
|
// console.log("Mark: "+mark)
|
|
265
288
|
if (offset === 0) {
|
|
266
289
|
if (mark) {
|
|
267
290
|
arrayOfText.push(MARK)
|
|
268
|
-
// arrayOfText.push(" ")
|
|
269
291
|
arrayOfText.push(MARK)
|
|
270
292
|
}
|
|
271
293
|
arrayOfText.push(text)
|
|
272
294
|
} else {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
295
|
+
if (useHtmlMath) {
|
|
296
|
+
let decoded = decodeFromHtml(text)
|
|
297
|
+
arrayOfText.push(encodeToHtml(decoded.substring(0,offset)))
|
|
298
|
+
if (mark) {
|
|
299
|
+
arrayOfText.push(MARK)
|
|
300
|
+
arrayOfText.push(MARK)
|
|
301
|
+
}
|
|
302
|
+
arrayOfText.push(encodeToHtml(decoded.substring(offset)))
|
|
303
|
+
} else {
|
|
304
|
+
let decoded = decodeFromLatex(text)
|
|
305
|
+
arrayOfText.push(encodeToLatex(decoded.substring(0,offset)))
|
|
306
|
+
if (mark) {
|
|
307
|
+
arrayOfText.push(MARK)
|
|
308
|
+
arrayOfText.push(MARK)
|
|
309
|
+
}
|
|
310
|
+
arrayOfText.push(encodeToLatex(decoded.substring(offset)))
|
|
280
311
|
}
|
|
281
|
-
arrayOfText.push(encodeToHtml(decoded.substring(offset)))
|
|
282
312
|
}
|
|
283
313
|
}
|
|
284
314
|
|
|
@@ -291,7 +321,7 @@ function addTextForNode(node, arrayOfText, nodeToMark=null, offset=0, useHtmlMat
|
|
|
291
321
|
try {
|
|
292
322
|
if (isTextNode(node)) {
|
|
293
323
|
addText(arrayOfText,
|
|
294
|
-
useHtmlMath ? encodeToHtml(node.nodeValue) : node.nodeValue,
|
|
324
|
+
useHtmlMath ? encodeToHtml(node.nodeValue) : encodeToLatex(node.nodeValue),
|
|
295
325
|
mark, offset, useHtmlMath)
|
|
296
326
|
} else if (isBrNode(node)) {
|
|
297
327
|
useHtmlMath && arrayOfText.push("<br>")
|
|
@@ -305,7 +335,7 @@ function addTextForNode(node, arrayOfText, nodeToMark=null, offset=0, useHtmlMat
|
|
|
305
335
|
if (mark)
|
|
306
336
|
arrayOfText.push(MARK)
|
|
307
337
|
arrayOfText.push(useHtmlMath ? RAW_TEXT_MATH_START_TAG_HTML_MATH : RAW_TEXT_MATH_START_TAG_TEX)
|
|
308
|
-
arrayOfText.push(
|
|
338
|
+
arrayOfText.push(getLatex(node))
|
|
309
339
|
arrayOfText.push(useHtmlMath ? RAW_TEXT_MATH_END_TAG_HTML_MATH : RAW_TEXT_MATH_END_TAG_TEX)
|
|
310
340
|
if (mark)
|
|
311
341
|
arrayOfText.push(MARK)
|
|
@@ -350,7 +380,9 @@ export function elementToMarkedRawText(element, nodeToMark=null, offset=0, useHt
|
|
|
350
380
|
|
|
351
381
|
// remove any zero-width spaces we added to the html
|
|
352
382
|
raw_text = raw_text.replace(SMALL_SPACE_REG_EXP,'')
|
|
353
|
-
|
|
383
|
+
|
|
384
|
+
console.log("Marked raw text: " + raw_text)
|
|
385
|
+
|
|
354
386
|
return raw_text
|
|
355
387
|
}
|
|
356
388
|
|
|
@@ -444,23 +476,38 @@ export function rawTextToHtml(katex, string, mimeType) {
|
|
|
444
476
|
mimeType = determineMimeType(string)
|
|
445
477
|
|
|
446
478
|
if (mimeType === MIME_TYPE_PLAIN_TEXT)
|
|
447
|
-
return string
|
|
479
|
+
return encodeToHtml(string)
|
|
448
480
|
|
|
449
|
-
let parseAsTex
|
|
450
|
-
if (mimeType === MIME_TYPE_TEX ||
|
|
481
|
+
let parseAsTex
|
|
482
|
+
if (mimeType === MIME_TYPE_TEX ||
|
|
483
|
+
mimeType === MIME_TYPE_LATEX)
|
|
451
484
|
parseAsTex = true
|
|
452
|
-
if (
|
|
485
|
+
else if (mimeType === MIME_TYPE_HTML ||
|
|
486
|
+
mimeType === MIME_TYPE_ZZISH_HTML_MATH)
|
|
487
|
+
parseAsTex = false
|
|
488
|
+
else {
|
|
489
|
+
parseAsTex = false
|
|
453
490
|
console.error("Unknown mime type: "+mimeType)
|
|
454
491
|
}
|
|
455
492
|
|
|
493
|
+
// console.log("Original string: "+string)
|
|
494
|
+
if (parseAsTex)
|
|
495
|
+
string = string.replace(DOLLAR_SLASH_REG_EXP, TEMP_CHAR)
|
|
496
|
+
// console.log("Modded string: "+string)
|
|
497
|
+
|
|
456
498
|
const stringElements = string.split(parseAsTex ? INLINE_TEX_REG_EXP : HTML_MATH_REG_EXP);
|
|
457
499
|
|
|
458
500
|
// Insert small space at start of first element if it is an empty element
|
|
459
501
|
if (stringElements[0] === "") // This means the original string stars with latex
|
|
460
502
|
stringElements[0] = "&#" + SMALL_SPACE.charCodeAt(0)
|
|
461
503
|
|
|
462
|
-
|
|
463
|
-
|
|
504
|
+
if (parseAsTex) {
|
|
505
|
+
for (let i = 0; i <stringElements.length; i++) {
|
|
506
|
+
stringElements[i] = stringElements[i].replace(TEMP_CHAR_REG_EXP, "$")
|
|
507
|
+
stringElements[i] = encodeToHtml(stringElements[i])
|
|
508
|
+
}
|
|
509
|
+
} else {
|
|
510
|
+
// Insert small space at end of <p></p> elements so that empty lines get rendered
|
|
464
511
|
for (let i = 0; i <stringElements.length; i++)
|
|
465
512
|
stringElements[i] = stringElements[i].replace(P_TAG_REG_EXP, P_ELEMENT_SMALL_SPACE)
|
|
466
513
|
}
|
|
@@ -476,8 +523,15 @@ export function rawTextToHtml(katex, string, mimeType) {
|
|
|
476
523
|
|
|
477
524
|
if (latexElements[i]) {
|
|
478
525
|
let element = latexElements[i]
|
|
479
|
-
|
|
480
|
-
|
|
526
|
+
let type
|
|
527
|
+
if (parseAsTex) {
|
|
528
|
+
type = getDisplayType(element)
|
|
529
|
+
element = stripDollars(element)
|
|
530
|
+
element = element.replace(TEMP_CHAR_REG_EXP, "\\$")
|
|
531
|
+
} else {
|
|
532
|
+
type = "inline"
|
|
533
|
+
element = stripTags(element)
|
|
534
|
+
}
|
|
481
535
|
|
|
482
536
|
let renderedElement = renderLatexString(katex, element, type)
|
|
483
537
|
renderedElement = renderedElement + "&#"+SMALL_SPACE.charCodeAt(0)
|