@wiris/mathtype-ckeditor5 7.26.0 → 7.27.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/package.json +44 -52
- package/src/commands.js +54 -63
- package/src/integration.js +268 -294
- package/src/plugin.js +419 -443
package/src/integration.js
CHANGED
|
@@ -1,294 +1,268 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
import
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
*
|
|
60
|
-
* - '
|
|
61
|
-
* - '
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
//
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
this.
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
), windowTarget.document
|
|
270
|
-
);
|
|
271
|
-
} catch ( e ) {
|
|
272
|
-
const x = e.toString();
|
|
273
|
-
if( ( x ).includes( "CKEditorError: Cannot read property 'parent' of undefined" ) ) {
|
|
274
|
-
this.core.modalDialog.cancelAction();
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
/* Due to PLUGINS-1329, we add the onChange event to the CK4 insertFormula.
|
|
280
|
-
We probably should add it here as well, but we should look further into how */
|
|
281
|
-
// this.editorObject.fire('change');
|
|
282
|
-
|
|
283
|
-
return returnObject;
|
|
284
|
-
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
/**
|
|
288
|
-
* Function called when the content submits an action.
|
|
289
|
-
*/
|
|
290
|
-
notifyWindowClosed() {
|
|
291
|
-
this.editorObject.editing.view.focus();
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
}
|
|
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
|
+
|
|
6
|
+
/**
|
|
7
|
+
* This class represents the MathType integration for CKEditor5.
|
|
8
|
+
* @extends {IntegrationModel}
|
|
9
|
+
*/
|
|
10
|
+
export default class CKEditor5Integration extends IntegrationModel {
|
|
11
|
+
constructor(ckeditorIntegrationModelProperties) {
|
|
12
|
+
const editor = ckeditorIntegrationModelProperties.editorObject;
|
|
13
|
+
|
|
14
|
+
if (typeof editor.config !== 'undefined' && typeof editor.config.get('mathTypeParameters') !== 'undefined') {
|
|
15
|
+
ckeditorIntegrationModelProperties.integrationParameters = editor.config.get('mathTypeParameters');
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* CKEditor5 Integration.
|
|
19
|
+
*
|
|
20
|
+
* @param {integrationModelProperties} integrationModelAttributes
|
|
21
|
+
*/
|
|
22
|
+
super(ckeditorIntegrationModelProperties);
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Folder name used for the integration inside CKEditor plugins folder.
|
|
26
|
+
*/
|
|
27
|
+
this.integrationFolderName = 'ckeditor_wiris';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @inheritdoc
|
|
32
|
+
* @returns {string} - The CKEditor instance language.
|
|
33
|
+
* @override
|
|
34
|
+
*/
|
|
35
|
+
getLanguage() {
|
|
36
|
+
// Returns the CKEDitor instance language taking into account that the language can be an object.
|
|
37
|
+
try {
|
|
38
|
+
return this.editorParameters.language;
|
|
39
|
+
} catch (e) { console.error(); }
|
|
40
|
+
const languageObject = this.editorObject.config.get('language');
|
|
41
|
+
if (languageObject != null) {
|
|
42
|
+
if (typeof (languageObject) === 'object') {
|
|
43
|
+
// eslint-disable-next-line no-prototype-builtins
|
|
44
|
+
if (languageObject.hasOwnProperty('ui')) {
|
|
45
|
+
return languageObject.ui;
|
|
46
|
+
} return super.getLanguage();
|
|
47
|
+
}
|
|
48
|
+
return languageObject;
|
|
49
|
+
}
|
|
50
|
+
return super.getLanguage();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Adds callbacks to the following CKEditor listeners:
|
|
55
|
+
* - 'focus' - updates the current instance.
|
|
56
|
+
* - 'contentDom' - adds 'doubleclick' callback.
|
|
57
|
+
* - 'doubleclick' - sets to null data.dialog property to avoid modifications for MathType formulas.
|
|
58
|
+
* - 'setData' - parses the data converting MathML into images.
|
|
59
|
+
* - 'afterSetData' - adds an observer to MathType formulas to avoid modifications.
|
|
60
|
+
* - 'getData' - parses the data converting images into selected save mode (MathML by default).
|
|
61
|
+
* - 'mode' - recalculates the active element.
|
|
62
|
+
*/
|
|
63
|
+
addEditorListeners() {
|
|
64
|
+
const editor = this.editorObject;
|
|
65
|
+
|
|
66
|
+
if (typeof editor.config.wirislistenersdisabled === 'undefined'
|
|
67
|
+
|| !editor.config.wirislistenersdisabled) {
|
|
68
|
+
this.checkElement();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Checks the current container and assign events in case that it doesn't have them.
|
|
74
|
+
* CKEditor replaces several times the element element during its execution,
|
|
75
|
+
* so we must assign the events again to editor element.
|
|
76
|
+
*/
|
|
77
|
+
checkElement() {
|
|
78
|
+
const editor = this.editorObject;
|
|
79
|
+
const newElement = editor.sourceElement;
|
|
80
|
+
|
|
81
|
+
// If the element wasn't treated, add the events.
|
|
82
|
+
if (!newElement.wirisActive) {
|
|
83
|
+
this.setTarget(newElement);
|
|
84
|
+
this.addEvents();
|
|
85
|
+
// Set the element as treated
|
|
86
|
+
newElement.wirisActive = true;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @inheritdoc
|
|
92
|
+
* @param {HTMLElement} element - HTMLElement target.
|
|
93
|
+
* @param {MouseEvent} event - event which trigger the handler.
|
|
94
|
+
*/
|
|
95
|
+
doubleClickHandler(element, event) {
|
|
96
|
+
if (this.editorObject.isReadOnly === false) {
|
|
97
|
+
if (element.nodeName.toLowerCase() === 'img') {
|
|
98
|
+
if (Util.containsClass(element, Configuration.get('imageClassName'))) {
|
|
99
|
+
// Some plugins (image2, image) open a dialog on double click. On formulas
|
|
100
|
+
// doubleclick event ends here.
|
|
101
|
+
if (typeof event.stopPropagation !== 'undefined') { // old I.E compatibility.
|
|
102
|
+
event.stopPropagation();
|
|
103
|
+
} else {
|
|
104
|
+
event.returnValue = false;
|
|
105
|
+
}
|
|
106
|
+
this.core.getCustomEditors().disable();
|
|
107
|
+
const customEditorAttr = element.getAttribute(Configuration.get('imageCustomEditorName'));
|
|
108
|
+
if (customEditorAttr) {
|
|
109
|
+
this.core.getCustomEditors().enable(customEditorAttr);
|
|
110
|
+
}
|
|
111
|
+
this.core.editionProperties.temporalImage = element;
|
|
112
|
+
this.openExistingFormulaEditor();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** @inheritdoc */
|
|
119
|
+
static getCorePath() {
|
|
120
|
+
return null; // TODO
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** @inheritdoc */
|
|
124
|
+
callbackFunction() {
|
|
125
|
+
super.callbackFunction();
|
|
126
|
+
this.addEditorListeners();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
openNewFormulaEditor() {
|
|
130
|
+
// Store the editor selection as it will be lost upon opening the modal
|
|
131
|
+
this.core.editionProperties.selection = this.editorObject.editing.view.document.selection;
|
|
132
|
+
|
|
133
|
+
return super.openNewFormulaEditor();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Replaces old formula with new MathML or inserts it in caret position if new
|
|
138
|
+
* @param {String} mathml MathML to update old one or insert
|
|
139
|
+
* @returns {module:engine/model/element~Element} The model element corresponding to the inserted image
|
|
140
|
+
*/
|
|
141
|
+
insertMathml(mathml) {
|
|
142
|
+
// This returns the value returned by the callback function (writer => {...})
|
|
143
|
+
return this.editorObject.model.change((writer) => {
|
|
144
|
+
const core = this.getCore();
|
|
145
|
+
|
|
146
|
+
const modelElementNew = writer.createElement('mathml', { formula: mathml });
|
|
147
|
+
modelElementNew.data = mathml;
|
|
148
|
+
|
|
149
|
+
// Obtain the DOM <span><img ... /></span> object corresponding to the formula
|
|
150
|
+
if (core.editionProperties.isNewElement) {
|
|
151
|
+
// Don't bother inserting anything at all if the MathML is empty.
|
|
152
|
+
if (!mathml) return;
|
|
153
|
+
|
|
154
|
+
const viewSelection = this.core.editionProperties.selection || this.editorObject.editing.view.document.selection;
|
|
155
|
+
const modelPosition = this.editorObject.editing.mapper.toModelPosition(viewSelection.getLastPosition());
|
|
156
|
+
|
|
157
|
+
writer.insert(modelElementNew, modelPosition);
|
|
158
|
+
|
|
159
|
+
// Remove selection
|
|
160
|
+
if (!viewSelection.isCollapsed) {
|
|
161
|
+
for (const range of viewSelection.getRanges()) {
|
|
162
|
+
writer.remove(this.editorObject.editing.mapper.toModelRange(range));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
} else {
|
|
166
|
+
const img = core.editionProperties.temporalImage;
|
|
167
|
+
const viewElement = this.editorObject.editing.view.domConverter.domToView(img).parent;
|
|
168
|
+
const modelElementOld = this.editorObject.editing.mapper.toModelElement(viewElement);
|
|
169
|
+
|
|
170
|
+
// Insert the new <mathml> and remove the old one
|
|
171
|
+
const position = this.editorObject.model.createPositionBefore(modelElementOld);
|
|
172
|
+
|
|
173
|
+
// If the given MathML is empty, don't insert a new formula.
|
|
174
|
+
if (mathml) {
|
|
175
|
+
writer.insert(modelElementNew, position);
|
|
176
|
+
}
|
|
177
|
+
writer.remove(modelElementOld);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// eslint-disable-next-line consistent-return
|
|
181
|
+
return modelElementNew;
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Finds the text node corresponding to given DOM text element.
|
|
187
|
+
* @param {element} viewElement Element to find corresponding text node of.
|
|
188
|
+
* @returns {module:engine/model/text~Text|undefined} Text node corresponding to the given element or undefined if it doesn't exist.
|
|
189
|
+
*/
|
|
190
|
+
findText(viewElement) { // eslint-disable-line consistent-return
|
|
191
|
+
// mapper always converts text nodes to *new* model elements so we need to convert the text's parents and then come back down
|
|
192
|
+
let pivot = viewElement;
|
|
193
|
+
let element;
|
|
194
|
+
while (!element) {
|
|
195
|
+
element = this.editorObject.editing.mapper.toModelElement(
|
|
196
|
+
this.editorObject.editing.view.domConverter.domToView(
|
|
197
|
+
pivot,
|
|
198
|
+
),
|
|
199
|
+
);
|
|
200
|
+
pivot = pivot.parentElement;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Navigate through all the subtree under `pivot` in order to find the correct text node
|
|
204
|
+
const range = this.editorObject.model.createRangeIn(element);
|
|
205
|
+
const descendants = Array.from(range.getItems());
|
|
206
|
+
for (const node of descendants) {
|
|
207
|
+
if (node.is('textProxy') && node.data === viewElement.data.replace(String.fromCharCode(160), ' ')) {
|
|
208
|
+
return node.textNode;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/** @inheritdoc */
|
|
214
|
+
insertFormula(focusElement, windowTarget, mathml, wirisProperties) { // eslint-disable-line no-unused-vars
|
|
215
|
+
const returnObject = {};
|
|
216
|
+
|
|
217
|
+
if (!mathml) {
|
|
218
|
+
this.insertMathml('');
|
|
219
|
+
} else if (this.core.editMode === 'latex') {
|
|
220
|
+
returnObject.latex = Latex.getLatexFromMathML(mathml);
|
|
221
|
+
returnObject.node = windowTarget.document.createTextNode(`$$${returnObject.latex}$$`);
|
|
222
|
+
|
|
223
|
+
this.editorObject.model.change((writer) => {
|
|
224
|
+
const { latexRange } = this.core.editionProperties;
|
|
225
|
+
|
|
226
|
+
const startNode = this.findText(latexRange.startContainer);
|
|
227
|
+
const endNode = this.findText(latexRange.endContainer);
|
|
228
|
+
|
|
229
|
+
const startPosition = writer.createPositionAt(startNode.parent, startNode.startOffset + latexRange.startOffset);
|
|
230
|
+
const endPosition = writer.createPositionAt(endNode.parent, endNode.startOffset + latexRange.endOffset);
|
|
231
|
+
|
|
232
|
+
const range = writer.createRange(
|
|
233
|
+
startPosition,
|
|
234
|
+
endPosition,
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
writer.remove(range);
|
|
238
|
+
writer.insertText(`$$${returnObject.latex}$$`, startNode.getAttributes(), startPosition);
|
|
239
|
+
});
|
|
240
|
+
} else {
|
|
241
|
+
try {
|
|
242
|
+
returnObject.node = this.editorObject.editing.view.domConverter.viewToDom(
|
|
243
|
+
this.editorObject.editing.mapper.toViewElement(
|
|
244
|
+
this.insertMathml(mathml),
|
|
245
|
+
), windowTarget.document,
|
|
246
|
+
);
|
|
247
|
+
} catch (e) {
|
|
248
|
+
const x = e.toString();
|
|
249
|
+
if ((x).includes("CKEditorError: Cannot read property 'parent' of undefined")) {
|
|
250
|
+
this.core.modalDialog.cancelAction();
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/* Due to PLUGINS-1329, we add the onChange event to the CK4 insertFormula.
|
|
256
|
+
We probably should add it here as well, but we should look further into how */
|
|
257
|
+
// this.editorObject.fire('change');
|
|
258
|
+
|
|
259
|
+
return returnObject;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Function called when the content submits an action.
|
|
264
|
+
*/
|
|
265
|
+
notifyWindowClosed() {
|
|
266
|
+
this.editorObject.editing.view.focus();
|
|
267
|
+
}
|
|
268
|
+
}
|