@wiris/mathtype-ckeditor5 8.9.1 → 8.9.2
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 +70 -68
- package/package.json +2 -2
- package/src/commands.js +17 -13
- package/src/integration.js +83 -86
- package/src/plugin.js +157 -147
package/README.md
CHANGED
|
@@ -1,68 +1,70 @@
|
|
|
1
|
-
MathType for CKEditor 5 [](https://twitter.com/wirismath)
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
- [
|
|
11
|
-
- [
|
|
12
|
-
- [
|
|
13
|
-
- [
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
'
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
```html
|
|
54
|
-
<script src="https://www.wiris.net/demo/plugins/app/WIRISplugins.js?viewer=image"></script>
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
## Documentation
|
|
58
|
-
|
|
59
|
-
To find out more information about MathType, please go to the following documentation:
|
|
60
|
-
|
|
61
|
-
[comment]: <> (TODO: link to install instructions)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
1
|
+
# MathType for CKEditor 5 [](https://twitter.com/wirismath)
|
|
2
|
+
|
|
3
|
+
Type and handwrite mathematical notation with MathType.
|
|
4
|
+
|
|
5
|
+
Easily include quality math equations in your documents and digital content.
|
|
6
|
+
|
|
7
|
+
# Table of Contents
|
|
8
|
+
|
|
9
|
+
- [Install instructions](#install-instructions)
|
|
10
|
+
- [Services](#services)
|
|
11
|
+
- [Documentation](#documentation)
|
|
12
|
+
- [Displaying on Target Page](#displaying-on-target-page)
|
|
13
|
+
- [Privacy policy](#privacy-policy)
|
|
14
|
+
|
|
15
|
+
## Install instructions
|
|
16
|
+
|
|
17
|
+
1. Install the npm module:
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
npm install @wiris/mathtype-ckeditor5
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
2. Update the CKEditor configuration by adding the new plugin and including the MathType and ChemType buttons:
|
|
24
|
+
|
|
25
|
+
```js
|
|
26
|
+
import MathType from '@wiris/mathtype-ckeditor5/src/plugin';
|
|
27
|
+
|
|
28
|
+
...
|
|
29
|
+
|
|
30
|
+
ClassicEditor
|
|
31
|
+
.create( editorElement, {
|
|
32
|
+
plugins: [ ..., MathType, ... ],
|
|
33
|
+
toolbar: {
|
|
34
|
+
items: [
|
|
35
|
+
...
|
|
36
|
+
'MathType',
|
|
37
|
+
'ChemType',
|
|
38
|
+
...
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Services
|
|
44
|
+
|
|
45
|
+
This npm module uses remotely hosted services to render MathML data. In case of wanting to install these services on your own backend, please contact <support@wiris.com>.
|
|
46
|
+
|
|
47
|
+
[comment]: <> (TODO: fill this section when the documentation is ready)
|
|
48
|
+
|
|
49
|
+
## Displaying on Target Page
|
|
50
|
+
|
|
51
|
+
In order to display mathematical formulas on the target page, i.e. the page where content produced by the HTML editor will be visible, the target page needs to include the [MathType script](https://docs.wiris.com/en/mathtype/mathtype_web/integrations/mathml-mode#add_a_script_to_head). For example for the default setting this would be:
|
|
52
|
+
|
|
53
|
+
```html
|
|
54
|
+
<script src="https://www.wiris.net/demo/plugins/app/WIRISplugins.js?viewer=image"></script>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Documentation
|
|
58
|
+
|
|
59
|
+
To find out more information about MathType, please go to the following documentation:
|
|
60
|
+
|
|
61
|
+
[comment]: <> (TODO: link to install instructions)
|
|
62
|
+
|
|
63
|
+
- [MathType documentation](https://docs.wiris.com/en/mathtype/mathtype_web/start?utm_source=npmjs&utm_medium=referral)
|
|
64
|
+
- [Introductory tutorials](https://docs.wiris.com/en/mathtype/mathtype_web/intro_tutorials?utm_source=npmjs&utm_medium=referral)
|
|
65
|
+
- [Service customization](https://docs.wiris.com/en/mathtype/mathtype_web/integrations/config-table?utm_source=npmjs&utm_medium=referral)
|
|
66
|
+
- [Testing](https://docs.wiris.com/en/mathtype/mathtype_web/integrations/html/plugins-test?utm_source=npmjs&utm_medium=referral)
|
|
67
|
+
|
|
68
|
+
## Privacy policy
|
|
69
|
+
|
|
70
|
+
The [MathType Privacy Policy](https://www.wiris.com/en/mathtype-privacy-policy/?utm_source=npmjs&utm_medium=referral) covers the data processing operations for the MathType users. It is an addendum of the company’s general Privacy Policy and the [general Privacy Policy](https://www.wiris.com/en/privacy-policy?utm_source=npmjs&utm_medium=referral) still applies to MathType users.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wiris/mathtype-ckeditor5",
|
|
3
|
-
"version": "8.9.
|
|
3
|
+
"version": "8.9.2",
|
|
4
4
|
"description": "MathType Web for CKEditor5 editor",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"chem",
|
|
@@ -39,6 +39,6 @@
|
|
|
39
39
|
"@ckeditor/ckeditor5-engine": ">=27.0.0",
|
|
40
40
|
"@ckeditor/ckeditor5-ui": ">=27.0.0",
|
|
41
41
|
"@ckeditor/ckeditor5-widget": ">=27.0.0",
|
|
42
|
-
"@wiris/mathtype-html-integration-devkit": "1.17.
|
|
42
|
+
"@wiris/mathtype-html-integration-devkit": "1.17.2"
|
|
43
43
|
}
|
|
44
44
|
}
|
package/src/commands.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable max-classes-per-file */
|
|
2
|
-
import Command from
|
|
3
|
-
import CKEditor5Integration from
|
|
2
|
+
import Command from "@ckeditor/ckeditor5-core/src/command";
|
|
3
|
+
import CKEditor5Integration from "./integration";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Command for opening the MathType editor
|
|
@@ -9,7 +9,7 @@ export class MathTypeCommand extends Command {
|
|
|
9
9
|
execute(options = {}) {
|
|
10
10
|
// Check we get a valid integration
|
|
11
11
|
// eslint-disable-next-line no-prototype-builtins
|
|
12
|
-
if (!options.hasOwnProperty(
|
|
12
|
+
if (!options.hasOwnProperty("integration") || !(options.integration instanceof CKEditor5Integration)) {
|
|
13
13
|
throw 'Must pass a valid CKEditor5Integration instance as attribute "integration" of options';
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -24,8 +24,8 @@ export class MathTypeCommand extends Command {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
* Sets the appropriate custom editor, if any, or disables them.
|
|
28
|
+
*/
|
|
29
29
|
setEditor() {
|
|
30
30
|
// It's possible that a custom editor was last used.
|
|
31
31
|
// We need to disable it to avoid wrong behaviors.
|
|
@@ -33,12 +33,16 @@ export class MathTypeCommand extends Command {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
* Checks whether we are editing an existing formula or a new one and opens the editor.
|
|
37
|
+
*/
|
|
38
38
|
openEditor() {
|
|
39
39
|
this.integration.core.editionProperties.dbclick = false;
|
|
40
40
|
const image = this._getSelectedImage();
|
|
41
|
-
if (
|
|
41
|
+
if (
|
|
42
|
+
typeof image !== "undefined" &&
|
|
43
|
+
image !== null &&
|
|
44
|
+
image.classList.contains(WirisPlugin.Configuration.get("imageClassName"))
|
|
45
|
+
) {
|
|
42
46
|
this.integration.core.editionProperties.temporalImage = image;
|
|
43
47
|
this.integration.openExistingFormulaEditor();
|
|
44
48
|
} else {
|
|
@@ -47,9 +51,9 @@ export class MathTypeCommand extends Command {
|
|
|
47
51
|
}
|
|
48
52
|
|
|
49
53
|
/**
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
54
|
+
* Gets the currently selected formula image
|
|
55
|
+
* @returns {Element} selected image, if any, undefined otherwise
|
|
56
|
+
*/
|
|
53
57
|
_getSelectedImage() {
|
|
54
58
|
const { selection } = this.editor.editing.view.document;
|
|
55
59
|
|
|
@@ -65,7 +69,7 @@ export class MathTypeCommand extends Command {
|
|
|
65
69
|
let image;
|
|
66
70
|
|
|
67
71
|
for (const span of range) {
|
|
68
|
-
if (span.item.name !==
|
|
72
|
+
if (span.item.name !== "span") {
|
|
69
73
|
return;
|
|
70
74
|
}
|
|
71
75
|
image = span.item.getChild(0);
|
|
@@ -86,6 +90,6 @@ export class MathTypeCommand extends Command {
|
|
|
86
90
|
*/
|
|
87
91
|
export class ChemTypeCommand extends MathTypeCommand {
|
|
88
92
|
setEditor() {
|
|
89
|
-
this.integration.core.getCustomEditors().enable(
|
|
93
|
+
this.integration.core.getCustomEditors().enable("chemistry");
|
|
90
94
|
}
|
|
91
95
|
}
|
package/src/integration.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import IntegrationModel from
|
|
2
|
-
import Util from
|
|
3
|
-
import Configuration from
|
|
4
|
-
import Latex from
|
|
5
|
-
import MathML from
|
|
6
|
-
import Telemeter from
|
|
1
|
+
import IntegrationModel from "@wiris/mathtype-html-integration-devkit/src/integrationmodel";
|
|
2
|
+
import Util from "@wiris/mathtype-html-integration-devkit/src/util";
|
|
3
|
+
import Configuration from "@wiris/mathtype-html-integration-devkit/src/configuration";
|
|
4
|
+
import Latex from "@wiris/mathtype-html-integration-devkit/src/latex";
|
|
5
|
+
import MathML from "@wiris/mathtype-html-integration-devkit/src/mathml";
|
|
6
|
+
import Telemeter from "@wiris/mathtype-html-integration-devkit/src/telemeter";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* This class represents the MathType integration for CKEditor5.
|
|
@@ -13,40 +13,41 @@ export default class CKEditor5Integration extends IntegrationModel {
|
|
|
13
13
|
constructor(ckeditorIntegrationModelProperties) {
|
|
14
14
|
const editor = ckeditorIntegrationModelProperties.editorObject;
|
|
15
15
|
|
|
16
|
-
if (typeof editor.config !==
|
|
17
|
-
ckeditorIntegrationModelProperties.integrationParameters = editor.config.get(
|
|
16
|
+
if (typeof editor.config !== "undefined" && typeof editor.config.get("mathTypeParameters") !== "undefined") {
|
|
17
|
+
ckeditorIntegrationModelProperties.integrationParameters = editor.config.get("mathTypeParameters");
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
* CKEditor5 Integration.
|
|
21
|
+
*
|
|
22
|
+
* @param {integrationModelProperties} integrationModelAttributes
|
|
23
|
+
*/
|
|
24
24
|
super(ckeditorIntegrationModelProperties);
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Folder name used for the integration inside CKEditor plugins folder.
|
|
28
28
|
*/
|
|
29
|
-
this.integrationFolderName =
|
|
29
|
+
this.integrationFolderName = "ckeditor_wiris";
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
* @inheritdoc
|
|
34
|
+
* @returns {string} - The CKEditor instance language.
|
|
35
|
+
* @override
|
|
36
|
+
*/
|
|
37
37
|
getLanguage() {
|
|
38
38
|
// Returns the CKEDitor instance language taking into account that the language can be an object.
|
|
39
39
|
// Try to get editorParameters.language, fail silently otherwise
|
|
40
40
|
try {
|
|
41
41
|
return this.editorParameters.language;
|
|
42
42
|
} catch (e) {}
|
|
43
|
-
const languageObject = this.editorObject.config.get(
|
|
43
|
+
const languageObject = this.editorObject.config.get("language");
|
|
44
44
|
if (languageObject != null) {
|
|
45
|
-
if (typeof
|
|
45
|
+
if (typeof languageObject === "object") {
|
|
46
46
|
// eslint-disable-next-line no-prototype-builtins
|
|
47
|
-
if (languageObject.hasOwnProperty(
|
|
47
|
+
if (languageObject.hasOwnProperty("ui")) {
|
|
48
48
|
return languageObject.ui;
|
|
49
|
-
}
|
|
49
|
+
}
|
|
50
|
+
return languageObject;
|
|
50
51
|
}
|
|
51
52
|
return languageObject;
|
|
52
53
|
}
|
|
@@ -54,29 +55,28 @@ export default class CKEditor5Integration extends IntegrationModel {
|
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
/**
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
58
|
+
* Adds callbacks to the following CKEditor listeners:
|
|
59
|
+
* - 'focus' - updates the current instance.
|
|
60
|
+
* - 'contentDom' - adds 'doubleclick' callback.
|
|
61
|
+
* - 'doubleclick' - sets to null data.dialog property to avoid modifications for MathType formulas.
|
|
62
|
+
* - 'setData' - parses the data converting MathML into images.
|
|
63
|
+
* - 'afterSetData' - adds an observer to MathType formulas to avoid modifications.
|
|
64
|
+
* - 'getData' - parses the data converting images into selected save mode (MathML by default).
|
|
65
|
+
* - 'mode' - recalculates the active element.
|
|
66
|
+
*/
|
|
66
67
|
addEditorListeners() {
|
|
67
68
|
const editor = this.editorObject;
|
|
68
69
|
|
|
69
|
-
if (typeof editor.config.wirislistenersdisabled ===
|
|
70
|
-
|| !editor.config.wirislistenersdisabled) {
|
|
70
|
+
if (typeof editor.config.wirislistenersdisabled === "undefined" || !editor.config.wirislistenersdisabled) {
|
|
71
71
|
this.checkElement();
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
/**
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
* Checks the current container and assign events in case that it doesn't have them.
|
|
77
|
+
* CKEditor replaces several times the element element during its execution,
|
|
78
|
+
* so we must assign the events again to editor element.
|
|
79
|
+
*/
|
|
80
80
|
checkElement() {
|
|
81
81
|
const editor = this.editorObject;
|
|
82
82
|
const newElement = editor.sourceElement;
|
|
@@ -91,24 +91,25 @@ export default class CKEditor5Integration extends IntegrationModel {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
/**
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
94
|
+
* @inheritdoc
|
|
95
|
+
* @param {HTMLElement} element - HTMLElement target.
|
|
96
|
+
* @param {MouseEvent} event - event which trigger the handler.
|
|
97
|
+
*/
|
|
98
98
|
doubleClickHandler(element, event) {
|
|
99
99
|
this.core.editionProperties.dbclick = true;
|
|
100
100
|
if (this.editorObject.isReadOnly === false) {
|
|
101
|
-
if (element.nodeName.toLowerCase() ===
|
|
102
|
-
if (Util.containsClass(element, Configuration.get(
|
|
101
|
+
if (element.nodeName.toLowerCase() === "img") {
|
|
102
|
+
if (Util.containsClass(element, Configuration.get("imageClassName"))) {
|
|
103
103
|
// Some plugins (image2, image) open a dialog on Double-click. On formulas
|
|
104
104
|
// doubleclick event ends here.
|
|
105
|
-
if (typeof event.stopPropagation !==
|
|
105
|
+
if (typeof event.stopPropagation !== "undefined") {
|
|
106
|
+
// old I.E compatibility.
|
|
106
107
|
event.stopPropagation();
|
|
107
108
|
} else {
|
|
108
109
|
event.returnValue = false;
|
|
109
110
|
}
|
|
110
111
|
this.core.getCustomEditors().disable();
|
|
111
|
-
const customEditorAttr = element.getAttribute(Configuration.get(
|
|
112
|
+
const customEditorAttr = element.getAttribute(Configuration.get("imageCustomEditorName"));
|
|
112
113
|
if (customEditorAttr) {
|
|
113
114
|
this.core.getCustomEditors().enable(customEditorAttr);
|
|
114
115
|
}
|
|
@@ -138,17 +139,17 @@ export default class CKEditor5Integration extends IntegrationModel {
|
|
|
138
139
|
}
|
|
139
140
|
|
|
140
141
|
/**
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
142
|
+
* Replaces old formula with new MathML or inserts it in caret position if new
|
|
143
|
+
* @param {String} mathml MathML to update old one or insert
|
|
144
|
+
* @returns {module:engine/model/element~Element} The model element corresponding to the inserted image
|
|
145
|
+
*/
|
|
145
146
|
insertMathml(mathml) {
|
|
146
147
|
// This returns the value returned by the callback function (writer => {...})
|
|
147
148
|
return this.editorObject.model.change((writer) => {
|
|
148
149
|
const core = this.getCore();
|
|
149
150
|
const selection = this.editorObject.model.document.selection;
|
|
150
151
|
|
|
151
|
-
const modelElementNew = writer.createElement(
|
|
152
|
+
const modelElementNew = writer.createElement("mathml", {
|
|
152
153
|
formula: mathml,
|
|
153
154
|
...Object.fromEntries(selection.getAttributes()), // To keep the format, such as style and font
|
|
154
155
|
});
|
|
@@ -158,7 +159,8 @@ export default class CKEditor5Integration extends IntegrationModel {
|
|
|
158
159
|
// Don't bother inserting anything at all if the MathML is empty.
|
|
159
160
|
if (!mathml) return;
|
|
160
161
|
|
|
161
|
-
const viewSelection =
|
|
162
|
+
const viewSelection =
|
|
163
|
+
this.core.editionProperties.selection || this.editorObject.editing.view.document.selection;
|
|
162
164
|
const modelPosition = this.editorObject.editing.mapper.toModelPosition(viewSelection.getLastPosition());
|
|
163
165
|
|
|
164
166
|
this.editorObject.model.insertObject(modelElementNew, modelPosition);
|
|
@@ -194,19 +196,18 @@ export default class CKEditor5Integration extends IntegrationModel {
|
|
|
194
196
|
}
|
|
195
197
|
|
|
196
198
|
/**
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
findText(viewElement) {
|
|
199
|
+
* Finds the text node corresponding to given DOM text element.
|
|
200
|
+
* @param {element} viewElement Element to find corresponding text node of.
|
|
201
|
+
* @returns {module:engine/model/text~Text|undefined} Text node corresponding to the given element or undefined if it doesn't exist.
|
|
202
|
+
*/
|
|
203
|
+
findText(viewElement) {
|
|
204
|
+
// eslint-disable-line consistent-return
|
|
202
205
|
// mapper always converts text nodes to *new* model elements so we need to convert the text's parents and then come back down
|
|
203
206
|
let pivot = viewElement;
|
|
204
207
|
let element;
|
|
205
208
|
while (!element) {
|
|
206
209
|
element = this.editorObject.editing.mapper.toModelElement(
|
|
207
|
-
this.editorObject.editing.view.domConverter.domToView(
|
|
208
|
-
pivot,
|
|
209
|
-
),
|
|
210
|
+
this.editorObject.editing.view.domConverter.domToView(pivot),
|
|
210
211
|
);
|
|
211
212
|
pivot = pivot.parentElement;
|
|
212
213
|
}
|
|
@@ -218,22 +219,23 @@ export default class CKEditor5Integration extends IntegrationModel {
|
|
|
218
219
|
let viewElementData = viewElement.data;
|
|
219
220
|
if (viewElement.nodeType === 3) {
|
|
220
221
|
// Remove invisible white spaces
|
|
221
|
-
viewElementData = viewElementData.replaceAll(String.fromCharCode(8288),
|
|
222
|
+
viewElementData = viewElementData.replaceAll(String.fromCharCode(8288), "");
|
|
222
223
|
}
|
|
223
|
-
if (node.is(
|
|
224
|
+
if (node.is("textProxy") && node.data === viewElementData.replace(String.fromCharCode(160), " ")) {
|
|
224
225
|
return node.textNode;
|
|
225
226
|
}
|
|
226
227
|
}
|
|
227
228
|
}
|
|
228
229
|
|
|
229
230
|
/** @inheritdoc */
|
|
230
|
-
insertFormula(focusElement, windowTarget, mathml, wirisProperties) {
|
|
231
|
+
insertFormula(focusElement, windowTarget, mathml, wirisProperties) {
|
|
232
|
+
// eslint-disable-line no-unused-vars
|
|
231
233
|
const returnObject = {};
|
|
232
234
|
|
|
233
235
|
let mathmlOrigin;
|
|
234
236
|
if (!mathml) {
|
|
235
|
-
this.insertMathml(
|
|
236
|
-
} else if (this.core.editMode ===
|
|
237
|
+
this.insertMathml("");
|
|
238
|
+
} else if (this.core.editMode === "latex") {
|
|
237
239
|
returnObject.latex = Latex.getLatexFromMathML(mathml);
|
|
238
240
|
returnObject.node = windowTarget.document.createTextNode(`$$${returnObject.latex}$$`);
|
|
239
241
|
|
|
@@ -246,28 +248,26 @@ export default class CKEditor5Integration extends IntegrationModel {
|
|
|
246
248
|
let startPosition = writer.createPositionAt(startNode.parent, startNode.startOffset + latexRange.startOffset);
|
|
247
249
|
let endPosition = writer.createPositionAt(endNode.parent, endNode.startOffset + latexRange.endOffset);
|
|
248
250
|
|
|
249
|
-
let range = writer.createRange(
|
|
250
|
-
startPosition,
|
|
251
|
-
endPosition,
|
|
252
|
-
);
|
|
253
|
-
|
|
254
|
-
|
|
251
|
+
let range = writer.createRange(startPosition, endPosition);
|
|
255
252
|
|
|
256
253
|
// When Latex is next to image/formula.
|
|
257
254
|
if (latexRange.startContainer.nodeType === 3 && latexRange.startContainer.previousSibling?.nodeType === 1) {
|
|
258
255
|
// Get the position of the latex to be replaced.
|
|
259
|
-
let latexEdited =
|
|
256
|
+
let latexEdited =
|
|
257
|
+
"$$" +
|
|
258
|
+
Latex.getLatexFromMathML(MathML.safeXmlDecode(this.core.editionProperties.temporalImage.dataset.mathml)) +
|
|
259
|
+
"$$";
|
|
260
260
|
let data = latexRange.startContainer.data;
|
|
261
261
|
|
|
262
262
|
// Remove invisible characters.
|
|
263
|
-
data = data.replaceAll(String.fromCharCode(8288),
|
|
263
|
+
data = data.replaceAll(String.fromCharCode(8288), "");
|
|
264
264
|
|
|
265
265
|
// Get to the start of the latex we are editing.
|
|
266
266
|
let offset = data.indexOf(latexEdited);
|
|
267
267
|
let dataOffset = data.substring(offset);
|
|
268
268
|
let second$ = dataOffset.substring(2).indexOf("$$") + 4;
|
|
269
269
|
let substring = dataOffset.substr(0, second$);
|
|
270
|
-
data = data.replace(substring,
|
|
270
|
+
data = data.replace(substring, "");
|
|
271
271
|
|
|
272
272
|
if (!data) {
|
|
273
273
|
startPosition = writer.createPositionBefore(startNode);
|
|
@@ -275,10 +275,7 @@ export default class CKEditor5Integration extends IntegrationModel {
|
|
|
275
275
|
} else {
|
|
276
276
|
startPosition = startPosition = writer.createPositionAt(startNode.parent, startNode.startOffset + offset);
|
|
277
277
|
endPosition = writer.createPositionAt(endNode.parent, endNode.startOffset + second$ + offset);
|
|
278
|
-
range = writer.createRange(
|
|
279
|
-
startPosition,
|
|
280
|
-
endPosition,
|
|
281
|
-
);
|
|
278
|
+
range = writer.createRange(startPosition, endPosition);
|
|
282
279
|
}
|
|
283
280
|
}
|
|
284
281
|
|
|
@@ -289,13 +286,12 @@ export default class CKEditor5Integration extends IntegrationModel {
|
|
|
289
286
|
mathmlOrigin = this.core.editionProperties.temporalImage?.dataset.mathml;
|
|
290
287
|
try {
|
|
291
288
|
returnObject.node = this.editorObject.editing.view.domConverter.viewToDom(
|
|
292
|
-
this.editorObject.editing.mapper.toViewElement(
|
|
293
|
-
|
|
294
|
-
), windowTarget.document,
|
|
289
|
+
this.editorObject.editing.mapper.toViewElement(this.insertMathml(mathml)),
|
|
290
|
+
windowTarget.document,
|
|
295
291
|
);
|
|
296
292
|
} catch (e) {
|
|
297
293
|
const x = e.toString();
|
|
298
|
-
if (
|
|
294
|
+
if (x.includes("CKEditorError: Cannot read property 'parent' of undefined")) {
|
|
299
295
|
this.core.modalDialog.cancelAction();
|
|
300
296
|
}
|
|
301
297
|
}
|
|
@@ -312,16 +308,17 @@ export default class CKEditor5Integration extends IntegrationModel {
|
|
|
312
308
|
};
|
|
313
309
|
|
|
314
310
|
// Remove desired null keys.
|
|
315
|
-
Object.keys(payload).forEach(key => {
|
|
316
|
-
if (key ===
|
|
311
|
+
Object.keys(payload).forEach((key) => {
|
|
312
|
+
if (key === "mathml_origin" || key === "editor_origin") !payload[key] ? delete payload[key] : {};
|
|
317
313
|
});
|
|
318
314
|
|
|
315
|
+
// Call Telemetry service to track the event.
|
|
319
316
|
try {
|
|
320
317
|
Telemeter.telemeter.track("INSERTED_FORMULA", {
|
|
321
318
|
...payload,
|
|
322
319
|
});
|
|
323
|
-
} catch (
|
|
324
|
-
console.error(
|
|
320
|
+
} catch (error) {
|
|
321
|
+
console.error("Error tracking INSERTED_FORMULA", error);
|
|
325
322
|
}
|
|
326
323
|
|
|
327
324
|
/* Due to PLUGINS-1329, we add the onChange event to the CK4 insertFormula.
|
|
@@ -335,8 +332,8 @@ export default class CKEditor5Integration extends IntegrationModel {
|
|
|
335
332
|
}
|
|
336
333
|
|
|
337
334
|
/**
|
|
338
|
-
|
|
339
|
-
|
|
335
|
+
* Function called when the content submits an action.
|
|
336
|
+
*/
|
|
340
337
|
notifyWindowClosed() {
|
|
341
338
|
this.editorObject.editing.view.focus();
|
|
342
339
|
}
|
package/src/plugin.js
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
1
|
// CKEditor imports
|
|
2
|
-
import Plugin from
|
|
3
|
-
import ButtonView from
|
|
4
|
-
import ClickObserver from
|
|
5
|
-
import HtmlDataProcessor from
|
|
6
|
-
import XmlDataProcessor from
|
|
7
|
-
import UpcastWriter from
|
|
8
|
-
import { toWidget, viewToModelPositionOutsideModelElement } from
|
|
9
|
-
import Widget from
|
|
2
|
+
import Plugin from "@ckeditor/ckeditor5-core/src/plugin";
|
|
3
|
+
import ButtonView from "@ckeditor/ckeditor5-ui/src/button/buttonview";
|
|
4
|
+
import ClickObserver from "@ckeditor/ckeditor5-engine/src/view/observer/clickobserver";
|
|
5
|
+
import HtmlDataProcessor from "@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor";
|
|
6
|
+
import XmlDataProcessor from "@ckeditor/ckeditor5-engine/src/dataprocessor/xmldataprocessor";
|
|
7
|
+
import UpcastWriter from "@ckeditor/ckeditor5-engine/src/view/upcastwriter";
|
|
8
|
+
import { toWidget, viewToModelPositionOutsideModelElement } from "@ckeditor/ckeditor5-widget/src/utils";
|
|
9
|
+
import Widget from "@ckeditor/ckeditor5-widget/src/widget";
|
|
10
10
|
|
|
11
11
|
// MathType API imports
|
|
12
|
-
import IntegrationModel from
|
|
13
|
-
import Core from
|
|
14
|
-
import Parser from
|
|
15
|
-
import Util from
|
|
16
|
-
import Image from
|
|
17
|
-
import Configuration from
|
|
18
|
-
import Listeners from
|
|
19
|
-
import MathML from
|
|
20
|
-
import Latex from
|
|
21
|
-
import StringManager from
|
|
12
|
+
import IntegrationModel from "@wiris/mathtype-html-integration-devkit/src/integrationmodel";
|
|
13
|
+
import Core from "@wiris/mathtype-html-integration-devkit/src/core.src";
|
|
14
|
+
import Parser from "@wiris/mathtype-html-integration-devkit/src/parser";
|
|
15
|
+
import Util from "@wiris/mathtype-html-integration-devkit/src/util";
|
|
16
|
+
import Image from "@wiris/mathtype-html-integration-devkit/src/image";
|
|
17
|
+
import Configuration from "@wiris/mathtype-html-integration-devkit/src/configuration";
|
|
18
|
+
import Listeners from "@wiris/mathtype-html-integration-devkit/src/listeners";
|
|
19
|
+
import MathML from "@wiris/mathtype-html-integration-devkit/src/mathml";
|
|
20
|
+
import Latex from "@wiris/mathtype-html-integration-devkit/src/latex";
|
|
21
|
+
import StringManager from "@wiris/mathtype-html-integration-devkit/src/stringmanager";
|
|
22
22
|
|
|
23
23
|
// Local imports
|
|
24
|
-
import { MathTypeCommand, ChemTypeCommand } from
|
|
25
|
-
import CKEditor5Integration from
|
|
24
|
+
import { MathTypeCommand, ChemTypeCommand } from "./commands";
|
|
25
|
+
import CKEditor5Integration from "./integration";
|
|
26
26
|
|
|
27
|
-
import mathIcon from
|
|
28
|
-
import chemIcon from
|
|
27
|
+
import mathIcon from "../theme/icons/ckeditor5-formula.svg";
|
|
28
|
+
import chemIcon from "../theme/icons/ckeditor5-chem.svg";
|
|
29
29
|
|
|
30
|
-
import packageInfo from
|
|
30
|
+
import packageInfo from "../package.json";
|
|
31
31
|
|
|
32
32
|
export let currentInstance = null; // eslint-disable-line import/no-mutable-exports
|
|
33
33
|
|
|
@@ -37,7 +37,7 @@ export default class MathType extends Plugin {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
static get pluginName() {
|
|
40
|
-
return
|
|
40
|
+
return "MathType";
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
init() {
|
|
@@ -64,14 +64,15 @@ export default class MathType extends Plugin {
|
|
|
64
64
|
/**
|
|
65
65
|
* Inherited from Plugin class: Executed when CKEditor5 is destroyed
|
|
66
66
|
*/
|
|
67
|
-
destroy() {
|
|
67
|
+
destroy() {
|
|
68
|
+
// eslint-disable-line class-methods-use-this
|
|
68
69
|
currentInstance.destroy();
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
/**
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
* Create the MathType API Integration object
|
|
74
|
+
* @returns {CKEditor5Integration} the integration object
|
|
75
|
+
*/
|
|
75
76
|
_addIntegration() {
|
|
76
77
|
const { editor } = this;
|
|
77
78
|
|
|
@@ -81,15 +82,15 @@ export default class MathType extends Plugin {
|
|
|
81
82
|
*/
|
|
82
83
|
const integrationProperties = {};
|
|
83
84
|
integrationProperties.environment = {};
|
|
84
|
-
integrationProperties.environment.editor =
|
|
85
|
-
integrationProperties.environment.editorVersion =
|
|
85
|
+
integrationProperties.environment.editor = "CKEditor5";
|
|
86
|
+
integrationProperties.environment.editorVersion = "5.x";
|
|
86
87
|
integrationProperties.version = packageInfo.version;
|
|
87
88
|
integrationProperties.editorObject = editor;
|
|
88
89
|
integrationProperties.serviceProviderProperties = {};
|
|
89
|
-
integrationProperties.serviceProviderProperties.URI =
|
|
90
|
-
integrationProperties.serviceProviderProperties.server =
|
|
90
|
+
integrationProperties.serviceProviderProperties.URI = "https://www.wiris.net/demo/plugins/app";
|
|
91
|
+
integrationProperties.serviceProviderProperties.server = "java";
|
|
91
92
|
integrationProperties.target = editor.sourceElement;
|
|
92
|
-
integrationProperties.scriptName =
|
|
93
|
+
integrationProperties.scriptName = "bundle.js";
|
|
93
94
|
integrationProperties.managesLanguage = true;
|
|
94
95
|
// etc
|
|
95
96
|
|
|
@@ -100,59 +101,64 @@ export default class MathType extends Plugin {
|
|
|
100
101
|
// Instance of the integration associated to this editor instance
|
|
101
102
|
integration = new CKEditor5Integration(integrationProperties);
|
|
102
103
|
integration.init();
|
|
103
|
-
integration.listeners.fire(
|
|
104
|
+
integration.listeners.fire("onTargetReady", {});
|
|
104
105
|
|
|
105
106
|
integration.checkElement();
|
|
106
107
|
|
|
107
|
-
this.listenTo(
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
108
|
+
this.listenTo(
|
|
109
|
+
editor.editing.view.document,
|
|
110
|
+
"click",
|
|
111
|
+
(evt, data) => {
|
|
112
|
+
// Is Double-click
|
|
113
|
+
if (data.domEvent.detail === 2) {
|
|
114
|
+
integration.doubleClickHandler(data.domTarget, data.domEvent);
|
|
115
|
+
evt.stop();
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
{ priority: "highest" },
|
|
119
|
+
);
|
|
114
120
|
}
|
|
115
121
|
|
|
116
122
|
return integration;
|
|
117
123
|
}
|
|
118
124
|
|
|
119
125
|
/**
|
|
120
|
-
|
|
121
|
-
|
|
126
|
+
* Add the MathType and ChemType commands to the editor
|
|
127
|
+
*/
|
|
122
128
|
_addCommands() {
|
|
123
129
|
const { editor } = this;
|
|
124
130
|
|
|
125
131
|
// Add command to open the formula editor
|
|
126
|
-
editor.commands.add(
|
|
132
|
+
editor.commands.add("MathType", new MathTypeCommand(editor));
|
|
127
133
|
|
|
128
134
|
// Add command to open the chemistry formula editor
|
|
129
|
-
editor.commands.add(
|
|
135
|
+
editor.commands.add("ChemType", new ChemTypeCommand(editor));
|
|
130
136
|
}
|
|
131
137
|
|
|
132
138
|
/**
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
139
|
+
* Add the buttons for MathType and ChemType
|
|
140
|
+
* @param {CKEditor5Integration} integration the integration object
|
|
141
|
+
*/
|
|
136
142
|
_addViews(integration) {
|
|
137
143
|
const { editor } = this;
|
|
138
144
|
|
|
139
145
|
// Check if MathType editor is enabled
|
|
140
|
-
if (Configuration.get(
|
|
146
|
+
if (Configuration.get("editorEnabled")) {
|
|
141
147
|
// Add button for the formula editor
|
|
142
|
-
editor.ui.componentFactory.add(
|
|
148
|
+
editor.ui.componentFactory.add("MathType", (locale) => {
|
|
143
149
|
const view = new ButtonView(locale);
|
|
144
150
|
|
|
145
151
|
// View is enabled iff command is enabled
|
|
146
|
-
view.bind(
|
|
152
|
+
view.bind("isEnabled").to(editor.commands.get("MathType"), "isEnabled");
|
|
147
153
|
view.set({
|
|
148
|
-
label: StringManager.get(
|
|
154
|
+
label: StringManager.get("insert_math", integration.getLanguage()),
|
|
149
155
|
icon: mathIcon,
|
|
150
156
|
tooltip: true,
|
|
151
157
|
});
|
|
152
158
|
|
|
153
159
|
// Callback executed once the image is clicked.
|
|
154
|
-
view.on(
|
|
155
|
-
editor.execute(
|
|
160
|
+
view.on("execute", () => {
|
|
161
|
+
editor.execute("MathType", {
|
|
156
162
|
integration, // Pass integration as parameter
|
|
157
163
|
});
|
|
158
164
|
});
|
|
@@ -162,23 +168,23 @@ export default class MathType extends Plugin {
|
|
|
162
168
|
}
|
|
163
169
|
|
|
164
170
|
// Check if ChemType editor is enabled
|
|
165
|
-
if (Configuration.get(
|
|
171
|
+
if (Configuration.get("chemEnabled")) {
|
|
166
172
|
// Add button for the chemistry formula editor
|
|
167
|
-
editor.ui.componentFactory.add(
|
|
173
|
+
editor.ui.componentFactory.add("ChemType", (locale) => {
|
|
168
174
|
const view = new ButtonView(locale);
|
|
169
175
|
|
|
170
176
|
// View is enabled iff command is enabled
|
|
171
|
-
view.bind(
|
|
177
|
+
view.bind("isEnabled").to(editor.commands.get("ChemType"), "isEnabled");
|
|
172
178
|
|
|
173
179
|
view.set({
|
|
174
|
-
label: StringManager.get(
|
|
180
|
+
label: StringManager.get("insert_chem", integration.getLanguage()),
|
|
175
181
|
icon: chemIcon,
|
|
176
182
|
tooltip: true,
|
|
177
183
|
});
|
|
178
184
|
|
|
179
185
|
// Callback executed once the image is clicked.
|
|
180
|
-
view.on(
|
|
181
|
-
editor.execute(
|
|
186
|
+
view.on("execute", () => {
|
|
187
|
+
editor.execute("ChemType", {
|
|
182
188
|
integration, // Pass integration as parameter
|
|
183
189
|
});
|
|
184
190
|
});
|
|
@@ -192,39 +198,39 @@ export default class MathType extends Plugin {
|
|
|
192
198
|
}
|
|
193
199
|
|
|
194
200
|
/**
|
|
195
|
-
|
|
196
|
-
|
|
201
|
+
* Registers the <mathml> element in the schema
|
|
202
|
+
*/
|
|
197
203
|
_addSchema() {
|
|
198
204
|
const { schema } = this.editor.model;
|
|
199
205
|
|
|
200
|
-
schema.register(
|
|
201
|
-
inheritAllFrom:
|
|
202
|
-
allowAttributes: [
|
|
206
|
+
schema.register("mathml", {
|
|
207
|
+
inheritAllFrom: "$inlineObject",
|
|
208
|
+
allowAttributes: ["formula"],
|
|
203
209
|
});
|
|
204
210
|
}
|
|
205
211
|
|
|
206
212
|
/**
|
|
207
|
-
|
|
208
|
-
|
|
213
|
+
* Add the downcast and upcast converters
|
|
214
|
+
*/
|
|
209
215
|
_addConverters(integration) {
|
|
210
216
|
const { editor } = this;
|
|
211
217
|
|
|
212
218
|
// Editing view -> Model
|
|
213
|
-
editor.conversion.for(
|
|
219
|
+
editor.conversion.for("upcast").elementToElement({
|
|
214
220
|
view: {
|
|
215
|
-
name:
|
|
216
|
-
classes:
|
|
221
|
+
name: "span",
|
|
222
|
+
classes: "ck-math-widget",
|
|
217
223
|
},
|
|
218
224
|
model: (viewElement, { writer: modelWriter }) => {
|
|
219
|
-
const formula = MathML.safeXmlDecode(viewElement.getChild(0).getAttribute(
|
|
220
|
-
return modelWriter.createElement(
|
|
225
|
+
const formula = MathML.safeXmlDecode(viewElement.getChild(0).getAttribute("data-mathml"));
|
|
226
|
+
return modelWriter.createElement("mathml", {
|
|
221
227
|
formula,
|
|
222
228
|
});
|
|
223
229
|
},
|
|
224
230
|
});
|
|
225
231
|
|
|
226
232
|
// Data view -> Model
|
|
227
|
-
editor.data.upcastDispatcher.on(
|
|
233
|
+
editor.data.upcastDispatcher.on("element:math", (evt, data, conversionApi) => {
|
|
228
234
|
const { consumable, writer } = conversionApi;
|
|
229
235
|
const { viewItem } = data;
|
|
230
236
|
|
|
@@ -246,28 +252,23 @@ export default class MathType extends Plugin {
|
|
|
246
252
|
const viewDocumentFragment = upcastWriter.createDocumentFragment(viewItem.getChildren());
|
|
247
253
|
|
|
248
254
|
// and obtain the attributes of <math> too!
|
|
249
|
-
const mathAttributes = [...viewItem.getAttributes()]
|
|
250
|
-
.map(([key, value]) => ` ${key}="${value}"`)
|
|
251
|
-
.join('');
|
|
255
|
+
const mathAttributes = [...viewItem.getAttributes()].map(([key, value]) => ` ${key}="${value}"`).join("");
|
|
252
256
|
|
|
253
257
|
// We process the document fragment
|
|
254
|
-
let formula = processor.toData(viewDocumentFragment) ||
|
|
258
|
+
let formula = processor.toData(viewDocumentFragment) || "";
|
|
255
259
|
|
|
256
260
|
// And obtain the complete formula
|
|
257
261
|
formula = Util.htmlSanitize(`<math${mathAttributes}>${formula}</math>`);
|
|
258
262
|
|
|
259
263
|
// Replaces the < & > characters to its HTMLEntity to avoid render issues.
|
|
260
|
-
formula = formula.replaceAll('"<"', '"<"')
|
|
261
|
-
.replaceAll('">"', '">"')
|
|
262
|
-
.replaceAll('><<', '><<');
|
|
263
|
-
|
|
264
|
+
formula = formula.replaceAll('"<"', '"<"').replaceAll('">"', '">"').replaceAll("><<", "><<");
|
|
264
265
|
|
|
265
266
|
/* Model node that contains what's going to actually be inserted. This can be either:
|
|
266
267
|
- A <mathml> element with a formula attribute set to the given formula, or
|
|
267
268
|
- If the original <math> had a LaTeX annotation, then the annotation surrounded by "$$...$$" */
|
|
268
269
|
const modelNode = isLatex
|
|
269
270
|
? writer.createText(Parser.initParse(formula, integration.getLanguage()))
|
|
270
|
-
: writer.createElement(
|
|
271
|
+
: writer.createElement("mathml", { formula });
|
|
271
272
|
|
|
272
273
|
// Find allowed parent for element that we are going to insert.
|
|
273
274
|
// If current parent does not allow to insert element but one of the ancestors does
|
|
@@ -308,15 +309,15 @@ export default class MathType extends Plugin {
|
|
|
308
309
|
});
|
|
309
310
|
|
|
310
311
|
/**
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
312
|
+
* Whether the given view <math> element has a LaTeX annotation element.
|
|
313
|
+
* @param {*} math
|
|
314
|
+
* @returns {bool}
|
|
315
|
+
*/
|
|
315
316
|
function mathIsLatex(math) {
|
|
316
317
|
const semantics = math.getChild(0);
|
|
317
|
-
if (!semantics || semantics.name !==
|
|
318
|
+
if (!semantics || semantics.name !== "semantics") return false;
|
|
318
319
|
for (const child of semantics.getChildren()) {
|
|
319
|
-
if (child.name ===
|
|
320
|
+
if (child.name === "annotation" && child.getAttribute("encoding") === "LaTeX") {
|
|
320
321
|
return true;
|
|
321
322
|
}
|
|
322
323
|
}
|
|
@@ -324,8 +325,8 @@ export default class MathType extends Plugin {
|
|
|
324
325
|
}
|
|
325
326
|
|
|
326
327
|
function createViewWidget(modelItem, { writer: viewWriter }) {
|
|
327
|
-
const widgetElement = viewWriter.createContainerElement(
|
|
328
|
-
class:
|
|
328
|
+
const widgetElement = viewWriter.createContainerElement("span", {
|
|
329
|
+
class: "ck-math-widget",
|
|
329
330
|
});
|
|
330
331
|
|
|
331
332
|
const mathUIElement = createViewImage(modelItem, { writer: viewWriter }); // eslint-disable-line no-use-before-define
|
|
@@ -340,7 +341,7 @@ export default class MathType extends Plugin {
|
|
|
340
341
|
function createViewImage(modelItem, { writer: viewWriter }) {
|
|
341
342
|
const htmlDataProcessor = new HtmlDataProcessor(viewWriter.document);
|
|
342
343
|
|
|
343
|
-
const mathString = modelItem.getAttribute(
|
|
344
|
+
const mathString = modelItem.getAttribute("formula").replaceAll('ref="<"', 'ref="<"');
|
|
344
345
|
const imgHtml = Parser.initParse(mathString, integration.getLanguage());
|
|
345
346
|
const imgElement = htmlDataProcessor.toView(imgHtml).getChild(0);
|
|
346
347
|
|
|
@@ -348,8 +349,8 @@ export default class MathType extends Plugin {
|
|
|
348
349
|
we must create a new EmptyElement which is independent of the
|
|
349
350
|
DataProcessor being used by this editor instance */
|
|
350
351
|
if (imgElement) {
|
|
351
|
-
return viewWriter.createEmptyElement(
|
|
352
|
-
renderUnsafeAttributes: [
|
|
352
|
+
return viewWriter.createEmptyElement("img", imgElement.getAttributes(), {
|
|
353
|
+
renderUnsafeAttributes: ["src"],
|
|
353
354
|
});
|
|
354
355
|
}
|
|
355
356
|
|
|
@@ -357,14 +358,14 @@ export default class MathType extends Plugin {
|
|
|
357
358
|
}
|
|
358
359
|
|
|
359
360
|
// Model -> Editing view
|
|
360
|
-
editor.conversion.for(
|
|
361
|
-
model:
|
|
361
|
+
editor.conversion.for("editingDowncast").elementToElement({
|
|
362
|
+
model: "mathml",
|
|
362
363
|
view: createViewWidget,
|
|
363
364
|
});
|
|
364
365
|
|
|
365
366
|
// Model -> Data view
|
|
366
|
-
editor.conversion.for(
|
|
367
|
-
model:
|
|
367
|
+
editor.conversion.for("dataDowncast").elementToElement({
|
|
368
|
+
model: "mathml",
|
|
368
369
|
view: createDataString, // eslint-disable-line no-use-before-define
|
|
369
370
|
});
|
|
370
371
|
|
|
@@ -374,26 +375,27 @@ export default class MathType extends Plugin {
|
|
|
374
375
|
* @returns {module:engine/view/node~Node} Copy of the node.
|
|
375
376
|
*/
|
|
376
377
|
function clone(viewWriter, sourceNode) {
|
|
377
|
-
if (sourceNode.is(
|
|
378
|
+
if (sourceNode.is("text")) {
|
|
378
379
|
return viewWriter.createText(sourceNode.data);
|
|
379
|
-
}
|
|
380
|
-
|
|
380
|
+
}
|
|
381
|
+
if (sourceNode.is("element")) {
|
|
382
|
+
if (sourceNode.is("emptyElement")) {
|
|
381
383
|
return viewWriter.createEmptyElement(sourceNode.name, sourceNode.getAttributes());
|
|
382
384
|
}
|
|
383
385
|
const element = viewWriter.createContainerElement(sourceNode.name, sourceNode.getAttributes());
|
|
384
386
|
for (const child of sourceNode.getChildren()) {
|
|
385
|
-
viewWriter.insert(viewWriter.createPositionAt(element,
|
|
387
|
+
viewWriter.insert(viewWriter.createPositionAt(element, "end"), clone(viewWriter, child));
|
|
386
388
|
}
|
|
387
389
|
return element;
|
|
388
390
|
}
|
|
389
391
|
|
|
390
|
-
throw new Exception(
|
|
392
|
+
throw new Exception("Given node has unsupported type."); // eslint-disable-line no-undef
|
|
391
393
|
}
|
|
392
394
|
|
|
393
395
|
function createDataString(modelItem, { writer: viewWriter }) {
|
|
394
396
|
const htmlDataProcessor = new HtmlDataProcessor(viewWriter.document);
|
|
395
397
|
|
|
396
|
-
let mathString = Parser.endParseSaveMode(modelItem.getAttribute(
|
|
398
|
+
let mathString = Parser.endParseSaveMode(modelItem.getAttribute("formula"));
|
|
397
399
|
|
|
398
400
|
const sourceMathElement = htmlDataProcessor.toView(mathString).getChild(0);
|
|
399
401
|
|
|
@@ -402,8 +404,8 @@ export default class MathType extends Plugin {
|
|
|
402
404
|
|
|
403
405
|
// This stops the view selection getting into the <span>s and messing up caret movement
|
|
404
406
|
editor.editing.mapper.on(
|
|
405
|
-
|
|
406
|
-
viewToModelPositionOutsideModelElement(editor.model, (viewElement) => viewElement.hasClass(
|
|
407
|
+
"viewToModelPosition",
|
|
408
|
+
viewToModelPositionOutsideModelElement(editor.model, (viewElement) => viewElement.hasClass("ck-math-widget")),
|
|
407
409
|
);
|
|
408
410
|
|
|
409
411
|
// Keep a reference to the original get and set function.
|
|
@@ -412,54 +414,62 @@ export default class MathType extends Plugin {
|
|
|
412
414
|
/**
|
|
413
415
|
* Hack to transform $$latex$$ into <math> in editor.getData()'s output.
|
|
414
416
|
*/
|
|
415
|
-
editor.data.
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
.
|
|
422
|
-
.replaceAll('
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
417
|
+
editor.data.on(
|
|
418
|
+
"get",
|
|
419
|
+
(e) => {
|
|
420
|
+
let output = e.return;
|
|
421
|
+
|
|
422
|
+
// CKEditor 5 replaces all the time the < and > for < and >, which our render can't understand.
|
|
423
|
+
// We replace the values inserted for CKEditor5 to be able to render the formulas with the mentioned characters.
|
|
424
|
+
output = output.replaceAll('"<"', '"<"').replaceAll('">"', '">"').replaceAll("><<", "><<");
|
|
425
|
+
|
|
426
|
+
// Ckeditor retrieves editor data and removes the image information on the formulas
|
|
427
|
+
// We transform all the retrieved data to images and then we Parse the data.
|
|
428
|
+
let imageFormula = Parser.initParse(output);
|
|
429
|
+
e.return = Parser.endParse(imageFormula);
|
|
430
|
+
},
|
|
431
|
+
{ priority: "low" },
|
|
432
|
+
);
|
|
429
433
|
|
|
430
434
|
/**
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
editor.data.
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
435
|
+
* Hack to transform <math> with LaTeX into $$LaTeX$$ in editor.setData().
|
|
436
|
+
*/
|
|
437
|
+
editor.data.on(
|
|
438
|
+
"set",
|
|
439
|
+
(e, args) => {
|
|
440
|
+
// Retrieve the data to be set on the CKEditor.
|
|
441
|
+
let modifiedData = args[0];
|
|
442
|
+
// Regex to find all mathml formulas.
|
|
443
|
+
const regexp = /<math(.*?)<\/math>/gm;
|
|
444
|
+
|
|
445
|
+
// Get all MathML formulas and store them in an array.
|
|
446
|
+
// Using the conditional operator on data.main because the data parameter has different types depending on:
|
|
447
|
+
// editor.data.set can be used directly or by the source editing plugin.
|
|
448
|
+
// With the source editor plugin, data is an object with the key `main` which contains the source code string.
|
|
449
|
+
// When using the editor.data.set method, the data is a string with the content to be set to the editor.
|
|
450
|
+
let formulas = Object.values(modifiedData)[0]
|
|
451
|
+
? [...Object.values(modifiedData)[0].matchAll(regexp)]
|
|
452
|
+
: [...modifiedData.matchAll(regexp)];
|
|
453
|
+
|
|
454
|
+
// Loop to find LaTeX formulas and replace the MathML for the LaTeX notation.
|
|
455
|
+
formulas.forEach((formula) => {
|
|
456
|
+
let mathml = formula[0];
|
|
457
|
+
if (mathml.includes('encoding="LaTeX"')) {
|
|
458
|
+
// LaTeX found.
|
|
459
|
+
let latex = "$$$" + Latex.getLatexFromMathML(mathml) + "$$$"; // We add $$$ instead of $$ because the replace function ignores one $.
|
|
460
|
+
modifiedData = modifiedData.replace(mathml, latex);
|
|
461
|
+
}
|
|
462
|
+
});
|
|
454
463
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
464
|
+
args[0] = modifiedData;
|
|
465
|
+
},
|
|
466
|
+
{ priority: "high" },
|
|
467
|
+
);
|
|
458
468
|
}
|
|
459
469
|
|
|
460
470
|
/**
|
|
461
|
-
|
|
462
|
-
|
|
471
|
+
* Expose the WirisPlugin variable to the window
|
|
472
|
+
*/
|
|
463
473
|
// eslint-disable-next-line class-methods-use-this
|
|
464
474
|
_exposeWiris() {
|
|
465
475
|
window.WirisPlugin = {
|