suneditor 3.0.0-alpha.13 → 3.0.0-alpha.15

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.
Files changed (35) hide show
  1. package/dist/suneditor.min.css +1 -1
  2. package/dist/suneditor.min.js +1 -1
  3. package/package.json +2 -1
  4. package/src/assets/icons/_default.js +9 -2
  5. package/src/assets/suneditor-contents.css +9 -22
  6. package/src/assets/suneditor.css +317 -183
  7. package/src/assets/variables.css +137 -0
  8. package/src/core/base/eventHandlers/handler_toolbar.js +1 -0
  9. package/src/core/base/eventHandlers/handler_ww_dragDrop.js +9 -2
  10. package/src/core/base/eventHandlers/handler_ww_key_input.js +1 -1
  11. package/src/core/base/eventManager.js +5 -0
  12. package/src/core/class/component.js +12 -8
  13. package/src/core/class/html.js +5 -5
  14. package/src/core/class/offset.js +11 -3
  15. package/src/core/class/selection.js +5 -4
  16. package/src/core/class/toolbar.js +1 -5
  17. package/src/core/class/viewer.js +29 -7
  18. package/src/core/editor.js +61 -1
  19. package/src/core/section/actives.js +5 -0
  20. package/src/core/section/constructor.js +35 -19
  21. package/src/core/section/documentType.js +143 -19
  22. package/src/helper/domUtils.js +5 -4
  23. package/src/langs/en.js +5 -0
  24. package/src/modules/Modal.js +108 -1
  25. package/src/plugins/command/exportPdf.js +1 -1
  26. package/src/plugins/command/list_bulleted.js +1 -1
  27. package/src/plugins/command/list_numbered.js +1 -1
  28. package/src/plugins/index.js +6 -0
  29. package/src/plugins/input/fontSize.js +3 -3
  30. package/src/plugins/input/pageNavigator.js +47 -0
  31. package/src/plugins/modal/drawing.js +426 -0
  32. package/src/plugins/modal/image.js +3 -2
  33. package/src/plugins/modal/math.js +72 -34
  34. package/src/themes/dark-variables.css +85 -0
  35. package/src/themes/test.css +0 -61
