@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/plugin.js
CHANGED
|
@@ -1,443 +1,419 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
import
|
|
18
|
-
import
|
|
19
|
-
import
|
|
20
|
-
import
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
import
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
import
|
|
27
|
-
import
|
|
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
|
-
|
|
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
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
/**
|
|
424
|
-
* Expose the WirisPlugin variable to the window
|
|
425
|
-
*/
|
|
426
|
-
_exposeWiris() {
|
|
427
|
-
|
|
428
|
-
window.WirisPlugin = {
|
|
429
|
-
Core: Core,
|
|
430
|
-
Parser: Parser,
|
|
431
|
-
Image: Image,
|
|
432
|
-
MathML: MathML,
|
|
433
|
-
Util: Util,
|
|
434
|
-
Configuration: Configuration,
|
|
435
|
-
Listeners: Listeners,
|
|
436
|
-
IntegrationModel: IntegrationModel,
|
|
437
|
-
currentInstance: currentInstance,
|
|
438
|
-
Latex: Latex
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
}
|
|
1
|
+
// CKEditor imports
|
|
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
|
+
|
|
11
|
+
// MathType API imports
|
|
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
|
+
|
|
22
|
+
// Local imports
|
|
23
|
+
import { MathTypeCommand, ChemTypeCommand } from './commands';
|
|
24
|
+
import CKEditor5Integration from './integration';
|
|
25
|
+
|
|
26
|
+
import mathIcon from '../theme/icons/formula.svg';
|
|
27
|
+
import chemIcon from '../theme/icons/chem.svg';
|
|
28
|
+
|
|
29
|
+
export let currentInstance = null; // eslint-disable-line import/no-mutable-exports
|
|
30
|
+
|
|
31
|
+
export default class MathType extends Plugin {
|
|
32
|
+
static get requires() {
|
|
33
|
+
return [Widget];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
static get pluginName() {
|
|
37
|
+
return 'MathType';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
init() {
|
|
41
|
+
// Create the MathType API Integration object
|
|
42
|
+
const integration = this._addIntegration();
|
|
43
|
+
currentInstance = integration;
|
|
44
|
+
|
|
45
|
+
// Add the MathType and ChemType commands to the editor
|
|
46
|
+
this._addCommands();
|
|
47
|
+
|
|
48
|
+
// Add the buttons for MathType and ChemType
|
|
49
|
+
this._addViews(integration);
|
|
50
|
+
|
|
51
|
+
// Registers the <mathml> element in the schema
|
|
52
|
+
this._addSchema();
|
|
53
|
+
|
|
54
|
+
// Add the downcast and upcast converters
|
|
55
|
+
this._addConverters();
|
|
56
|
+
|
|
57
|
+
// Expose the WirisPlugin variable to the window
|
|
58
|
+
this._exposeWiris();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Create the MathType API Integration object
|
|
63
|
+
* @returns {CKEditor5Integration} the integration object
|
|
64
|
+
*/
|
|
65
|
+
_addIntegration() {
|
|
66
|
+
const { editor } = this;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Integration model constructor attributes.
|
|
70
|
+
* @type {integrationModelProperties}
|
|
71
|
+
*/
|
|
72
|
+
const integrationProperties = {};
|
|
73
|
+
integrationProperties.environment = {};
|
|
74
|
+
integrationProperties.environment.editor = 'CKEditor5';
|
|
75
|
+
integrationProperties.environment.editorVersion = '5.x';
|
|
76
|
+
integrationProperties.editorObject = editor;
|
|
77
|
+
integrationProperties.serviceProviderProperties = {};
|
|
78
|
+
integrationProperties.serviceProviderProperties.URI = 'https://www.wiris.net/demo/plugins/app';
|
|
79
|
+
integrationProperties.serviceProviderProperties.server = 'java';
|
|
80
|
+
integrationProperties.target = editor.sourceElement;
|
|
81
|
+
integrationProperties.scriptName = 'bundle.js';
|
|
82
|
+
integrationProperties.managesLanguage = true;
|
|
83
|
+
// etc
|
|
84
|
+
|
|
85
|
+
// There are platforms like Drupal that initialize CKEditor but they hide or remove the container element.
|
|
86
|
+
// To avoid a wrong behaviour, this integration only starts if the workspace container exists.
|
|
87
|
+
let integration;
|
|
88
|
+
if (integrationProperties.target) {
|
|
89
|
+
// Instance of the integration associated to this editor instance
|
|
90
|
+
integration = new CKEditor5Integration(integrationProperties);
|
|
91
|
+
integration.init();
|
|
92
|
+
integration.listeners.fire('onTargetReady', {});
|
|
93
|
+
|
|
94
|
+
integration.checkElement();
|
|
95
|
+
|
|
96
|
+
this.listenTo(editor.editing.view.document, 'click', (evt, data) => {
|
|
97
|
+
// Is double click
|
|
98
|
+
if (data.domEvent.detail === 2) {
|
|
99
|
+
integration.doubleClickHandler(data.domTarget, data.domEvent);
|
|
100
|
+
evt.stop();
|
|
101
|
+
}
|
|
102
|
+
}, { priority: 'highest' });
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return integration;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Add the MathType and ChemType commands to the editor
|
|
110
|
+
*/
|
|
111
|
+
_addCommands() {
|
|
112
|
+
const { editor } = this;
|
|
113
|
+
|
|
114
|
+
// Add command to open the formula editor
|
|
115
|
+
editor.commands.add('MathType', new MathTypeCommand(editor));
|
|
116
|
+
|
|
117
|
+
// Add command to open the chemistry formula editor
|
|
118
|
+
editor.commands.add('ChemType', new ChemTypeCommand(editor));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Add the buttons for MathType and ChemType
|
|
123
|
+
* @param {CKEditor5Integration} integration the integration object
|
|
124
|
+
*/
|
|
125
|
+
_addViews(integration) {
|
|
126
|
+
const { editor } = this;
|
|
127
|
+
|
|
128
|
+
// Add button for the formula editor
|
|
129
|
+
editor.ui.componentFactory.add('MathType', (locale) => {
|
|
130
|
+
const view = new ButtonView(locale);
|
|
131
|
+
|
|
132
|
+
// View is enabled iff command is enabled
|
|
133
|
+
view.bind('isEnabled').to(editor.commands.get('MathType'), 'isEnabled');
|
|
134
|
+
|
|
135
|
+
view.set({
|
|
136
|
+
label: 'Insert a math equation - MathType',
|
|
137
|
+
icon: mathIcon,
|
|
138
|
+
tooltip: true,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Callback executed once the image is clicked.
|
|
142
|
+
view.on('execute', () => {
|
|
143
|
+
editor.execute('MathType', {
|
|
144
|
+
integration, // Pass integration as parameter
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
return view;
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Add button for the chemistry formula editor
|
|
152
|
+
editor.ui.componentFactory.add('ChemType', (locale) => {
|
|
153
|
+
const view = new ButtonView(locale);
|
|
154
|
+
|
|
155
|
+
// View is enabled iff command is enabled
|
|
156
|
+
view.bind('isEnabled').to(editor.commands.get('ChemType'), 'isEnabled');
|
|
157
|
+
|
|
158
|
+
view.set({
|
|
159
|
+
label: 'Insert a chemistry formula - ChemType',
|
|
160
|
+
icon: chemIcon,
|
|
161
|
+
tooltip: true,
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// Callback executed once the image is clicked.
|
|
165
|
+
view.on('execute', () => {
|
|
166
|
+
editor.execute('ChemType', {
|
|
167
|
+
integration, // Pass integration as parameter
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
return view;
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// Observer for the double click event
|
|
175
|
+
editor.editing.view.addObserver(ClickObserver);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Registers the <mathml> element in the schema
|
|
180
|
+
*/
|
|
181
|
+
_addSchema() {
|
|
182
|
+
const { schema } = this.editor.model;
|
|
183
|
+
|
|
184
|
+
schema.register('mathml', {
|
|
185
|
+
allowWhere: '$text',
|
|
186
|
+
isObject: true,
|
|
187
|
+
isInline: true,
|
|
188
|
+
allowAttributes: ['formula'],
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Add the downcast and upcast converters
|
|
194
|
+
*/
|
|
195
|
+
_addConverters() {
|
|
196
|
+
const { editor } = this;
|
|
197
|
+
|
|
198
|
+
// Editing view -> Model
|
|
199
|
+
editor.conversion.for('upcast').elementToElement({
|
|
200
|
+
view: {
|
|
201
|
+
name: 'span',
|
|
202
|
+
classes: 'ck-math-widget',
|
|
203
|
+
},
|
|
204
|
+
model: (viewElement, { writer: modelWriter }) => {
|
|
205
|
+
const formula = MathML.safeXmlDecode(viewElement.getChild(0).getAttribute('data-mathml'));
|
|
206
|
+
return modelWriter.createElement('mathml', {
|
|
207
|
+
formula,
|
|
208
|
+
});
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
// Data view -> Model
|
|
213
|
+
editor.data.upcastDispatcher.on('element:math', (evt, data, conversionApi) => {
|
|
214
|
+
const { consumable, writer } = conversionApi;
|
|
215
|
+
const { viewItem } = data;
|
|
216
|
+
|
|
217
|
+
// When element was already consumed then skip it.
|
|
218
|
+
if (!consumable.test(viewItem, { name: true })) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// If we encounter any <math> with a LaTeX annotation inside,
|
|
223
|
+
// convert it into a "$$...$$" string.
|
|
224
|
+
const isLatex = mathIsLatex(viewItem); // eslint-disable-line no-use-before-define
|
|
225
|
+
|
|
226
|
+
// Get the formula of the <math> (which is all its children).
|
|
227
|
+
const processor = new XmlDataProcessor(editor.editing.view.document);
|
|
228
|
+
|
|
229
|
+
// Only god knows why the following line makes viewItem lose all of its children,
|
|
230
|
+
// so we obtain isLatex before doing this because we need viewItem's children for that.
|
|
231
|
+
const upcastWriter = new UpcastWriter(editor.editing.view.document);
|
|
232
|
+
const viewDocumentFragment = upcastWriter.createDocumentFragment(viewItem.getChildren());
|
|
233
|
+
|
|
234
|
+
// and obtain the attributes of <math> too!
|
|
235
|
+
const mathAttributes = [...viewItem.getAttributes()]
|
|
236
|
+
.map(([key, value]) => ` ${key}="${value}"`)
|
|
237
|
+
.join('');
|
|
238
|
+
|
|
239
|
+
// We process the document fragment
|
|
240
|
+
let formula = processor.toData(viewDocumentFragment) || '';
|
|
241
|
+
|
|
242
|
+
// And obtain the complete formula
|
|
243
|
+
formula = `<math${mathAttributes}>${formula}</math>`;
|
|
244
|
+
|
|
245
|
+
/* Model node that contains what's going to actually be inserted. This can be either:
|
|
246
|
+
- A <mathml> element with a formula attribute set to the given formula, or
|
|
247
|
+
- If the original <math> had a LaTeX annotation, then the annotation surrounded by "$$...$$" */
|
|
248
|
+
const modelNode = isLatex
|
|
249
|
+
? writer.createText(Parser.initParse(formula, editor.config.get('language')))
|
|
250
|
+
: writer.createElement('mathml', { formula });
|
|
251
|
+
modelNode.data = formula;
|
|
252
|
+
|
|
253
|
+
// Find allowed parent for element that we are going to insert.
|
|
254
|
+
// If current parent does not allow to insert element but one of the ancestors does
|
|
255
|
+
// then split nodes to allowed parent.
|
|
256
|
+
const splitResult = conversionApi.splitToAllowedParent(modelNode, data.modelCursor);
|
|
257
|
+
|
|
258
|
+
// When there is no split result it means that we can't insert element to model tree, so let's skip it.
|
|
259
|
+
if (!splitResult) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Insert element on allowed position.
|
|
264
|
+
conversionApi.writer.insert(modelNode, splitResult.position);
|
|
265
|
+
|
|
266
|
+
// Consume appropriate value from consumable values list.
|
|
267
|
+
consumable.consume(viewItem, { name: true });
|
|
268
|
+
|
|
269
|
+
const parts = conversionApi.getSplitParts(modelNode);
|
|
270
|
+
|
|
271
|
+
// Set conversion result range.
|
|
272
|
+
data.modelRange = writer.createRange(
|
|
273
|
+
conversionApi.writer.createPositionBefore(modelNode),
|
|
274
|
+
conversionApi.writer.createPositionAfter(parts[parts.length - 1]),
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
// Now we need to check where the `modelCursor` should be.
|
|
278
|
+
if (splitResult.cursorParent) {
|
|
279
|
+
// If we split parent to insert our element then we want to continue conversion in the new part of the split parent.
|
|
280
|
+
//
|
|
281
|
+
// before: <allowed><notAllowed>foo[]</notAllowed></allowed>
|
|
282
|
+
// after: <allowed><notAllowed>foo</notAllowed><converted></converted><notAllowed>[]</notAllowed></allowed>
|
|
283
|
+
|
|
284
|
+
data.modelCursor = conversionApi.writer.createPositionAt(splitResult.cursorParent, 0);
|
|
285
|
+
} else {
|
|
286
|
+
// Otherwise just continue after inserted element.
|
|
287
|
+
data.modelCursor = data.modelRange.end;
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Whether the given view <math> element has a LaTeX annotation element.
|
|
293
|
+
* @param {*} math
|
|
294
|
+
* @returns {bool}
|
|
295
|
+
*/
|
|
296
|
+
function mathIsLatex(math) {
|
|
297
|
+
const semantics = math.getChild(0);
|
|
298
|
+
if (!semantics || semantics.name !== 'semantics') return false;
|
|
299
|
+
for (const child of semantics.getChildren()) {
|
|
300
|
+
if (child.name === 'annotation' && child.getAttribute('encoding') === 'LaTeX') {
|
|
301
|
+
return true;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function createViewWidget(modelItem, { writer: viewWriter }) {
|
|
308
|
+
const widgetElement = viewWriter.createContainerElement('span', {
|
|
309
|
+
class: 'ck-math-widget',
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
const mathUIElement = createViewImage(modelItem, { writer: viewWriter }); // eslint-disable-line no-use-before-define
|
|
313
|
+
|
|
314
|
+
viewWriter.insert(viewWriter.createPositionAt(widgetElement, 0), mathUIElement);
|
|
315
|
+
|
|
316
|
+
return toWidget(widgetElement, viewWriter);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function createViewImage(modelItem, { writer: viewWriter }) {
|
|
320
|
+
const htmlDataProcessor = new HtmlDataProcessor(viewWriter.document);
|
|
321
|
+
|
|
322
|
+
const mathString = modelItem.getAttribute('formula');
|
|
323
|
+
const imgHtml = Parser.initParse(mathString, editor.config.get('language'));
|
|
324
|
+
const imgElement = htmlDataProcessor.toView(imgHtml).getChild(0);
|
|
325
|
+
|
|
326
|
+
/* Although we use the HtmlDataProcessor to obtain the attributes,
|
|
327
|
+
we must create a new EmptyElement which is independent of the
|
|
328
|
+
DataProcessor being used by this editor instance */
|
|
329
|
+
return viewWriter.createEmptyElement('img', imgElement.getAttributes(), {
|
|
330
|
+
renderUnsafeAttributes: [ 'src' ]
|
|
331
|
+
} );
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Model -> Editing view
|
|
335
|
+
editor.conversion.for('editingDowncast').elementToElement({
|
|
336
|
+
model: 'mathml',
|
|
337
|
+
view: createViewWidget,
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
// Model -> Data view
|
|
341
|
+
editor.conversion.for('dataDowncast').elementToElement({
|
|
342
|
+
model: 'mathml',
|
|
343
|
+
view: createDataString, // eslint-disable-line no-use-before-define
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Makes a copy of the given view node.
|
|
348
|
+
* @param {module:engine/view/node~Node} sourceNode Node to copy.
|
|
349
|
+
* @returns {module:engine/view/node~Node} Copy of the node.
|
|
350
|
+
*/
|
|
351
|
+
function clone(viewWriter, sourceNode) {
|
|
352
|
+
if (sourceNode.is('text')) {
|
|
353
|
+
return viewWriter.createText(sourceNode.data);
|
|
354
|
+
} if (sourceNode.is('element')) {
|
|
355
|
+
if (sourceNode.is('emptyElement')) {
|
|
356
|
+
return viewWriter.createEmptyElement(sourceNode.name, sourceNode.getAttributes());
|
|
357
|
+
}
|
|
358
|
+
const element = viewWriter.createContainerElement(sourceNode.name, sourceNode.getAttributes());
|
|
359
|
+
for (const child of sourceNode.getChildren()) {
|
|
360
|
+
viewWriter.insert(viewWriter.createPositionAt(element, 'end'), clone(viewWriter, child));
|
|
361
|
+
}
|
|
362
|
+
return element;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
throw new Exception('Given node has unsupported type.'); // eslint-disable-line no-undef
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function createDataString(modelItem, { writer: viewWriter }) {
|
|
369
|
+
const htmlDataProcessor = new HtmlDataProcessor(viewWriter.document);
|
|
370
|
+
|
|
371
|
+
let mathString = Parser.endParseSaveMode(modelItem.getAttribute('formula'));
|
|
372
|
+
|
|
373
|
+
// Remove the traces from Hand. This code should be removed once PLUGINS-1307 is solved.
|
|
374
|
+
if (!Configuration.get('saveHandTraces')) {
|
|
375
|
+
mathString = MathML.removeAnnotation(mathString, 'application/json');
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
const sourceMathElement = htmlDataProcessor.toView(mathString).getChild(0);
|
|
379
|
+
|
|
380
|
+
return clone(viewWriter, sourceMathElement);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// This stops the view selection getting into the <span>s and messing up caret movement
|
|
384
|
+
editor.editing.mapper.on(
|
|
385
|
+
'viewToModelPosition',
|
|
386
|
+
viewToModelPositionOutsideModelElement(editor.model, (viewElement) => viewElement.hasClass('ck-math-widget')),
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
// Keep a reference to the original get function
|
|
390
|
+
const { get } = editor.data;
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Hack to transform $$latex$$ into <math> in editor.getData()'s output.
|
|
394
|
+
*/
|
|
395
|
+
editor.data.get = (options) => {
|
|
396
|
+
const output = get.bind(editor.data)(options);
|
|
397
|
+
return Parser.endParse(output);
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Expose the WirisPlugin variable to the window
|
|
403
|
+
*/
|
|
404
|
+
// eslint-disable-next-line class-methods-use-this
|
|
405
|
+
_exposeWiris() {
|
|
406
|
+
window.WirisPlugin = {
|
|
407
|
+
Core,
|
|
408
|
+
Parser,
|
|
409
|
+
Image,
|
|
410
|
+
MathML,
|
|
411
|
+
Util,
|
|
412
|
+
Configuration,
|
|
413
|
+
Listeners,
|
|
414
|
+
IntegrationModel,
|
|
415
|
+
currentInstance,
|
|
416
|
+
Latex,
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
}
|