suneditor 3.0.0-rc.5 → 3.0.0
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 +3 -2
- package/dist/suneditor-contents.min.css +1 -1
- package/dist/suneditor.min.css +1 -1
- package/dist/suneditor.min.js +1 -1
- package/package.json +2 -3
- package/src/assets/design/color.css +14 -2
- package/src/assets/design/typography.css +5 -0
- package/src/assets/icons/defaultIcons.js +22 -4
- package/src/assets/suneditor-contents.css +1 -1
- package/src/assets/suneditor.css +312 -18
- package/src/core/config/eventManager.js +6 -9
- package/src/core/editor.js +1 -1
- package/src/core/event/actions/index.js +5 -0
- package/src/core/event/effects/keydown.registry.js +25 -0
- package/src/core/event/eventOrchestrator.js +69 -2
- package/src/core/event/handlers/handler_ww_mouse.js +1 -0
- package/src/core/event/rules/keydown.rule.backspace.js +9 -1
- package/src/core/kernel/coreKernel.js +4 -0
- package/src/core/kernel/store.js +2 -0
- package/src/core/logic/dom/html.js +110 -11
- package/src/core/logic/dom/offset.js +89 -35
- package/src/core/logic/dom/selection.js +46 -19
- package/src/core/logic/panel/finder.js +982 -0
- package/src/core/logic/panel/menu.js +8 -6
- package/src/core/logic/panel/toolbar.js +112 -19
- package/src/core/logic/panel/viewer.js +214 -43
- package/src/core/logic/shell/_commandExecutor.js +7 -1
- package/src/core/logic/shell/commandDispatcher.js +1 -1
- package/src/core/logic/shell/component.js +5 -7
- package/src/core/logic/shell/history.js +24 -0
- package/src/core/logic/shell/shortcuts.js +3 -3
- package/src/core/logic/shell/ui.js +25 -26
- package/src/core/schema/frameContext.js +15 -1
- package/src/core/schema/options.js +75 -16
- package/src/core/section/constructor.js +61 -20
- package/src/core/section/documentType.js +1 -1
- package/src/events.js +12 -0
- package/src/helper/clipboard.js +1 -1
- package/src/helper/dom/domUtils.js +5 -14
- package/src/helper/index.js +3 -0
- package/src/helper/markdown.js +876 -0
- package/src/langs/ckb.js +9 -0
- package/src/langs/cs.js +9 -0
- package/src/langs/da.js +9 -0
- package/src/langs/de.js +9 -0
- package/src/langs/en.js +9 -0
- package/src/langs/es.js +9 -0
- package/src/langs/fa.js +9 -0
- package/src/langs/fr.js +9 -0
- package/src/langs/he.js +9 -0
- package/src/langs/hu.js +9 -0
- package/src/langs/it.js +9 -0
- package/src/langs/ja.js +9 -0
- package/src/langs/km.js +9 -0
- package/src/langs/ko.js +9 -0
- package/src/langs/lv.js +9 -0
- package/src/langs/nl.js +9 -0
- package/src/langs/pl.js +9 -0
- package/src/langs/pt_br.js +9 -0
- package/src/langs/ro.js +9 -0
- package/src/langs/ru.js +9 -0
- package/src/langs/se.js +9 -0
- package/src/langs/tr.js +9 -0
- package/src/langs/uk.js +9 -0
- package/src/langs/ur.js +9 -0
- package/src/langs/zh_cn.js +9 -0
- package/src/modules/contract/Controller.js +50 -39
- package/src/modules/manager/ApiManager.js +27 -4
- package/src/modules/manager/FileManager.js +1 -1
- package/src/modules/ui/SelectMenu.js +22 -11
- package/src/plugins/command/codeBlock.js +324 -0
- package/src/plugins/command/exportPDF.js +15 -3
- package/src/plugins/dropdown/blockStyle.js +1 -1
- package/src/plugins/dropdown/paragraphStyle.js +1 -2
- package/src/plugins/dropdown/table/render/table.html.js +1 -1
- package/src/plugins/dropdown/table/services/table.grid.js +16 -8
- package/src/plugins/dropdown/table/services/table.style.js +5 -9
- package/src/plugins/index.js +3 -0
- package/src/plugins/input/fontSize.js +4 -2
- package/src/plugins/modal/audio.js +2 -1
- package/src/plugins/modal/image/index.js +2 -1
- package/src/plugins/modal/math.js +2 -1
- package/src/plugins/modal/video/index.js +2 -1
- package/src/themes/cobalt.css +13 -4
- package/src/themes/cream.css +11 -2
- package/src/themes/dark.css +13 -4
- package/src/themes/midnight.css +13 -4
- package/src/typedef.js +4 -4
- package/types/assets/icons/defaultIcons.d.ts +12 -1
- package/types/core/config/eventManager.d.ts +6 -8
- package/types/core/event/actions/index.d.ts +1 -0
- package/types/core/event/effects/keydown.registry.d.ts +2 -0
- package/types/core/event/eventOrchestrator.d.ts +2 -1
- package/types/core/kernel/coreKernel.d.ts +5 -0
- package/types/core/kernel/store.d.ts +5 -0
- package/types/core/logic/dom/offset.d.ts +16 -3
- package/types/core/logic/dom/selection.d.ts +3 -3
- package/types/core/logic/panel/finder.d.ts +83 -0
- package/types/core/logic/panel/toolbar.d.ts +14 -1
- package/types/core/logic/panel/viewer.d.ts +22 -2
- package/types/core/logic/shell/shortcuts.d.ts +1 -1
- package/types/core/schema/frameContext.d.ts +22 -0
- package/types/core/schema/options.d.ts +153 -31
- package/types/events.d.ts +11 -0
- package/types/helper/dom/domUtils.d.ts +2 -2
- package/types/helper/index.d.ts +5 -0
- package/types/helper/markdown.d.ts +27 -0
- package/types/langs/_Lang.d.ts +9 -0
- package/types/modules/contract/Controller.d.ts +8 -1
- package/types/modules/ui/SelectMenu.d.ts +12 -0
- package/types/plugins/command/codeBlock.d.ts +53 -0
- package/types/plugins/index.d.ts +3 -0
- package/types/plugins/input/fontSize.d.ts +6 -2
- package/types/plugins/modal/audio.d.ts +4 -2
- package/types/plugins/modal/image/index.d.ts +3 -1
- package/types/plugins/modal/math.d.ts +3 -1
- package/types/plugins/modal/video/index.d.ts +3 -1
- package/types/typedef.d.ts +5 -2
|
@@ -18,6 +18,8 @@ class Menu {
|
|
|
18
18
|
#bindClose_dropdown_mouse = null;
|
|
19
19
|
#bindClose_dropdown_key = null;
|
|
20
20
|
#bindClose_cons_mouse = null;
|
|
21
|
+
#bindMenu_mousemove = null;
|
|
22
|
+
#bindMenu_mouseout = null;
|
|
21
23
|
#menuBtn = null;
|
|
22
24
|
#menuContainer = null;
|
|
23
25
|
|
|
@@ -114,8 +116,8 @@ class Menu {
|
|
|
114
116
|
this.menus = converter.nodeListToArray(menu.querySelectorAll('[data-command]'));
|
|
115
117
|
if (this.menus.length > 0) {
|
|
116
118
|
this.#bindClose_dropdown_key = this.#eventManager.addGlobalEvent('keydown', this.#globalEventHandler.keydown, false);
|
|
117
|
-
|
|
118
|
-
|
|
119
|
+
this.#bindMenu_mousemove = this.#eventManager.addEvent(menu, 'mousemove', this.#globalEventHandler.mousemove, false);
|
|
120
|
+
this.#bindMenu_mouseout = this.#eventManager.addEvent(menu, 'mouseout', this.#globalEventHandler.mouseout, false);
|
|
119
121
|
}
|
|
120
122
|
}
|
|
121
123
|
|
|
@@ -220,7 +222,7 @@ class Menu {
|
|
|
220
222
|
* @param {HTMLElement} menu Menu element
|
|
221
223
|
*/
|
|
222
224
|
__resetMenuPosition(element, menu) {
|
|
223
|
-
this.#$.offset.setRelPosition(menu, this.#contextProvider.carrierWrapper, element.parentElement, dom.query.getParentElement(element, '.se-toolbar'));
|
|
225
|
+
this.#$.offset.setRelPosition(menu, this.#contextProvider.carrierWrapper, element.parentElement, dom.query.getParentElement(element, '.se-toolbar'), { preferUp: this.#store.mode.isBottom });
|
|
224
226
|
}
|
|
225
227
|
|
|
226
228
|
/**
|
|
@@ -243,7 +245,7 @@ class Menu {
|
|
|
243
245
|
menu.style.height = '';
|
|
244
246
|
dom.utils.addClass(element.parentElement.children, 'on');
|
|
245
247
|
|
|
246
|
-
this.#$.offset.setRelPosition(menu, this.#contextProvider.carrierWrapper, element.parentElement, dom.query.getParentElement(element, '.se-toolbar'));
|
|
248
|
+
this.#$.offset.setRelPosition(menu, this.#contextProvider.carrierWrapper, element.parentElement, dom.query.getParentElement(element, '.se-toolbar'), { preferUp: this.#store.mode.isBottom });
|
|
247
249
|
|
|
248
250
|
menu.style.visibility = '';
|
|
249
251
|
|
|
@@ -293,10 +295,10 @@ class Menu {
|
|
|
293
295
|
this.#bindClose_cons_mouse &&= this.#eventManager.removeGlobalEvent(this.#bindClose_cons_mouse);
|
|
294
296
|
if (this.#bindClose_dropdown_key) {
|
|
295
297
|
this.#bindClose_dropdown_key = this.#eventManager.removeGlobalEvent(this.#bindClose_dropdown_key);
|
|
298
|
+
this.#bindMenu_mousemove &&= this.#eventManager.removeEvent(this.#bindMenu_mousemove);
|
|
299
|
+
this.#bindMenu_mouseout &&= this.#eventManager.removeEvent(this.#bindMenu_mouseout);
|
|
296
300
|
dom.utils.removeClass(this.menus, 'on');
|
|
297
301
|
dom.utils.removeClass(this.currentDropdown, 'se-select-menu-key-action|se-select-menu-mouse-move');
|
|
298
|
-
this.currentDropdown.removeEventListener('mousemove', this.#globalEventHandler.mousemove, false);
|
|
299
|
-
this.currentDropdown.removeEventListener('mouseout', this.#globalEventHandler.mouseout, false);
|
|
300
302
|
}
|
|
301
303
|
}
|
|
302
304
|
|
|
@@ -26,6 +26,9 @@ class Toolbar {
|
|
|
26
26
|
#rButtonsInfo = null;
|
|
27
27
|
#rButtonsize = null;
|
|
28
28
|
|
|
29
|
+
#useCSSSticky = false;
|
|
30
|
+
#_isStickyFlag = false;
|
|
31
|
+
|
|
29
32
|
/**
|
|
30
33
|
* @constructor
|
|
31
34
|
* @param {SunEditor.Kernel} kernel
|
|
@@ -65,7 +68,6 @@ class Toolbar {
|
|
|
65
68
|
};
|
|
66
69
|
|
|
67
70
|
this.currentMoreLayerActiveButton = null;
|
|
68
|
-
this.isSticky = false;
|
|
69
71
|
this.isBalloonMode = balloon;
|
|
70
72
|
this.isInlineMode = inline;
|
|
71
73
|
this.isBalloonAlwaysMode = balloonAlways;
|
|
@@ -84,9 +86,63 @@ class Toolbar {
|
|
|
84
86
|
this.#rButtonArray = res;
|
|
85
87
|
this.#isViewPortSize = 'visualViewport' in _w;
|
|
86
88
|
|
|
89
|
+
// CSS sticky: non-balloon, non-inline, non-container, sticky enabled
|
|
90
|
+
const isStickyPosible = !this.isSub && !balloon && !inline;
|
|
91
|
+
const stickyTop = this.#options.get('toolbar_sticky');
|
|
92
|
+
|
|
93
|
+
this.#useCSSSticky = isStickyPosible && stickyTop >= 0 && !this.#options.get('toolbar_container') && typeof CSS !== 'undefined' && CSS.supports('position', 'sticky');
|
|
94
|
+
|
|
95
|
+
this.isBottomMode = this.#store.mode.isBottom;
|
|
96
|
+
|
|
97
|
+
if (this.#useCSSSticky) {
|
|
98
|
+
// CSS sticky: browser handles positioning natively
|
|
99
|
+
const toolbar = this.#context.get(this.keyName.main);
|
|
100
|
+
if (this.isBottomMode) {
|
|
101
|
+
toolbar.style.bottom = stickyTop + 'px';
|
|
102
|
+
toolbar.style.top = 'auto';
|
|
103
|
+
} else if (stickyTop > 0) {
|
|
104
|
+
toolbar.style.top = stickyTop + 'px';
|
|
105
|
+
}
|
|
106
|
+
} else if (isStickyPosible) {
|
|
107
|
+
// JS fallback (toolbar_container) or sticky disabled (-1):
|
|
108
|
+
dom.utils.addClass(this.#context.get(this.keyName.main), 'se-toolbar-relative');
|
|
109
|
+
}
|
|
110
|
+
|
|
87
111
|
this._setResponsive();
|
|
88
112
|
}
|
|
89
113
|
|
|
114
|
+
/**
|
|
115
|
+
* @description Whether the toolbar is currently in a sticky (fixed) state.
|
|
116
|
+
* For CSS sticky mode, computed from the element's viewport position.
|
|
117
|
+
* For JS sticky mode (toolbar_container), uses a manual flag.
|
|
118
|
+
* @type {boolean}
|
|
119
|
+
*/
|
|
120
|
+
get isSticky() {
|
|
121
|
+
if (this.isSub) return false;
|
|
122
|
+
const stickyTop = this.#options.get('toolbar_sticky');
|
|
123
|
+
if (stickyTop < 0) return false;
|
|
124
|
+
|
|
125
|
+
if (this.#useCSSSticky) {
|
|
126
|
+
const toolbar = this.#context.get(this.keyName.main);
|
|
127
|
+
if (!toolbar || toolbar.offsetWidth === 0 || toolbar.style.display === 'none') return false;
|
|
128
|
+
if (this.isBottomMode) {
|
|
129
|
+
return toolbar.getBoundingClientRect().bottom >= _w.innerHeight - stickyTop - 1;
|
|
130
|
+
}
|
|
131
|
+
return toolbar.getBoundingClientRect().top <= stickyTop + 1;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return this.#_isStickyFlag;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* @description Whether the toolbar uses native CSS `position: sticky`.
|
|
139
|
+
* - When `false`, the JS-based sticky fallback (`position: fixed`) is active.
|
|
140
|
+
* @type {boolean}
|
|
141
|
+
*/
|
|
142
|
+
get isCSSSticky() {
|
|
143
|
+
return this.#useCSSSticky;
|
|
144
|
+
}
|
|
145
|
+
|
|
90
146
|
/**
|
|
91
147
|
* @description Disables all toolbar buttons.
|
|
92
148
|
*/
|
|
@@ -198,6 +254,8 @@ class Toolbar {
|
|
|
198
254
|
* @description Reset the sticky toolbar position based on the editor state.
|
|
199
255
|
*/
|
|
200
256
|
_resetSticky() {
|
|
257
|
+
if (this.#useCSSSticky) return;
|
|
258
|
+
|
|
201
259
|
const wrapper = this.#frameContext.get('wrapper');
|
|
202
260
|
if (!wrapper) return;
|
|
203
261
|
|
|
@@ -210,18 +268,36 @@ class Toolbar {
|
|
|
210
268
|
const minHeight = this.#frameContext.get('_minHeight');
|
|
211
269
|
const editorHeight = wrapper.offsetHeight;
|
|
212
270
|
const editorOffset = this.#$.offset.getGlobal(this.#frameContext.get('topArea'));
|
|
213
|
-
const y = currentScrollY + stickyTop;
|
|
214
|
-
const t = (this.isBalloonMode || this.isInlineMode ? editorOffset.top : this.#$.offset.getGlobal(this.#options.get('toolbar_container')).top) - (this.isInlineMode ? toolbar.offsetHeight : 0);
|
|
215
271
|
const inlineOffset = 1;
|
|
216
272
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
273
|
+
if (this.isBottomMode) {
|
|
274
|
+
const viewportBottom = currentScrollY + _w.innerHeight;
|
|
275
|
+
const editorBottom = editorOffset.top + editorHeight;
|
|
276
|
+
const y = viewportBottom - stickyTop - (this.isInlineMode ? toolbar.offsetHeight : 0);
|
|
277
|
+
|
|
278
|
+
const offSticky = !this.#options.get('toolbar_container') ? y - editorOffset.top - minHeight : viewportBottom - stickyTop - editorOffset.top - minHeight - toolbar.offsetHeight;
|
|
279
|
+
if (y > editorBottom) {
|
|
280
|
+
this.#offSticky();
|
|
281
|
+
} else if (offSticky < 0) {
|
|
282
|
+
if (!this.isSticky) this.#onSticky(inlineOffset);
|
|
283
|
+
toolbar.style.bottom = inlineOffset + offSticky + this.#getViewportTop() + 'px';
|
|
284
|
+
toolbar.style.top = 'auto';
|
|
285
|
+
} else {
|
|
286
|
+
this.#onSticky(inlineOffset);
|
|
287
|
+
}
|
|
223
288
|
} else {
|
|
224
|
-
|
|
289
|
+
const y = currentScrollY + stickyTop;
|
|
290
|
+
const t = (this.isBalloonMode || this.isInlineMode ? editorOffset.top : this.#$.offset.getGlobal(this.#options.get('toolbar_container')).top) - (this.isInlineMode ? toolbar.offsetHeight : 0);
|
|
291
|
+
|
|
292
|
+
const offSticky = !this.#options.get('toolbar_container') ? editorHeight + t + stickyTop - y - minHeight : editorOffset.top - currentScrollY + editorHeight - minHeight - stickyTop - toolbar.offsetHeight;
|
|
293
|
+
if (y < t) {
|
|
294
|
+
this.#offSticky();
|
|
295
|
+
} else if (offSticky < 0) {
|
|
296
|
+
if (!this.isSticky) this.#onSticky(inlineOffset);
|
|
297
|
+
toolbar.style.top = inlineOffset + offSticky + this.#getViewportTop() + 'px';
|
|
298
|
+
} else {
|
|
299
|
+
this.#onSticky(inlineOffset);
|
|
300
|
+
}
|
|
225
301
|
}
|
|
226
302
|
}
|
|
227
303
|
|
|
@@ -229,7 +305,7 @@ class Toolbar {
|
|
|
229
305
|
* @description Reset the common buttons info.
|
|
230
306
|
*/
|
|
231
307
|
#resetButtonInfo() {
|
|
232
|
-
this.#$.shortcuts.
|
|
308
|
+
this.#$.shortcuts._registerShortcuts();
|
|
233
309
|
this.#$.commandDispatcher.resetTargets();
|
|
234
310
|
this.#$.ui._initToggleButtons();
|
|
235
311
|
|
|
@@ -350,12 +426,17 @@ class Toolbar {
|
|
|
350
426
|
|
|
351
427
|
const toolbar = this.#context.get(this.keyName.main);
|
|
352
428
|
toolbar.style.visibility = 'hidden';
|
|
429
|
+
toolbar.style.display = 'block';
|
|
353
430
|
this.#offSticky();
|
|
354
431
|
|
|
355
|
-
toolbar.style.display = 'block';
|
|
356
432
|
toolbar.style.top = '0px';
|
|
357
433
|
this.inlineToolbarAttr.width = toolbar.style.width = this.#options.get(this.keyName.width);
|
|
358
|
-
|
|
434
|
+
if (this.isBottomMode) {
|
|
435
|
+
const topArea = this.#frameContext.get('topArea');
|
|
436
|
+
this.inlineToolbarAttr.top = toolbar.style.top = this.#$.offset.getGlobal(topArea).top + topArea.offsetHeight - this.#$.offset.getGlobal(toolbar).top + 'px';
|
|
437
|
+
} else {
|
|
438
|
+
this.inlineToolbarAttr.top = toolbar.style.top = -1 + (this.#$.offset.getGlobal(this.#frameContext.get('topArea')).top - this.#$.offset.getGlobal(toolbar).top - toolbar.offsetHeight) + 'px';
|
|
439
|
+
}
|
|
359
440
|
|
|
360
441
|
this._resetSticky();
|
|
361
442
|
this.inlineToolbarAttr.isShow = true;
|
|
@@ -403,11 +484,17 @@ class Toolbar {
|
|
|
403
484
|
stickyDummy.style.display = 'block';
|
|
404
485
|
}
|
|
405
486
|
|
|
406
|
-
|
|
407
|
-
|
|
487
|
+
if (this.isBottomMode) {
|
|
488
|
+
const toolbarBottomPosition = this.#options.get('toolbar_sticky') + this.#getViewportTop();
|
|
489
|
+
toolbar.style.bottom = `${toolbarBottomPosition}px`;
|
|
490
|
+
toolbar.style.top = 'auto';
|
|
491
|
+
} else {
|
|
492
|
+
const toolbarTopPosition = this.#options.get('toolbar_sticky') + inlineOffset + this.#getViewportTop();
|
|
493
|
+
toolbar.style.top = `${toolbarTopPosition}px`;
|
|
494
|
+
}
|
|
408
495
|
toolbar.style.width = this.isInlineMode ? this.inlineToolbarAttr.width : toolbar.offsetWidth + 'px';
|
|
409
496
|
dom.utils.addClass(toolbar, 'se-toolbar-sticky');
|
|
410
|
-
this
|
|
497
|
+
this.#_isStickyFlag = true;
|
|
411
498
|
}
|
|
412
499
|
|
|
413
500
|
/**
|
|
@@ -429,12 +516,18 @@ class Toolbar {
|
|
|
429
516
|
stickyDummy.style.display = 'none';
|
|
430
517
|
|
|
431
518
|
const toolbar = this.#context.get(this.keyName.main);
|
|
432
|
-
|
|
519
|
+
if (this.isBottomMode) {
|
|
520
|
+
toolbar.style.bottom = this.isInlineMode ? `${-toolbar.offsetHeight}px` : '';
|
|
521
|
+
toolbar.style.top = 'auto';
|
|
522
|
+
this.#frameContext.get('wrapper').style.marginBottom = '';
|
|
523
|
+
} else {
|
|
524
|
+
toolbar.style.top = this.isInlineMode ? this.inlineToolbarAttr.top : '';
|
|
525
|
+
this.#frameContext.get('wrapper').style.marginTop = '';
|
|
526
|
+
}
|
|
433
527
|
toolbar.style.width = this.isInlineMode ? this.inlineToolbarAttr.width : '';
|
|
434
|
-
this.#frameContext.get('wrapper').style.marginTop = '';
|
|
435
528
|
|
|
436
529
|
dom.utils.removeClass(toolbar, 'se-toolbar-sticky');
|
|
437
|
-
this
|
|
530
|
+
this.#_isStickyFlag = false;
|
|
438
531
|
}
|
|
439
532
|
|
|
440
533
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { dom, env, converter,
|
|
1
|
+
import { dom, env, converter, markdown } from '../../../helper';
|
|
2
2
|
|
|
3
3
|
const { _w, _d } = env;
|
|
4
4
|
|
|
@@ -27,6 +27,9 @@ class Viewer {
|
|
|
27
27
|
#codeWrapperOriginCssText = '';
|
|
28
28
|
#codeOriginCssText = '';
|
|
29
29
|
#codeNumberOriginCssText = '';
|
|
30
|
+
#markdownWrapperOriginCssText = '';
|
|
31
|
+
#markdownOriginCssText = '';
|
|
32
|
+
#markdownNumberOriginCssText = '';
|
|
30
33
|
#toolbarOriginCssText = '';
|
|
31
34
|
#arrowOriginCssText = '';
|
|
32
35
|
#fullScreenInnerHeight = 0;
|
|
@@ -64,9 +67,15 @@ class Viewer {
|
|
|
64
67
|
*/
|
|
65
68
|
codeView(value) {
|
|
66
69
|
const fc = this.#frameContext;
|
|
70
|
+
if (!fc.get('codeWrapper')) return;
|
|
67
71
|
if (value === undefined) value = !fc.get('isCodeView');
|
|
68
72
|
if (value === fc.get('isCodeView')) return;
|
|
69
73
|
|
|
74
|
+
// Mutual exclusivity with markdown view
|
|
75
|
+
if (value && fc.get('isMarkdownView')) {
|
|
76
|
+
this.markdownView(false);
|
|
77
|
+
}
|
|
78
|
+
|
|
70
79
|
fc.set('isCodeView', value);
|
|
71
80
|
this.#$.ui.offCurrentController();
|
|
72
81
|
this.#$.ui.offCurrentModal();
|
|
@@ -77,6 +86,7 @@ class Viewer {
|
|
|
77
86
|
const wrapper = fc.get('wrapper');
|
|
78
87
|
|
|
79
88
|
if (value) {
|
|
89
|
+
this.#$.finder.close();
|
|
80
90
|
this.#setEditorDataToCodeView();
|
|
81
91
|
codeWrapper.style.setProperty('display', 'flex', 'important');
|
|
82
92
|
wysiwygFrame.style.display = 'none';
|
|
@@ -111,7 +121,7 @@ class Viewer {
|
|
|
111
121
|
this.#store.set('_range', null);
|
|
112
122
|
codeFrame.focus();
|
|
113
123
|
dom.utils.addClass(this.#$.commandDispatcher.targets.get('codeView'), 'active');
|
|
114
|
-
dom.utils.addClass(wrapper, 'se-
|
|
124
|
+
dom.utils.addClass(wrapper, 'se-source-view-status');
|
|
115
125
|
} else {
|
|
116
126
|
if (!dom.check.isNonEditable(wysiwygFrame)) this.#setCodeDataToEditor();
|
|
117
127
|
wysiwygFrame.scrollTop = 0;
|
|
@@ -137,7 +147,7 @@ class Viewer {
|
|
|
137
147
|
this.#$.history.push(false);
|
|
138
148
|
this.#$.history.resetButtons(fc.get('key'), null);
|
|
139
149
|
}
|
|
140
|
-
dom.utils.removeClass(wrapper, 'se-
|
|
150
|
+
dom.utils.removeClass(wrapper, 'se-source-view-status');
|
|
141
151
|
}
|
|
142
152
|
|
|
143
153
|
this.#$.ui._updatePlaceholder(fc);
|
|
@@ -157,6 +167,108 @@ class Viewer {
|
|
|
157
167
|
this.#eventManager.triggerEvent('onToggleCodeView', { frameContext: fc, is: fc.get('isCodeView') });
|
|
158
168
|
}
|
|
159
169
|
|
|
170
|
+
/**
|
|
171
|
+
* @description Changes to markdown view or wysiwyg view
|
|
172
|
+
* @param {boolean} [value] `true`/`false`, If `undefined` toggle the `markdownView` mode.
|
|
173
|
+
*/
|
|
174
|
+
markdownView(value) {
|
|
175
|
+
const fc = this.#frameContext;
|
|
176
|
+
if (!fc.get('markdownWrapper')) return;
|
|
177
|
+
if (value === undefined) value = !fc.get('isMarkdownView');
|
|
178
|
+
if (value === fc.get('isMarkdownView')) return;
|
|
179
|
+
|
|
180
|
+
// Mutual exclusivity with code view
|
|
181
|
+
if (value && fc.get('isCodeView')) {
|
|
182
|
+
this.codeView(false);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
fc.set('isMarkdownView', value);
|
|
186
|
+
this.#$.ui.offCurrentController();
|
|
187
|
+
this.#$.ui.offCurrentModal();
|
|
188
|
+
|
|
189
|
+
const markdownWrapper = fc.get('markdownWrapper');
|
|
190
|
+
const markdownFrame = fc.get('markdown');
|
|
191
|
+
const wysiwygFrame = fc.get('wysiwygFrame');
|
|
192
|
+
const wrapper = fc.get('wrapper');
|
|
193
|
+
|
|
194
|
+
if (value) {
|
|
195
|
+
this.#$.finder.close();
|
|
196
|
+
this.#setEditorDataToMarkdownView();
|
|
197
|
+
markdownWrapper.style.setProperty('display', 'flex', 'important');
|
|
198
|
+
wysiwygFrame.style.display = 'none';
|
|
199
|
+
|
|
200
|
+
if (fc.get('isFullScreen')) {
|
|
201
|
+
markdownFrame.style.height = '100%';
|
|
202
|
+
} else if (this.#frameOptions.get('height') === 'auto') {
|
|
203
|
+
markdownFrame.style.height = markdownFrame.scrollHeight > 0 ? markdownFrame.scrollHeight + 'px' : 'auto';
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (!fc.get('isFullScreen')) {
|
|
207
|
+
this.#$.ui.preventToolbarHide(true);
|
|
208
|
+
if (this.#store.mode.isBalloon) {
|
|
209
|
+
this.#context.get('toolbar_arrow').style.display = 'none';
|
|
210
|
+
this.#context.get('toolbar_main').style.left = '';
|
|
211
|
+
this.#store.mode.isInline = this.#$.toolbar.isInlineMode = true;
|
|
212
|
+
this.#store.mode.isBalloon = this.#$.toolbar.isBalloonMode = false;
|
|
213
|
+
this.#$.toolbar._showInline();
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (this.#store.mode.isBalloon) {
|
|
218
|
+
this.#$.subToolbar.hide();
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
CreateLineNumbers(fc, 'markdown');
|
|
222
|
+
|
|
223
|
+
this.#store.set('_range', null);
|
|
224
|
+
markdownFrame.focus();
|
|
225
|
+
dom.utils.addClass(this.#$.commandDispatcher.targets.get('markdownView'), 'active');
|
|
226
|
+
dom.utils.addClass(wrapper, 'se-source-view-status');
|
|
227
|
+
} else {
|
|
228
|
+
if (!dom.check.isNonEditable(wysiwygFrame)) this.#setMarkdownDataToEditor();
|
|
229
|
+
wysiwygFrame.scrollTop = 0;
|
|
230
|
+
markdownWrapper.style.setProperty('display', 'none', 'important');
|
|
231
|
+
wysiwygFrame.style.display = 'block';
|
|
232
|
+
|
|
233
|
+
if (this.#frameOptions.get('height') === 'auto') markdownFrame.style.height = '0px';
|
|
234
|
+
|
|
235
|
+
if (!fc.get('isFullScreen')) {
|
|
236
|
+
this.#$.ui.preventToolbarHide(false);
|
|
237
|
+
if (/balloon/.test(this.#options.get('mode'))) {
|
|
238
|
+
this.#context.get('toolbar_arrow').style.display = '';
|
|
239
|
+
this.#store.mode.isInline = this.#$.toolbar.isInlineMode = false;
|
|
240
|
+
this.#store.mode.isBalloon = this.#$.toolbar.isBalloonMode = true;
|
|
241
|
+
this.#kernel._eventOrchestrator._hideToolbar();
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
this.#$.focusManager.nativeFocus();
|
|
246
|
+
dom.utils.removeClass(this.#$.commandDispatcher.targets.get('markdownView'), 'active');
|
|
247
|
+
|
|
248
|
+
if (!dom.check.isNonEditable(wysiwygFrame)) {
|
|
249
|
+
this.#$.history.push(false);
|
|
250
|
+
this.#$.history.resetButtons(fc.get('key'), null);
|
|
251
|
+
}
|
|
252
|
+
dom.utils.removeClass(wrapper, 'se-source-view-status');
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
this.#$.ui._updatePlaceholder(fc);
|
|
256
|
+
this.#$.ui._toggleCodeViewButtons(value);
|
|
257
|
+
|
|
258
|
+
// document type
|
|
259
|
+
if (fc.has('documentType_use_header')) {
|
|
260
|
+
if (value) {
|
|
261
|
+
fc.get('documentTypeInner').style.display = 'none';
|
|
262
|
+
} else {
|
|
263
|
+
fc.get('documentTypeInner').style.display = '';
|
|
264
|
+
fc.get('documentType').reHeader();
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// user event
|
|
269
|
+
this.#eventManager.triggerEvent('onToggleMarkdownView', { frameContext: fc, is: fc.get('isMarkdownView') });
|
|
270
|
+
}
|
|
271
|
+
|
|
160
272
|
/**
|
|
161
273
|
* @description Changes to full screen or default screen
|
|
162
274
|
* @param {boolean} [value] `true`/`false`, If `undefined` toggle the `fullScreen` mode.
|
|
@@ -174,7 +286,11 @@ class Viewer {
|
|
|
174
286
|
const codeWrapper = fc.get('codeWrapper');
|
|
175
287
|
const code = fc.get('code');
|
|
176
288
|
const codeNumbers = fc.get('codeNumbers');
|
|
289
|
+
const markdownWrapper = fc.get('markdownWrapper');
|
|
290
|
+
const markdownFrame = fc.get('markdown');
|
|
291
|
+
const markdownNumbers = fc.get('markdownNumbers');
|
|
177
292
|
const isCodeView = this.#frameContext.get('isCodeView');
|
|
293
|
+
const isMarkdownView = this.#frameContext.get('isMarkdownView');
|
|
178
294
|
const arrow = this.#context.get('toolbar_arrow');
|
|
179
295
|
|
|
180
296
|
this.#$.ui.offCurrentController();
|
|
@@ -187,6 +303,9 @@ class Viewer {
|
|
|
187
303
|
this.#codeWrapperOriginCssText = codeWrapper.style.cssText;
|
|
188
304
|
this.#codeOriginCssText = code.style.cssText;
|
|
189
305
|
this.#codeNumberOriginCssText = codeNumbers?.style.cssText;
|
|
306
|
+
this.#markdownWrapperOriginCssText = markdownWrapper?.style.cssText;
|
|
307
|
+
this.#markdownOriginCssText = markdownFrame?.style.cssText;
|
|
308
|
+
this.#markdownNumberOriginCssText = markdownNumbers?.style.cssText;
|
|
190
309
|
this.#toolbarOriginCssText = toolbar.style.cssText;
|
|
191
310
|
if (arrow) this.#arrowOriginCssText = arrow.style.cssText;
|
|
192
311
|
|
|
@@ -222,15 +341,23 @@ class Viewer {
|
|
|
222
341
|
|
|
223
342
|
// frame
|
|
224
343
|
editorArea.style.cssText = toolbar.style.cssText = '';
|
|
225
|
-
wysiwygFrame.style.cssText = (wysiwygFrame.style.cssText.match(/\s?display(\s+)?:(\s+)?[a-zA-Z]+;/) || [''])[0] + this.#frameOptions.get('_defaultStyles').editor + (isCodeView ? 'display: none;' : '');
|
|
344
|
+
wysiwygFrame.style.cssText = (wysiwygFrame.style.cssText.match(/\s?display(\s+)?:(\s+)?[a-zA-Z]+;/) || [''])[0] + this.#frameOptions.get('_defaultStyles').editor + (isCodeView || isMarkdownView ? 'display: none;' : '');
|
|
226
345
|
|
|
227
346
|
// code wrapper
|
|
228
347
|
codeWrapper.style.cssText = (codeWrapper.style.cssText.match(/\s?display(\s+)?:(\s+)?[a-zA-Z]+;/) || [''])[0] + `display: ${!isCodeView ? 'none' : 'flex'} !important;`;
|
|
229
348
|
codeWrapper.style.overflow = 'auto';
|
|
230
349
|
codeWrapper.style.height = '100%';
|
|
231
350
|
|
|
351
|
+
// markdown wrapper
|
|
352
|
+
if (markdownWrapper) {
|
|
353
|
+
markdownWrapper.style.cssText = (markdownWrapper.style.cssText.match(/\s?display(\s+)?:(\s+)?[a-zA-Z]+;/) || [''])[0] + `display: ${!isMarkdownView ? 'none' : 'flex'} !important;`;
|
|
354
|
+
markdownWrapper.style.overflow = 'auto';
|
|
355
|
+
markdownWrapper.style.height = '100%';
|
|
356
|
+
}
|
|
357
|
+
|
|
232
358
|
// code
|
|
233
359
|
code.style.height = '';
|
|
360
|
+
if (markdownFrame) markdownFrame.style.height = '';
|
|
234
361
|
|
|
235
362
|
// toolbar, editor area
|
|
236
363
|
toolbar.style.width = wysiwygFrame.style.height = '100%';
|
|
@@ -254,7 +381,7 @@ class Viewer {
|
|
|
254
381
|
});
|
|
255
382
|
} else {
|
|
256
383
|
// frame
|
|
257
|
-
wysiwygFrame.style.cssText = this.#wysiwygOriginCssText.replace(/\s?display(\s+)?:(\s+)?[a-zA-Z]+;/, '') + (isCodeView ? 'display: none;' : '');
|
|
384
|
+
wysiwygFrame.style.cssText = this.#wysiwygOriginCssText.replace(/\s?display(\s+)?:(\s+)?[a-zA-Z]+;/, '') + (isCodeView || isMarkdownView ? 'display: none;' : '');
|
|
258
385
|
|
|
259
386
|
// code wrapper
|
|
260
387
|
codeWrapper.style.cssText = this.#codeWrapperOriginCssText.replace(/\s?display(\s+)?:(\s+)?[a-zA-Z]+;/, '') + `display: ${!isCodeView ? 'none' : 'flex'} !important;`;
|
|
@@ -263,6 +390,13 @@ class Viewer {
|
|
|
263
390
|
code.style.cssText = this.#codeOriginCssText;
|
|
264
391
|
if (codeNumbers) codeNumbers.style.cssText = this.#codeNumberOriginCssText;
|
|
265
392
|
|
|
393
|
+
// markdown wrapper
|
|
394
|
+
if (markdownWrapper) {
|
|
395
|
+
markdownWrapper.style.cssText = this.#markdownWrapperOriginCssText.replace(/\s?display(\s+)?:(\s+)?[a-zA-Z]+;/, '') + `display: ${!isMarkdownView ? 'none' : 'flex'} !important;`;
|
|
396
|
+
}
|
|
397
|
+
if (markdownFrame) markdownFrame.style.cssText = this.#markdownOriginCssText;
|
|
398
|
+
if (markdownNumbers) markdownNumbers.style.cssText = this.#markdownNumberOriginCssText;
|
|
399
|
+
|
|
266
400
|
// toolbar, editor area
|
|
267
401
|
toolbar.style.cssText = this.#toolbarOriginCssText;
|
|
268
402
|
editorArea.style.cssText = this.#editorAreaOriginCssText;
|
|
@@ -304,7 +438,7 @@ class Viewer {
|
|
|
304
438
|
});
|
|
305
439
|
}
|
|
306
440
|
|
|
307
|
-
if (wasToolbarHidden && !fc.get('isCodeView')) this.#$.toolbar.hide();
|
|
441
|
+
if (wasToolbarHidden && !fc.get('isCodeView') && !fc.get('isMarkdownView')) this.#$.toolbar.hide();
|
|
308
442
|
|
|
309
443
|
// user event
|
|
310
444
|
this.#eventManager.triggerEvent('onToggleFullScreen', { frameContext: fc, is: fc.get('isFullScreen') });
|
|
@@ -359,6 +493,13 @@ class Viewer {
|
|
|
359
493
|
});
|
|
360
494
|
}
|
|
361
495
|
|
|
496
|
+
// markdownView
|
|
497
|
+
if (fc.get('isMarkdownView')) {
|
|
498
|
+
dom.utils.addClass(this.#$.commandDispatcher.targets.get('markdownView'), 'active');
|
|
499
|
+
} else {
|
|
500
|
+
dom.utils.removeClass(this.#$.commandDispatcher.targets.get('markdownView'), 'active');
|
|
501
|
+
}
|
|
502
|
+
|
|
362
503
|
// showBlocks
|
|
363
504
|
if (fc.get('isShowBlocks')) {
|
|
364
505
|
dom.utils.addClass(this.#$.commandDispatcher.targets.get('showBlocks'), 'active');
|
|
@@ -582,7 +723,7 @@ class Viewer {
|
|
|
582
723
|
* @internal
|
|
583
724
|
* @description Adjusts the height of the code view area.
|
|
584
725
|
* - Ensures the code block `auto`-resizes based on its content.
|
|
585
|
-
* @param {
|
|
726
|
+
* @param {HTMLTextAreaElement} code - Code area
|
|
586
727
|
* @param {HTMLTextAreaElement} codeNumbers - Code numbers area
|
|
587
728
|
* @param {boolean} isAuto - `auto` height option
|
|
588
729
|
*/
|
|
@@ -603,6 +744,29 @@ class Viewer {
|
|
|
603
744
|
codeNumbers.scrollLeft = this.scrollLeft;
|
|
604
745
|
}
|
|
605
746
|
|
|
747
|
+
/**
|
|
748
|
+
* @internal
|
|
749
|
+
* @description Adjusts the height of the markdown view area.
|
|
750
|
+
* @param {HTMLTextAreaElement} md - Markdown area
|
|
751
|
+
* @param {HTMLTextAreaElement} mdNumbers - Markdown numbers area
|
|
752
|
+
* @param {boolean} isAuto - `auto` height option
|
|
753
|
+
*/
|
|
754
|
+
_markdownViewAutoHeight(md, mdNumbers, isAuto) {
|
|
755
|
+
if (isAuto) md.style.height = md.scrollHeight + 'px';
|
|
756
|
+
this.#updateLineNumbers(mdNumbers, md);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
/**
|
|
760
|
+
* @internal
|
|
761
|
+
* @this {HTMLElement} Markdown numbers area
|
|
762
|
+
* @description Synchronizes scrolling of line numbers with the markdown editor.
|
|
763
|
+
* @param {HTMLTextAreaElement} mdNumbers - Markdown numbers textarea
|
|
764
|
+
*/
|
|
765
|
+
_scrollMarkdownLineNumbers(mdNumbers) {
|
|
766
|
+
mdNumbers.scrollTop = this.scrollTop;
|
|
767
|
+
mdNumbers.scrollLeft = this.scrollLeft;
|
|
768
|
+
}
|
|
769
|
+
|
|
606
770
|
/**
|
|
607
771
|
* @description Convert the data of the code view and put it in the `WYSIWYG` area.
|
|
608
772
|
*/
|
|
@@ -668,25 +832,44 @@ class Viewer {
|
|
|
668
832
|
this._setCodeView(codeValue);
|
|
669
833
|
}
|
|
670
834
|
|
|
835
|
+
/**
|
|
836
|
+
* @description Convert the data of the `WYSIWYG` area and put it in the markdown view area.
|
|
837
|
+
*/
|
|
838
|
+
#setEditorDataToMarkdownView() {
|
|
839
|
+
const json = converter.htmlToJson(this.#frameContext.get('wysiwyg').innerHTML);
|
|
840
|
+
const md = markdown.jsonToMarkdown(json);
|
|
841
|
+
this.#frameContext.get('markdown').value = md;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
/**
|
|
845
|
+
* @description Convert the data of the markdown view and put it in the `WYSIWYG` area.
|
|
846
|
+
*/
|
|
847
|
+
#setMarkdownDataToEditor() {
|
|
848
|
+
const md = this.#frameContext.get('markdown').value;
|
|
849
|
+
const html = markdown.markdownToHtml(md, this.#options.get('defaultLine'));
|
|
850
|
+
|
|
851
|
+
this.#frameContext.get('wysiwyg').innerHTML =
|
|
852
|
+
html.length > 0 ? this.#$.html.clean(html, { forceFormat: true, whitelist: null, blacklist: null }) : '<' + this.#options.get('defaultLine') + '><br></' + this.#options.get('defaultLine') + '>';
|
|
853
|
+
}
|
|
854
|
+
|
|
671
855
|
/**
|
|
672
856
|
* @description Updates the line numbers for the code editor.
|
|
673
857
|
* - Dynamically adjusts line numbers as content grows.
|
|
674
858
|
* @param {HTMLTextAreaElement} lineNumbers - Code numbers area
|
|
675
|
-
* @param {
|
|
859
|
+
* @param {HTMLTextAreaElement} code - Code area
|
|
676
860
|
*/
|
|
677
861
|
#updateLineNumbers(lineNumbers, code) {
|
|
678
862
|
if (!lineNumbers) return;
|
|
679
863
|
|
|
680
|
-
const
|
|
681
|
-
const numberOfLinesNeeded = Math.ceil(code.scrollHeight / lineHeight);
|
|
682
|
-
|
|
864
|
+
const numberOfLinesNeeded = (code.value.match(/\n/g) || []).length + 1;
|
|
683
865
|
const currentLineCount = (lineNumbers.value.match(/\n/g) || []).length;
|
|
684
|
-
|
|
866
|
+
|
|
867
|
+
if (numberOfLinesNeeded !== currentLineCount) {
|
|
685
868
|
let n = '';
|
|
686
|
-
for (let i =
|
|
869
|
+
for (let i = 1; i <= numberOfLinesNeeded; i++) {
|
|
687
870
|
n += `${i}\n`;
|
|
688
871
|
}
|
|
689
|
-
lineNumbers.value
|
|
872
|
+
lineNumbers.value = n;
|
|
690
873
|
}
|
|
691
874
|
}
|
|
692
875
|
|
|
@@ -700,44 +883,32 @@ class Viewer {
|
|
|
700
883
|
}
|
|
701
884
|
|
|
702
885
|
/**
|
|
703
|
-
* @description Create line numbers for the code view area
|
|
886
|
+
* @description Create line numbers for the code/markdown view area
|
|
704
887
|
* @param {SunEditor.FrameContext} fc - Frame context
|
|
888
|
+
* @param {"code"|"markdown"} [type="code"] - View type
|
|
705
889
|
*/
|
|
706
|
-
function CreateLineNumbers(fc) {
|
|
707
|
-
const
|
|
708
|
-
|
|
890
|
+
function CreateLineNumbers(fc, type) {
|
|
891
|
+
const numbersKey = type === 'markdown' ? 'markdownNumbers' : 'codeNumbers';
|
|
892
|
+
const contentKey = type === 'markdown' ? 'markdown' : 'code';
|
|
893
|
+
const lineNumbers = fc.get(numbersKey);
|
|
894
|
+
if (!lineNumbers) return;
|
|
709
895
|
|
|
710
|
-
const
|
|
711
|
-
const numberOfLines =
|
|
896
|
+
const content = fc.get(contentKey);
|
|
897
|
+
const numberOfLines = (content.value.match(/\n/g) || []).length + 1;
|
|
712
898
|
|
|
713
899
|
let n = '';
|
|
714
900
|
for (let i = 1; i <= numberOfLines; i++) {
|
|
715
901
|
n += `${i}\n`;
|
|
716
902
|
}
|
|
717
903
|
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
* @param {HTMLTextAreaElement} textarea Textarea element
|
|
727
|
-
* @returns {number}
|
|
728
|
-
*/
|
|
729
|
-
function GetLineHeight(textarea) {
|
|
730
|
-
const lineHeight = _w.getComputedStyle(textarea).lineHeight;
|
|
731
|
-
let lineHeightMatch;
|
|
732
|
-
|
|
733
|
-
if (!numbers.is(lineHeight)) {
|
|
734
|
-
const fontSize = _w.getComputedStyle(textarea).fontSize;
|
|
735
|
-
lineHeightMatch = numbers.get(fontSize) * 1.2;
|
|
736
|
-
} else {
|
|
737
|
-
lineHeightMatch = numbers.get(lineHeight);
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
return lineHeightMatch;
|
|
904
|
+
// Sync font and line-height for accurate scroll alignment
|
|
905
|
+
const contentStyle = _w.getComputedStyle(content);
|
|
906
|
+
lineNumbers.style.lineHeight = contentStyle.lineHeight;
|
|
907
|
+
lineNumbers.style.fontSize = contentStyle.fontSize;
|
|
908
|
+
lineNumbers.style.fontFamily = contentStyle.fontFamily;
|
|
909
|
+
lineNumbers.style.paddingTop = contentStyle.paddingTop;
|
|
910
|
+
lineNumbers.style.paddingBottom = contentStyle.paddingBottom;
|
|
911
|
+
lineNumbers.value = n;
|
|
741
912
|
}
|
|
742
913
|
|
|
743
914
|
export default Viewer;
|