@@ -109,18 +109,18 @@ const FontSize = function (editor, pluginOptions) {
109
109
 
110
110
  // increase, decrease buttons
111
111
  if (showIncDec) {
112
- this.beforeButton = domUtils.createElement(
112
+ this.beforeItem = domUtils.createElement(
113
113
  'button',
114
114
  { class: 'se-btn se-tooltip se-sub-btn', 'data-command': FontSize.key, 'data-type': 'command', 'data-value': 'dec' },
115
115
  `${this.icons.minus}<span class="se-tooltip-inner"><span class="se-tooltip-text">${this.lang.decrease}</span></span>`
116
116
  );
117
- this.afterButton = domUtils.createElement(
117
+ this.afterItem = domUtils.createElement(
118
118
  'button',
119
119
  { class: 'se-btn se-tooltip se-sub-btn', 'data-command': FontSize.key, 'data-type': 'command', 'data-value': 'inc' },
120
120
  `${this.icons.plus}<span class="se-tooltip-inner"><span class="se-tooltip-text">${this.lang.increase}</span></span>`
121
121
  );
122
122
  } else if (!disableInput) {
123
- this.afterButton = domUtils.createElement(
123
+ this.afterItem = domUtils.createElement(
124
124
  'button',
125
125
  { class: 'se-btn se-tooltip se-sub-arrow-btn', 'data-command': FontSize.key, 'data-type': 'dropdown' },
126
126
  `${this.icons.arrow_down}<span class="se-tooltip-inner"><span class="se-tooltip-text">${this.lang.fontSize}</span></span>`
@@ -0,0 +1,47 @@
1
+ import EditorInjector from '../../editorInjector';
2
+ import { domUtils } from '../../helper';
3
+
4
+ const PageNavigator = function (editor) {
5
+ EditorInjector.call(this, editor);
6
+
7
+ // create HTML
8
+ this.title = this.lang.pageNumber;
9
+ this.inner = CreateInner();
10
+ this.afterItem = domUtils.createElement('span', { class: 'se-btn se-sub-btn' }, ``);
11
+
12
+ // members
13
+ this.pageNum = 1;
14
+ this.totalPages = 1;
15
+
16
+ // init
17
+ this.eventManager.addEvent(this.inner, 'change', OnChangeInner.bind(this));
18
+ };
19
+
20
+ PageNavigator.key = 'pageNavigator';
21
+ PageNavigator.type = 'input';
22
+ PageNavigator.className = 'se-btn-input se-btn-tool-pageNavigator';
23
+ PageNavigator.prototype = {
24
+ /**
25
+ * @override core
26
+ */
27
+ display(pageNum, totalPages) {
28
+ this.inner.value = this.pageNum = pageNum;
29
+ this.afterItem.textContent = this.totalPages = totalPages;
30
+ this.inner.max = totalPages;
31
+ },
32
+
33
+ constructor: PageNavigator
34
+ };
35
+
36
+ function OnChangeInner({ target }) {
37
+ if (!this.editor.frameContext.has('documentType-use-page')) return;
38
+
39
+ const value = target.value || 1;
40
+ this.editor.frameContext.get('documentType').pageGo(value);
41
+ }
42
+
43
+ function CreateInner() {
44
+ return domUtils.createElement('input', { type: 'number', class: 'se-not-arrow-text', placeholder: '1', value: '1', min: '1' }, null);
45
+ }
46
+
47
+ export default PageNavigator;
@@ -0,0 +1,426 @@
1
+ import EditorInjector from '../../editorInjector';
2
+ import { Modal } from '../../modules';
3
+ import { domUtils, env } from '../../helper';
4
+ import { CreateTooltipInner } from '../../core/section/constructor';
5
+
6
+ const { _w, isMobile } = env;
7
+
8
+ const Drawing = function (editor, pluginOptions) {
9
+ // plugin basic properties
10
+ EditorInjector.call(this, editor);
11
+ this.title = this.lang.drawing;
12
+ this.icon = 'drawing';
13
+ this.pluginOptions = {
14
+ outputFormat: pluginOptions.outputFormat || 'dataurl', // dataurl, svg
15
+ useFormatType: pluginOptions.useFormatType ?? false,
16
+ defaultFormatType: ['block', 'inline'].includes(pluginOptions.defaultFormatType) ? pluginOptions.defaultFormatType : 'block',
17
+ keepFormatType: pluginOptions.keepFormatType ?? false,
18
+ lineWidth: pluginOptions.lineWidth || 5,
19
+ lineReconnect: !!pluginOptions.lineReconnect,
20
+ lineCap: ['butt', 'round', 'square'].includes(pluginOptions.lineCap) ? pluginOptions.lineCap : 'round',
21
+ lineColor: pluginOptions.lineColor || '',
22
+ formSize: {
23
+ width: '750px',
24
+ height: '50vh',
25
+ maxWidth: '',
26
+ maxHeight: '',
27
+ minWidth: '150px',
28
+ minHeight: '100px',
29
+ ...pluginOptions.formSize
30
+ },
31
+ canResize: pluginOptions.canResize ?? true,
32
+ maintainRatio: pluginOptions.maintainRatio ?? true
33
+ };
34
+
35
+ // exception
36
+ if (!this.plugins.image) {
37
+ console.warn('[SUNEDITOR.plugins.drawing.warn] The drawing plugin must need either "image" plugin. Please add the "image" plugin.');
38
+ } else if (this.pluginOptions.outputFormat === 'svg' && !this.plugins.image.pluginOptions.uploadUrl) {
39
+ console.warn('[SUNEDITOR.plugins.drawing.warn] The drawing plugin must need the "image" plugin with the "uploadUrl" option. Please add the "image" plugin with the "uploadUrl" option.');
40
+ }
41
+
42
+ // create HTML
43
+ const modalEl = CreateHTML_modal(this);
44
+
45
+ // modules
46
+ this.modal = new Modal(this, modalEl);
47
+
48
+ // members
49
+ this.as = this.pluginOptions.defaultFormatType;
50
+ if (this.pluginOptions.useFormatType) {
51
+ this.asBlock = modalEl.querySelector('[data-command="asBlock"]');
52
+ this.asInline = modalEl.querySelector('[data-command="asInline"]');
53
+ this.eventManager.addEvent([this.asBlock, this.asInline], 'click', OnClickAsButton.bind(this));
54
+ }
55
+
56
+ this.canvas = null;
57
+ this.ctx = null;
58
+ this.isDrawing = false;
59
+ this.points = [];
60
+ this.paths = [];
61
+ this.resizeObserver = null;
62
+ this.__events = {
63
+ mousedown: isMobile ? OnCanvasTouchStart.bind(this) : OnCanvasMouseDown.bind(this),
64
+ mousemove: isMobile ? OnCanvasTouchMove.bind(this) : OnCanvasMouseMove.bind(this),
65
+ mouseup: OnCanvasMouseUp.bind(this),
66
+ mouseleave: OnCanvasMouseLeave.bind(this),
67
+ mouseenter: OnCanvasMouseEnter.bind(this)
68
+ };
69
+ this.__eventsRegister = {
70
+ mousedown: null,
71
+ mousemove: null,
72
+ mouseup: null,
73
+ mouseleave: null,
74
+ mouseenter: null
75
+ };
76
+ this.__eventNameMap = {
77
+ mousedown: isMobile ? 'touchstart' : 'mousedown',
78
+ mousemove: isMobile ? 'touchmove' : 'mousemove',
79
+ mouseup: isMobile ? 'touchend' : 'mouseup',
80
+ mouseleave: 'mouseleave',
81
+ mouseenter: 'mouseenter'
82
+ };
83
+
84
+ // init
85
+ this.eventManager.addEvent(modalEl.querySelector('[data-command="remove"]'), 'click', OnRemove.bind(this));
86
+ };
87
+
88
+ Drawing.key = 'drawing';
89
+ Drawing.type = 'modal';
90
+ Drawing.className = '';
91
+ Drawing.prototype = {
92
+ /**
93
+ * @override type = "modal"
94
+ */
95
+ open() {
96
+ if (this.pluginOptions.useFormatType) {
97
+ this._activeAsInline((this.pluginOptions.keepFormatType ? this.as : this.pluginOptions.defaultFormatType) === 'inline');
98
+ }
99
+ this.modal.open();
100
+ this._initDrawing();
101
+ },
102
+
103
+ /**
104
+ * @override modal
105
+ */
106
+ off() {
107
+ this._destroyDrawing();
108
+ },
109
+
110
+ /**
111
+ * @override modal
112
+ * @returns {string}
113
+ */
114
+ modalAction() {
115
+ if (this.pluginOptions.outputFormat === 'svg') {
116
+ const files = this._getSVGFileList();
117
+ this.plugins.image.init();
118
+ this.plugins.image.submitFile(files);
119
+ } else {
120
+ // dataurl | svg
121
+ const data = this.canvas.toDataURL();
122
+ const file = { name: 'drawing', size: 0 };
123
+ this.plugins.image.init();
124
+ if (this.as !== 'inline') {
125
+ this.plugins.image.create(data, null, 'auto', '', 'none', file, '');
126
+ } else {
127
+ this.plugins.image.createInline(data, null, 'auto', '', 'none', file, '');
128
+ }
129
+ }
130
+
131
+ return true;
132
+ },
133
+
134
+ _initDrawing() {
135
+ const canvas = (this.canvas = this.modal.form.querySelector('.se-drawing-canvas'));
136
+ this.ctx = canvas.getContext('2d');
137
+ canvas.width = canvas.offsetWidth;
138
+ canvas.height = canvas.offsetHeight;
139
+
140
+ this.points = [];
141
+ this.paths = [];
142
+
143
+ this._setCtx();
144
+
145
+ this.__eventsRegister.mousedown = this.eventManager.addEvent(canvas, this.__eventNameMap.mousedown, this.__events.mousedown, { passive: false, useCapture: true });
146
+ this.__eventsRegister.mousemove = this.eventManager.addEvent(canvas, this.__eventNameMap.mousemove, this.__events.mousemove, true);
147
+ this.__eventsRegister.mouseup = this.eventManager.addEvent(canvas, this.__eventNameMap.mouseup, this.__events.mouseup, true);
148
+ this.__eventsRegister.mouseleave = this.eventManager.addEvent(canvas, this.__eventNameMap.mouseleave, this.__events.mouseleave);
149
+ this.__eventsRegister.mouseenter = this.eventManager.addEvent(canvas, this.__eventNameMap.mouseenter, this.__events.mouseenter);
150
+
151
+ if (this.resizeObserver) {
152
+ this.resizeObserver.disconnect();
153
+ this.resizeObserver = null;
154
+ }
155
+
156
+ this.resizeObserver = new ResizeObserver(() => {
157
+ const prevWidth = canvas.width;
158
+ const prevHeight = canvas.height;
159
+ const newWidth = canvas.offsetWidth;
160
+ const newHeight = canvas.offsetHeight;
161
+ canvas.width = newWidth;
162
+ canvas.height = newHeight;
163
+ if (prevWidth !== canvas.width || prevHeight !== canvas.height) {
164
+ if (this.pluginOptions.maintainRatio) this._adjustPathsToNewDimensions(prevWidth, prevHeight, newWidth, newHeight);
165
+ this._drawAll();
166
+ }
167
+ });
168
+
169
+ this.resizeObserver.observe(canvas);
170
+ },
171
+
172
+ _destroyDrawing() {
173
+ if (this.resizeObserver) {
174
+ this.resizeObserver.disconnect();
175
+ this.resizeObserver = null;
176
+ }
177
+
178
+ if (this.canvas) {
179
+ this.eventManager.removeEvent(this.__eventsRegister.mousedown);
180
+ this.eventManager.removeEvent(this.__eventsRegister.mousemove);
181
+ this.eventManager.removeEvent(this.__eventsRegister.mouseup);
182
+ this.eventManager.removeEvent(this.__eventsRegister.mouseleave);
183
+ this.eventManager.removeEvent(this.__eventsRegister.mouseenter);
184
+ }
185
+
186
+ this.canvas = null;
187
+ this.ctx = null;
188
+ this.points = [];
189
+ this.paths = [];
190
+ this.isDrawing = false;
191
+ },
192
+
193
+ _setCtx() {
194
+ this.ctx.lineWidth = this.pluginOptions.lineWidth;
195
+ this.ctx.lineCap = this.pluginOptions.lineCap;
196
+ this.ctx.lineColor = this.pluginOptions.lineColor || _w.getComputedStyle(this.carrierWrapper).color;
197
+ },
198
+
199
+ _draw() {
200
+ this._setCtx();
201
+ this.ctx.beginPath();
202
+ this.points.forEach(([x, y], i) => {
203
+ if (i === 0) {
204
+ this.ctx.moveTo(x, y);
205
+ } else {
206
+ this.ctx.lineTo(x, y);
207
+ }
208
+ });
209
+ this.ctx.stroke();
210
+ },
211
+
212
+ _drawAll() {
213
+ this._setCtx();
214
+ this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
215
+ this.paths.forEach((path) => {
216
+ this.points = path;
217
+ this._draw();
218
+ });
219
+ this.points = [];
220
+ },
221
+
222
+ _adjustPathsToNewDimensions(prevWidth, prevHeight, newWidth, newHeight) {
223
+ const xRatio = newWidth / prevWidth;
224
+ const yRatio = newHeight / prevHeight;
225
+
226
+ this.paths = this.paths.map((path) => path.map(([x, y]) => [x * xRatio, y * yRatio]));
227
+ },
228
+
229
+ _clearCanvas() {
230
+ this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
231
+ this.points = [];
232
+ this.paths = [];
233
+ },
234
+
235
+ _getSVG() {
236
+ const svgNS = 'http://www.w3.org/2000/svg';
237
+ const svg = document.createElementNS(svgNS, 'svg');
238
+ svg.setAttribute('width', this.canvas.width);
239
+ svg.setAttribute('height', this.canvas.height);
240
+ svg.setAttribute('viewBox', `0 0 ${this.canvas.width} ${this.canvas.height}`);
241
+ svg.setAttribute('xmlns', svgNS);
242
+
243
+ this.paths.forEach((path) => {
244
+ const pathData = path.reduce((acc, [x, y], i) => {
245
+ return acc + (i === 0 ? `M ${x} ${y}` : ` L ${x} ${y}`);
246
+ }, '');
247
+ const svgPath = document.createElementNS(svgNS, 'path');
248
+ svgPath.setAttribute('d', pathData);
249
+ svgPath.setAttribute('fill', 'none');
250
+ svgPath.setAttribute('stroke', this.ctx.strokeStyle);
251
+ svgPath.setAttribute('stroke-width', this.ctx.lineWidth);
252
+ svg.appendChild(svgPath);
253
+ });
254
+
255
+ return svg;
256
+ },
257
+
258
+ _getSVGFileList() {
259
+ const svgElement = this._getSVG();
260
+ const serializer = new XMLSerializer();
261
+ const svgString = serializer.serializeToString(svgElement);
262
+ const blob = new Blob([svgString], { type: 'image/svg+xml' });
263
+ const file = new File([blob], 'drawing.svg', { type: 'image/svg+xml' });
264
+
265
+ // Creating a FileList
266
+ const dataTransfer = new DataTransfer();
267
+ dataTransfer.items.add(file);
268
+
269
+ return dataTransfer.files;
270
+ },
271
+
272
+ _getCanvasTouchPointer(e) {
273
+ const { touches } = e;
274
+ const rect = this.canvas.getBoundingClientRect();
275
+ const x = touches[0].clientX - rect.left;
276
+ const y = touches[0].clientY - rect.top;
277
+ return { x, y };
278
+ },
279
+
280
+ _activeAsInline(isInline) {
281
+ if (isInline) {
282
+ domUtils.addClass(this.asInline, 'on');
283
+ domUtils.removeClass(this.asBlock, 'on');
284
+ this.as = 'inline';
285
+ } else {
286
+ domUtils.addClass(this.asBlock, 'on');
287
+ domUtils.removeClass(this.asInline, 'on');
288
+ this.as = 'block';
289
+ }
290
+ },
291
+
292
+ constructor: Drawing
293
+ };
294
+
295
+ function CreateHTML_modal({ lang, icons, pluginOptions }) {
296
+ const { width, height, maxWidth, maxHeight, minWidth, minHeight } = pluginOptions.formSize;
297
+ const html = /*html*/ `
298
+ <form>
299
+ <div class="se-modal-header">
300
+ <button type="button" data-command="close" class="se-btn se-close-btn" title="${lang.close}" aria-label="${lang.close}">
301
+ ${icons.cancel}
302
+ </button>
303
+ <span class="se-modal-title">${lang.drawing_modal_title}</span>
304
+ </div>
305
+ <div class="se-modal-body" style="width: ${width}; height: ${height}; min-width: ${minWidth}; min-height: ${minHeight};">
306
+ <canvas class="se-drawing-canvas" style="width: 100%; height: 100%;"></canvas>
307
+ ${pluginOptions.canResize ? '<div class="se-modal-resize-handle-w"></div><div class="se-modal-resize-handle-h"></div><div class="se-modal-resize-handle-c"></div>' : ''}
308
+ </div>
309
+ <div class="se-modal-body-bottom">
310
+ <div class="se-modal-form">
311
+ <div class="se-modal-flex-form">
312
+ ${
313
+ pluginOptions.useFormatType
314
+ ? /*html*/ `
315
+ <div class="se-modal-flex-group">
316
+ <button type="button" class="se-btn se-tooltip" data-command="asBlock" aria-label="${lang.blockStyle}">
317
+ ${icons.as_block}
318
+ ${CreateTooltipInner(lang.blockStyle)}
319
+ </button>
320
+ <button type="button" class="se-btn se-tooltip" data-command="asInline" aria-label="${lang.inlineStyle}">
321
+ ${icons.as_inline}
322
+ ${CreateTooltipInner(lang.inlineStyle)}
323
+ </button>
324
+ </div>`
325
+ : ''
326
+ }
327
+ <div class="se-modal-flex-group">
328
+ <button type="button" class="se-btn se-tooltip" data-command="remove" aria-label="${lang.remove}">
329
+ ${icons.eraser}
330
+ ${CreateTooltipInner(lang.remove)}
331
+ </button>
332
+ </div>
333
+ </div>
334
+ </div>
335
+ </div>
336
+ <div class="se-modal-footer">
337
+ <button type="submit" class="se-btn-primary" title="${lang.submitButton}" aria-label="${lang.submitButton}">
338
+ <span>${lang.submitButton}</span>
339
+ </button>
340
+ </div>
341
+ </form>`;
342
+
343
+ return domUtils.createElement(
344
+ 'DIV',
345
+ {
346
+ class: 'se-modal-content se-modal-responsive',
347
+ style: `max-width: ${maxWidth}; max-height: ${maxHeight};`
348
+ },
349
+ html
350
+ );
351
+ }
352
+
353
+ // canvas events
354
+ function OnCanvasMouseDown(e) {
355
+ e.preventDefault();
356
+ this.isDrawing = true;
357
+ this.points.push([e.offsetX, e.offsetY]);
358
+ this._draw();
359
+ }
360
+
361
+ function OnCanvasMouseMove(e) {
362
+ e.preventDefault();
363
+ if (!this.isDrawing) return;
364
+ this.points.push([e.offsetX, e.offsetY]);
365
+ this._draw();
366
+ }
367
+
368
+ function OnCanvasTouchStart(e) {
369
+ e.preventDefault();
370
+ const { x, y } = this._getCanvasTouchPointer(e);
371
+ this.isDrawing = true;
372
+ this.points.push([x, y]);
373
+ this._draw();
374
+ }
375
+
376
+ function OnCanvasTouchMove(e) {
377
+ e.preventDefault();
378
+ const { x, y } = this._getCanvasTouchPointer(e);
379
+ if (!this.isDrawing) return;
380
+ this.points.push([x, y]);
381
+ this._draw();
382
+ }
383
+
384
+ function OnCanvasMouseUp() {
385
+ this.isDrawing = false;
386
+ if (this.points.length > 0) {
387
+ this.paths.push([...this.points]);
388
+ this.points = [];
389
+ }
390
+ }
391
+
392
+ function OnCanvasMouseLeave() {
393
+ if (this.isDrawing) {
394
+ this.paths.push([...this.points]);
395
+ if (!this.pluginOptions.lineReconnect) {
396
+ this.points = [];
397
+ this.isDrawing = false;
398
+ }
399
+ }
400
+ }
401
+
402
+ function OnCanvasMouseEnter(e) {
403
+ if (e.buttons === 1) {
404
+ this.isDrawing = true;
405
+ if (!this.pluginOptions.lineReconnect) {
406
+ this.points.push([e.offsetX, e.offsetY]);
407
+ } else {
408
+ const lastPath = this.paths[this.paths.length - 1];
409
+ const lastPoint = lastPath[lastPath.length - 1];
410
+ this.points.push([lastPoint[0], lastPoint[1]]);
411
+ this.points.push([e.offsetX, e.offsetY]);
412
+ }
413
+ this._draw();
414
+ }
415
+ }
416
+
417
+ // button events
418
+ function OnRemove() {
419
+ this._clearCanvas();
420
+ }
421
+
422
+ function OnClickAsButton({ target }) {
423
+ this._activeAsInline(target.getAttribute('data-command') === 'asInline');
424
+ }
425
+
426
+ export default Drawing;
@@ -26,7 +26,8 @@ const Image_ = function (editor, pluginOptions) {
26
26
  allowMultiple: !!pluginOptions.allowMultiple,
27
27
  acceptedFormats: typeof pluginOptions.acceptedFormats !== 'string' || pluginOptions.acceptedFormats.trim() === '*' ? 'image/*' : pluginOptions.acceptedFormats.trim() || 'image/*',
28
28
  useFormatType: pluginOptions.useFormatType ?? true,
29
- defaultFormatType: ['block', 'inline'].includes(pluginOptions.defaultFormatType) ? pluginOptions.defaultFormatType : 'block'
29
+ defaultFormatType: ['block', 'inline'].includes(pluginOptions.defaultFormatType) ? pluginOptions.defaultFormatType : 'block',
30
+ keepFormatType: pluginOptions.keepFormatType ?? false
30
31
  };
31
32
 
32
33
  // create HTML
@@ -249,7 +250,7 @@ Image_.prototype = {
249
250
  }
250
251
 
251
252
  if (this.pluginOptions.useFormatType) {
252
- this._activeAsInline(this.pluginOptions.defaultFormatType === 'inline');
253
+ this._activeAsInline((this.pluginOptions.keepFormatType ? this.as : this.pluginOptions.defaultFormatType) === 'inline');
253
254
  }
254
255
 
255
256
  this.anchor.init();
@@ -2,13 +2,15 @@ import EditorInjector from '../../editorInjector';
2
2
  import { Modal, Controller } from '../../modules';
3
3
  import { domUtils, env, converter } from '../../helper';
4
4
 
5
+ const { _w } = env;
6
+
5
7
  const Math_ = function (editor, pluginOptions) {
6
8
  // external library
7
9
  this.katex = null;
8
10
  this.mathjax = null;
9
11
 
10
12
  // exception
11
- if (!(this.katex = CheckKatex(editor.options.get('externalLibs').katex)) && !(this.mathjax = CheckMathJax(editor.options.get('externalLibs').mathjax))) {
13
+ if (!(this.katex = CheckKatex(editor.options.get('externalLibs').katex)) && !(this.mathjax = CheckMathJax(editor.options.get('externalLibs').mathjax, editor))) {
12
14
  console.warn('[SUNEDITOR.plugins.math.warn] The math plugin must need either "KaTeX" or "MathJax" library. Please add the katex or mathjax option.');
13
15
  }
14
16
 
@@ -17,8 +19,43 @@ const Math_ = function (editor, pluginOptions) {
17
19
  this.title = this.lang.math;
18
20
  this.icon = 'math';
19
21
 
22
+ this.pluginOptions = {
23
+ formSize: {
24
+ width: '460px',
25
+ height: '14em',
26
+ maxWidth: '',
27
+ maxHeight: '',
28
+ minWidth: '400px',
29
+ minHeight: '40px',
30
+ ...pluginOptions.formSize
31
+ },
32
+ canResize: pluginOptions.canResize ?? true,
33
+ autoHeight: !!pluginOptions.autoHeight,
34
+ fontSizeList: pluginOptions.fontSizeList || [
35
+ {
36
+ text: '1',
37
+ value: '1em'
38
+ },
39
+ {
40
+ text: '1.5',
41
+ value: '1.5em'
42
+ },
43
+ {
44
+ text: '2',
45
+ value: '2em'
46
+ },
47
+ {
48
+ text: '2.5',
49
+ value: '2.5em'
50
+ }
51
+ ]
52
+ };
53
+ if (this.pluginOptions.autoHeight) {
54
+ this.pluginOptions.formSize.height = this.pluginOptions.formSize.minHeight;
55
+ }
56
+
20
57
  // create HTML
21
- const modalEl = CreateHTML_modal(editor, this, pluginOptions.fontSizeList, this.katex);
58
+ const modalEl = CreateHTML_modal(this);
22
59
  const controllerEl = CreateHTML_controller(editor);
23
60
 
24
61
  // modules
@@ -94,7 +131,10 @@ Math_.prototype = {
94
131
  domUtils.removeClass(element, 'katex');
95
132
  }
96
133
 
97
- if (this.mathjax) renderMathJax(this.mathjax);
134
+ if (this.mathjax) {
135
+ renderMathJax(this.mathjax);
136
+ this._applyMathJaxStyleOnIframe();
137
+ }
98
138
  }
99
139
  };
100
140
  },
@@ -169,7 +209,10 @@ Math_.prototype = {
169
209
  return true;
170
210
  }
171
211
 
172
- if (this.mathjax) renderMathJax(this.mathjax);
212
+ if (this.mathjax) {
213
+ renderMathJax(this.mathjax);
214
+ this._applyMathJaxStyleOnIframe();
215
+ }
173
216
 
174
217
  const r = this.selection.getNearRange(mathEl);
175
218
  if (r) {
@@ -254,7 +297,7 @@ async function copyTextToClipboard(element) {
254
297
  await navigator.clipboard.writeText(text);
255
298
  domUtils.addClass(element, 'se-copy');
256
299
  // copy effect
257
- env._w.setTimeout(() => {
300
+ _w.setTimeout(() => {
258
301
  domUtils.removeClass(element, 'se-copy');
259
302
  }, 120);
260
303
  } catch (err) {
@@ -262,8 +305,13 @@ async function copyTextToClipboard(element) {
262
305
  }
263
306
  }
264
307
 
265
- function RenderMathExp(e) {
266
- this.previewElement.innerHTML = this._renderer(e.target.value);
308
+ function RenderMathExp({ target }) {
309
+ if (this.pluginOptions.autoHeight) {
310
+ target.style.height = '5px';
311
+ target.style.height = target.scrollHeight + 5 + 'px';
312
+ }
313
+
314
+ this.previewElement.innerHTML = this._renderer(target.value);
267
315
  if (this.mathjax) renderMathJax(this.mathjax);
268
316
  }
269
317
 
@@ -295,8 +343,11 @@ function CheckKatex(katex) {
295
343
  return katex;
296
344
  }
297
345
 
298
- function CheckMathJax(mathjax) {
346
+ function CheckMathJax(mathjax, editor) {
299
347
  if (!mathjax) return null;
348
+ if (editor.frameOptions.get('iframe')) {
349
+ console.warn('[SUNEDITOR.math.mathjax.fail] The MathJax option is not supported in the iframe.');
350
+ }
300
351
 
301
352
  try {
302
353
  const adaptor = mathjax.browserAdaptor();
@@ -315,26 +366,13 @@ function CheckMathJax(mathjax) {
315
366
  }
316
367
  }
317
368
 
318
- function CreateHTML_modal({ lang, icons }, math, fontSizeList, isKatex) {
319
- const fontSize = fontSizeList || [
320
- {
321
- text: '1',
322
- value: '1em'
323
- },
324
- {
325
- text: '1.5',
326
- value: '1.5em'
327
- },
328
- {
329
- text: '2',
330
- value: '2em'
331
- },
332
- {
333
- text: '2.5',
334
- value: '2.5em'
335
- }
336
- ];
337
- let defaultFontSize = fontSize[0].value;
369
+ function CreateHTML_modal(inst) {
370
+ const { lang, icons, pluginOptions, katex } = inst;
371
+ const { formSize, fontSizeList, canResize, autoHeight } = pluginOptions;
372
+ const { width, height, maxWidth, maxHeight, minWidth, minHeight } = formSize;
373
+ const resizeType = !canResize ? 'none' : autoHeight ? 'horizontal' : 'auto';
374
+
375
+ let defaultFontSize = fontSizeList[0].value;
338
376
  let html = /*html*/ `
339
377
  <form>
340
378
  <div class="se-modal-header">
@@ -345,15 +383,15 @@ function CreateHTML_modal({ lang, icons }, math, fontSizeList, isKatex) {
345
383
  </div>
346
384
  <div class="se-modal-body">
347
385
  <div class="se-modal-form">
348
- <label>${lang.math_modal_inputLabel} ${isKatex ? `(<a href="${env.KATEX_WEBSITE}" target="_blank">KaTeX</a>)` : `(<a href="${env.MATHJAX_WEBSITE}" target="_blank">MathJax</a>)`}</label>
349
- <textarea class="se-input-form se-math-exp" type="text" data-focus></textarea>
386
+ <label>${lang.math_modal_inputLabel} ${katex ? `(<a href="${env.KATEX_WEBSITE}" target="_blank">KaTeX</a>)` : `(<a href="${env.MATHJAX_WEBSITE}" target="_blank">MathJax</a>)`}</label>
387
+ <textarea class="se-input-form se-math-exp se-modal-resize-form" type="text" data-focus style="width: ${width}; height: ${height}; min-width: ${minWidth}; min-height: ${minHeight}; resize: ${resizeType};"></textarea>
350
388
  </div>
351
389
  <div class="se-modal-form">
352
390
  <label>${lang.math_modal_fontSizeLabel}</label>
353
391
  <select class="se-input-select se-math-size">`;
354
392
 
355
- for (let i = 0, len = fontSize.length, f; i < len; i++) {
356
- f = fontSize[i];
393
+ for (let i = 0, len = fontSizeList.length, f; i < len; i++) {
394
+ f = fontSizeList[i];
357
395
  if (f.default) defaultFontSize = f.value;
358
396
  html += /*html*/ `<option value="${f.value}"${f.default ? ' selected' : ''}>${f.text}</option>`;
359
397
  }
@@ -372,8 +410,8 @@ function CreateHTML_modal({ lang, icons }, math, fontSizeList, isKatex) {
372
410
  </div>
373
411
  </form>`;
374
412
 
375
- math.defaultFontSize = defaultFontSize;
376
- return domUtils.createElement('DIV', { class: 'se-modal-content' }, html);
413
+ inst.defaultFontSize = defaultFontSize;
414
+ return domUtils.createElement('DIV', { class: 'se-modal-content se-modal-responsive', style: `max-width: ${maxWidth}; max-height: ${maxHeight};` }, html);
377
415
  }
378
416
 
379
417
  function CreateHTML_controller({ lang, icons }) {