suneditor 3.1.2 → 3.1.3
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 +1 -1
- package/dist/suneditor.min.css +1 -1
- package/dist/suneditor.min.js +1 -1
- package/package.json +9 -6
- package/src/assets/suneditor.css +28 -2
- package/src/core/event/handlers/handler_ww_dragDrop.js +20 -0
- package/src/core/logic/panel/menu.js +4 -0
- package/src/core/logic/shell/ui.js +13 -2
- package/src/core/schema/options.js +1 -1
- package/src/core/section/constructor.js +29 -12
- package/src/core/section/documentType.js +55 -29
- package/src/modules/contract/Browser.js +3 -0
- package/src/modules/contract/Controller.js +3 -0
- package/src/modules/contract/Figure.js +23 -4
- package/src/modules/contract/Modal.js +2 -0
- package/src/plugins/dropdown/table/services/table.style.js +21 -12
- package/types/core/schema/options.d.ts +2 -2
- package/types/core/section/documentType.d.ts +17 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "suneditor",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.3",
|
|
4
4
|
"description": "Vanilla JavaScript based WYSIWYG web editor",
|
|
5
5
|
"author": "Yi JiHong",
|
|
6
6
|
"license": "MIT",
|
|
@@ -49,16 +49,19 @@
|
|
|
49
49
|
"engines": {
|
|
50
50
|
"node": ">=14.0.0"
|
|
51
51
|
},
|
|
52
|
+
"overrides": {
|
|
53
|
+
"uuid": ">=14.0.0"
|
|
54
|
+
},
|
|
52
55
|
"scripts": {
|
|
53
56
|
"dev": "webpack-dev-server --config webpack/dev.js",
|
|
54
57
|
"start": "npm run dev",
|
|
55
58
|
"build:dev": "cross-env NODE_ENV=development webpack --config webpack/builder.js && cross-env NODE_ENV=development webpack --config webpack/builder-contents.js && rm -f dist/_suneditor-contents.js",
|
|
56
59
|
"build:prod": "cross-env NODE_ENV=production webpack --config webpack/builder.js && cross-env NODE_ENV=production webpack --config webpack/builder-contents.js && rm -f dist/_suneditor-contents.js",
|
|
57
60
|
"lint:type": "npx tsc --noEmit",
|
|
58
|
-
"lint:fix-js": "npx eslint
|
|
61
|
+
"lint:fix-js": "npx eslint src/ --fix",
|
|
59
62
|
"lint:fix-ts": "npx eslint types/ --fix",
|
|
60
|
-
"lint:fix-all": "npx eslint
|
|
61
|
-
"lint": "npx eslint
|
|
63
|
+
"lint:fix-all": "npx eslint src/ types/ --fix",
|
|
64
|
+
"lint": "npx eslint src/ types/ && npm run lint:type && npm run check:arch",
|
|
62
65
|
"ts-build": "npm run check:inject && (npx tsc || true) && barrelsby --config .barrelsby.json && node scripts/ts-build/format-index.cjs && node scripts/ts-build/fix-langs.cjs && node scripts/ts-build/wrap-dts.cjs && node scripts/ts-build/rename-index.cjs && node scripts/ts-build/interfaces-convert.cjs && node scripts/ts-build/gen-options-dts.cjs && node scripts/ts-build/gen-css-dts.cjs && node scripts/ts-build/inject-typedef-import.cjs && npm run lint:fix-ts",
|
|
63
66
|
"test": "jest --silent",
|
|
64
67
|
"test:watch": "jest --watch",
|
|
@@ -125,13 +128,13 @@
|
|
|
125
128
|
"webpack": "^5.102.0",
|
|
126
129
|
"webpack-bundle-analyzer": "^4.10.2",
|
|
127
130
|
"webpack-cli": "^6.0.1",
|
|
128
|
-
"webpack-dev-server": "^5.2.
|
|
131
|
+
"webpack-dev-server": "^5.2.3",
|
|
129
132
|
"webpack-merge": "^6.0.1"
|
|
130
133
|
},
|
|
131
134
|
"browserslist": [
|
|
132
135
|
"chrome >= 119",
|
|
133
136
|
"edge >= 119",
|
|
134
|
-
"firefox >=
|
|
137
|
+
"firefox >= 125",
|
|
135
138
|
"safari >= 17.2",
|
|
136
139
|
"opera >= 105",
|
|
137
140
|
"samsung >= 23",
|
package/src/assets/suneditor.css
CHANGED
|
@@ -1149,6 +1149,26 @@
|
|
|
1149
1149
|
z-index: 2147483646;
|
|
1150
1150
|
}
|
|
1151
1151
|
|
|
1152
|
+
/** --- popover UA override ---------------------------------------------------- */
|
|
1153
|
+
.sun-editor .se-controller[popover],
|
|
1154
|
+
.sun-editor.sun-editor-carrier-wrapper .se-drag-cursor[popover] {
|
|
1155
|
+
inset: unset;
|
|
1156
|
+
margin: 0;
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
.sun-editor .se-modal-area[popover],
|
|
1160
|
+
.sun-editor .se-back-wrapper[popover],
|
|
1161
|
+
.sun-editor .se-loading-box[popover],
|
|
1162
|
+
.sun-editor .se-toast[popover],
|
|
1163
|
+
.sun-editor .se-browser[popover],
|
|
1164
|
+
.sun-editor .se-menu-tray[popover] {
|
|
1165
|
+
background: none;
|
|
1166
|
+
border: none;
|
|
1167
|
+
padding: 0;
|
|
1168
|
+
overflow: visible;
|
|
1169
|
+
color: inherit;
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1152
1172
|
/** --- dropdown layer ---------------------------------------------------------- */
|
|
1153
1173
|
.sun-editor .se-dropdown {
|
|
1154
1174
|
overflow-x: hidden;
|
|
@@ -2568,6 +2588,12 @@
|
|
|
2568
2588
|
display: none;
|
|
2569
2589
|
overflow: visible;
|
|
2570
2590
|
z-index: 2147483646;
|
|
2591
|
+
}
|
|
2592
|
+
|
|
2593
|
+
.sun-editor .se-controller[popover]:popover-open {
|
|
2594
|
+
position: absolute;
|
|
2595
|
+
inset: unset;
|
|
2596
|
+
margin: 0;
|
|
2571
2597
|
padding: 2px 2px 0 2px;
|
|
2572
2598
|
margin: 0;
|
|
2573
2599
|
border: 1px solid var(--se-controller-border-color);
|
|
@@ -4553,8 +4579,8 @@
|
|
|
4553
4579
|
.sun-editor-editable[contenteditable='true'] .se-page-break::after {
|
|
4554
4580
|
content: '⎯⎯⎯⎯⎯⎯';
|
|
4555
4581
|
position: absolute;
|
|
4556
|
-
top:
|
|
4557
|
-
background:
|
|
4582
|
+
top: 0px;
|
|
4583
|
+
background: transparent;
|
|
4558
4584
|
padding: 0 5px;
|
|
4559
4585
|
color: var(--se-doc-info-page-background-color);
|
|
4560
4586
|
font-size: var(--se-main-font-size);
|
|
@@ -46,7 +46,17 @@ export function OnDragOver_wysiwyg(fc, dragCursor, _iframeTopArea, _innerToolbar
|
|
|
46
46
|
dragCursor.style.top = `${rect.top + _w.scrollY + _offset.y - 5 + frameY}px`;
|
|
47
47
|
dragCursor.style.height = `${rect.height + 10}px`;
|
|
48
48
|
dragCursor.style.display = 'block';
|
|
49
|
+
try {
|
|
50
|
+
dragCursor.showPopover?.();
|
|
51
|
+
} catch {
|
|
52
|
+
// ignore
|
|
53
|
+
}
|
|
49
54
|
} else {
|
|
55
|
+
try {
|
|
56
|
+
dragCursor.hidePopover?.();
|
|
57
|
+
} catch {
|
|
58
|
+
// ignore
|
|
59
|
+
}
|
|
50
60
|
dragCursor.style.display = 'none';
|
|
51
61
|
}
|
|
52
62
|
}
|
|
@@ -56,6 +66,11 @@ export function OnDragOver_wysiwyg(fc, dragCursor, _iframeTopArea, _innerToolbar
|
|
|
56
66
|
* @param {HTMLElement} dragCursor - Drag cursor element
|
|
57
67
|
*/
|
|
58
68
|
export function OnDragEnd_wysiwyg(dragCursor) {
|
|
69
|
+
try {
|
|
70
|
+
dragCursor.hidePopover?.();
|
|
71
|
+
} catch {
|
|
72
|
+
// ignore
|
|
73
|
+
}
|
|
59
74
|
dragCursor.style.display = 'none';
|
|
60
75
|
}
|
|
61
76
|
|
|
@@ -109,6 +124,11 @@ export function OnDrop_wysiwyg(fc, dragCursor, e) {
|
|
|
109
124
|
this.$.selection.setRange(sc, so, ec, eo);
|
|
110
125
|
return this._dataTransferAction('drop', e, dataTransfer, fc);
|
|
111
126
|
} finally {
|
|
127
|
+
try {
|
|
128
|
+
dragCursor.hidePopover?.();
|
|
129
|
+
} catch {
|
|
130
|
+
// ignore
|
|
131
|
+
}
|
|
112
132
|
dragCursor.style.display = 'none';
|
|
113
133
|
}
|
|
114
134
|
}
|
|
@@ -122,6 +122,7 @@ class Menu {
|
|
|
122
122
|
this.#setMenuPosition(btnEl, menu);
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
this.#context.get('menuTray').showPopover?.();
|
|
125
126
|
this.#bindClose_dropdown_mouse = this.#eventManager.addGlobalEvent('mousedown', this.#globalEventHandler.mousedown, false);
|
|
126
127
|
if (this.#dropdownCommands.includes(dropdownName)) {
|
|
127
128
|
this.menus = converter.nodeListToArray(menu.querySelectorAll('[data-command]'));
|
|
@@ -162,6 +163,7 @@ class Menu {
|
|
|
162
163
|
}
|
|
163
164
|
this.currentDropdownActiveButton = null;
|
|
164
165
|
this.#$.ui.preventToolbarHide(false);
|
|
166
|
+
this.#context.get('menuTray').hidePopover?.();
|
|
165
167
|
}
|
|
166
168
|
|
|
167
169
|
this.#store.set('_preventBlur', false);
|
|
@@ -209,6 +211,7 @@ class Menu {
|
|
|
209
211
|
this.#setMenuPosition(button, this.currentContainer);
|
|
210
212
|
}
|
|
211
213
|
|
|
214
|
+
this.#context.get('menuTray').showPopover?.();
|
|
212
215
|
this.#bindClose_cons_mouse = this.#eventManager.addGlobalEvent('mousedown', this.#globalEventHandler.containerDown, false);
|
|
213
216
|
|
|
214
217
|
if (this.#$.plugins[containerName].on) this.#$.plugins[containerName].on(button);
|
|
@@ -229,6 +232,7 @@ class Menu {
|
|
|
229
232
|
dom.utils.removeClass(this.currentContainerActiveButton, 'on');
|
|
230
233
|
this.currentContainerActiveButton = null;
|
|
231
234
|
this.#$.ui.preventToolbarHide(false);
|
|
235
|
+
this.#context.get('menuTray').hidePopover?.();
|
|
232
236
|
}
|
|
233
237
|
|
|
234
238
|
this.#store.set('_preventBlur', false);
|
|
@@ -89,6 +89,7 @@ class UIManager {
|
|
|
89
89
|
|
|
90
90
|
// toast
|
|
91
91
|
const toastPopup = CreateToastHTML();
|
|
92
|
+
toastPopup.setAttribute('popover', 'manual');
|
|
92
93
|
this.toastPopup = toastPopup;
|
|
93
94
|
this.toastContainer = toastPopup.querySelector('.se-toast-container');
|
|
94
95
|
this.toastMessage = toastPopup.querySelector('span');
|
|
@@ -396,7 +397,9 @@ class UIManager {
|
|
|
396
397
|
* @param {string} [rootKey] Root key
|
|
397
398
|
*/
|
|
398
399
|
showLoading(rootKey) {
|
|
399
|
-
/** @type {HTMLElement} */ ((rootKey ? this.#frameRoots.get(rootKey).get('container') : this.#carrierWrapper).querySelector('.se-loading-box'))
|
|
400
|
+
const el = /** @type {HTMLElement} */ ((rootKey ? this.#frameRoots.get(rootKey).get('container') : this.#carrierWrapper).querySelector('.se-loading-box'));
|
|
401
|
+
el.style.display = 'block';
|
|
402
|
+
el.showPopover?.();
|
|
400
403
|
}
|
|
401
404
|
|
|
402
405
|
/**
|
|
@@ -404,7 +407,9 @@ class UIManager {
|
|
|
404
407
|
* @param {string} [rootKey] Root key
|
|
405
408
|
*/
|
|
406
409
|
hideLoading(rootKey) {
|
|
407
|
-
/** @type {HTMLElement} */ ((rootKey ? this.#frameRoots.get(rootKey).get('container') : this.#carrierWrapper).querySelector('.se-loading-box'))
|
|
410
|
+
const el = /** @type {HTMLElement} */ ((rootKey ? this.#frameRoots.get(rootKey).get('container') : this.#carrierWrapper).querySelector('.se-loading-box'));
|
|
411
|
+
el.hidePopover?.();
|
|
412
|
+
el.style.display = 'none';
|
|
408
413
|
}
|
|
409
414
|
|
|
410
415
|
/**
|
|
@@ -423,6 +428,7 @@ class UIManager {
|
|
|
423
428
|
this.#bindClose = this.#eventManager.addGlobalEvent('keydown', this.#closeListener[0]);
|
|
424
429
|
|
|
425
430
|
this.#alertArea.style.display = 'block';
|
|
431
|
+
this.#alertArea.showPopover?.();
|
|
426
432
|
dom.utils.addClass(this.alertModal, 'se-modal-show');
|
|
427
433
|
}
|
|
428
434
|
|
|
@@ -432,6 +438,7 @@ class UIManager {
|
|
|
432
438
|
alertClose() {
|
|
433
439
|
dom.utils.removeClass(this.alertModal, 'se-modal-show');
|
|
434
440
|
dom.utils.removeClass(this.alertModal, 'se-alert-*');
|
|
441
|
+
this.#alertArea.hidePopover?.();
|
|
435
442
|
this.#alertArea.style.display = 'none';
|
|
436
443
|
this.#bindAlertClick &&= this.#eventManager.removeEvent(this.#bindAlertClick);
|
|
437
444
|
this.#bindClose &&= this.#eventManager.removeGlobalEvent(this.#bindClose);
|
|
@@ -452,6 +459,7 @@ class UIManager {
|
|
|
452
459
|
if (type) dom.utils.addClass(this.toastPopup, `se-toast-${type}`);
|
|
453
460
|
|
|
454
461
|
this.toastPopup.style.display = 'block';
|
|
462
|
+
this.toastPopup.showPopover?.();
|
|
455
463
|
this.toastMessage.textContent = message;
|
|
456
464
|
dom.utils.addClass(this.toastContainer, 'se-toast-show');
|
|
457
465
|
|
|
@@ -468,6 +476,7 @@ class UIManager {
|
|
|
468
476
|
if (this.#toastToggle) _w.clearTimeout(this.#toastToggle);
|
|
469
477
|
this.#toastToggle = null;
|
|
470
478
|
dom.utils.removeClass(this.toastContainer, 'se-toast-show');
|
|
479
|
+
this.toastPopup.hidePopover?.();
|
|
471
480
|
this.toastPopup.style.display = 'none';
|
|
472
481
|
}
|
|
473
482
|
|
|
@@ -509,12 +518,14 @@ class UIManager {
|
|
|
509
518
|
enableBackWrapper(cursor) {
|
|
510
519
|
this.#backWrapper.style.cursor = cursor;
|
|
511
520
|
this.#backWrapper.style.display = 'block';
|
|
521
|
+
this.#backWrapper.showPopover?.();
|
|
512
522
|
}
|
|
513
523
|
|
|
514
524
|
/**
|
|
515
525
|
* @description Disabled background `div`
|
|
516
526
|
*/
|
|
517
527
|
disableBackWrapper() {
|
|
528
|
+
this.#backWrapper.hidePopover?.();
|
|
518
529
|
this.#backWrapper.style.display = 'none';
|
|
519
530
|
this.#backWrapper.style.cursor = 'default';
|
|
520
531
|
}
|
|
@@ -6,6 +6,7 @@ import { dom, numbers, converter, env } from '../../helper';
|
|
|
6
6
|
import { DEFAULTS } from '../schema/options';
|
|
7
7
|
|
|
8
8
|
const _d = env._d;
|
|
9
|
+
let editorInstanceId = 0;
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* @typedef {import('../schema/options').AllBaseOptions} AllBaseOptions_constructor
|
|
@@ -57,16 +58,21 @@ function Constructor(editorTargets, options) {
|
|
|
57
58
|
const icons = optionMap.i;
|
|
58
59
|
const lang = optionMap.l;
|
|
59
60
|
const loadingBox = dom.utils.createElement('DIV', { class: 'se-loading-box sun-editor-common' }, '<div class="se-loading-effect"></div>');
|
|
61
|
+
const editorFormFieldPrefix = 'suneditor-' + ++editorInstanceId;
|
|
60
62
|
|
|
61
63
|
/** --- carrier wrapper --------------------------------------------------------------- */
|
|
62
64
|
const editor_carrier_wrapper = dom.utils.createElement('DIV', { class: 'sun-editor sun-editor-carrier-wrapper sun-editor-common' + o.get('_themeClass') + (o.get('_rtl') ? ' se-rtl' : '') });
|
|
63
65
|
// menuTray
|
|
64
|
-
const menuTray = dom.utils.createElement('DIV', { class: 'se-menu-tray' });
|
|
66
|
+
const menuTray = dom.utils.createElement('DIV', { class: 'se-menu-tray', popover: 'manual' });
|
|
65
67
|
editor_carrier_wrapper.appendChild(menuTray);
|
|
66
68
|
// focus temp element
|
|
67
69
|
const focusTemp = /** @type {HTMLInputElement} */ (
|
|
68
70
|
dom.utils.createElement('INPUT', {
|
|
71
|
+
type: 'text',
|
|
72
|
+
id: editorFormFieldPrefix + '-focus-temp',
|
|
69
73
|
class: '__se__focus__temp__',
|
|
74
|
+
autocomplete: 'off',
|
|
75
|
+
'aria-hidden': 'true',
|
|
70
76
|
style: 'position: fixed !important; top: -10000px !important; left: -10000px !important; display: block !important; width: 0 !important; height: 0 !important; margin: 0 !important; padding: 0 !important;',
|
|
71
77
|
})
|
|
72
78
|
);
|
|
@@ -74,7 +80,7 @@ function Constructor(editorTargets, options) {
|
|
|
74
80
|
editor_carrier_wrapper.appendChild(focusTemp);
|
|
75
81
|
|
|
76
82
|
// modal
|
|
77
|
-
const modal = dom.utils.createElement('DIV', { class: 'se-modal se-modal-area sun-editor-common' });
|
|
83
|
+
const modal = dom.utils.createElement('DIV', { class: 'se-modal se-modal-area sun-editor-common', popover: 'manual' });
|
|
78
84
|
const modal_back = dom.utils.createElement('DIV', { class: 'se-modal-back' });
|
|
79
85
|
const modal_inner = dom.utils.createElement('DIV', { class: 'se-modal-inner' });
|
|
80
86
|
modal.appendChild(modal_back);
|
|
@@ -82,7 +88,7 @@ function Constructor(editorTargets, options) {
|
|
|
82
88
|
editor_carrier_wrapper.appendChild(modal);
|
|
83
89
|
|
|
84
90
|
// alert
|
|
85
|
-
const alert = dom.utils.createElement('DIV', { class: 'se-alert se-modal-area sun-editor-common', style: 'display: none;' });
|
|
91
|
+
const alert = dom.utils.createElement('DIV', { class: 'se-alert se-modal-area sun-editor-common', style: 'display: none;', popover: 'manual' });
|
|
86
92
|
const alert_back = dom.utils.createElement('DIV', { class: 'se-modal-back' });
|
|
87
93
|
const alert_inner = dom.utils.createElement('DIV', { class: 'se-modal-inner' });
|
|
88
94
|
alert.appendChild(alert_back);
|
|
@@ -90,11 +96,13 @@ function Constructor(editorTargets, options) {
|
|
|
90
96
|
editor_carrier_wrapper.appendChild(alert);
|
|
91
97
|
|
|
92
98
|
// loding box, resizing back
|
|
93
|
-
editor_carrier_wrapper.appendChild(dom.utils.createElement('DIV', { class: 'se-back-wrapper' }));
|
|
94
|
-
|
|
99
|
+
editor_carrier_wrapper.appendChild(dom.utils.createElement('DIV', { class: 'se-back-wrapper', popover: 'manual' }));
|
|
100
|
+
const loadingBoxEl = /** @type {HTMLElement} */ (loadingBox.cloneNode(true));
|
|
101
|
+
loadingBoxEl.setAttribute('popover', 'manual');
|
|
102
|
+
editor_carrier_wrapper.appendChild(loadingBoxEl);
|
|
95
103
|
|
|
96
104
|
// drag cursor
|
|
97
|
-
const dragCursor = dom.utils.createElement('DIV', { class: 'se-drag-cursor' });
|
|
105
|
+
const dragCursor = dom.utils.createElement('DIV', { class: 'se-drag-cursor', popover: 'manual' });
|
|
98
106
|
editor_carrier_wrapper.appendChild(dragCursor);
|
|
99
107
|
|
|
100
108
|
// set carrier wrapper
|
|
@@ -146,7 +154,7 @@ function Constructor(editorTargets, options) {
|
|
|
146
154
|
container.appendChild(dom.utils.createElement('DIV', { class: 'se-toolbar-shadow' }));
|
|
147
155
|
|
|
148
156
|
// init element
|
|
149
|
-
const initElements = _initTargetElements(editTarget.key, o, top_div, to);
|
|
157
|
+
const initElements = _initTargetElements(editTarget.key, o, top_div, to, editorFormFieldPrefix);
|
|
150
158
|
const bottomBar = initElements.bottomBar;
|
|
151
159
|
const statusbar = bottomBar.statusbar;
|
|
152
160
|
const wysiwyg_div = initElements.wysiwygFrame;
|
|
@@ -195,7 +203,11 @@ function Constructor(editorTargets, options) {
|
|
|
195
203
|
// not used code mirror
|
|
196
204
|
if (textarea === codeMirrorEl) {
|
|
197
205
|
// add line nubers
|
|
198
|
-
const codeNumbers = dom.utils.createElement(
|
|
206
|
+
const codeNumbers = dom.utils.createElement(
|
|
207
|
+
'TEXTAREA',
|
|
208
|
+
{ id: editorFormFieldPrefix + '-code-view-line-' + (key || 'default'), class: 'se-code-view-line', readonly: 'true', autocomplete: 'off', 'aria-hidden': 'true', tabindex: '-1' },
|
|
209
|
+
null,
|
|
210
|
+
);
|
|
199
211
|
codeWrapper.insertBefore(codeNumbers, textarea);
|
|
200
212
|
} else {
|
|
201
213
|
textarea = codeMirrorEl;
|
|
@@ -207,7 +219,11 @@ function Constructor(editorTargets, options) {
|
|
|
207
219
|
let markdownTextarea = null;
|
|
208
220
|
if (o.get('buttons').has('markdownView')) {
|
|
209
221
|
markdownTextarea = initElements.markdownView;
|
|
210
|
-
const markdownNumbers = dom.utils.createElement(
|
|
222
|
+
const markdownNumbers = dom.utils.createElement(
|
|
223
|
+
'TEXTAREA',
|
|
224
|
+
{ id: editorFormFieldPrefix + '-markdown-view-line-' + (key || 'default'), class: 'se-markdown-view-line', readonly: 'true', autocomplete: 'off', 'aria-hidden': 'true', tabindex: '-1' },
|
|
225
|
+
null,
|
|
226
|
+
);
|
|
211
227
|
markdownWrapper = dom.utils.createElement('DIV', { class: 'se-markdown-wrapper' });
|
|
212
228
|
markdownWrapper.appendChild(markdownNumbers);
|
|
213
229
|
markdownWrapper.appendChild(markdownTextarea);
|
|
@@ -934,9 +950,10 @@ function InitFrameOptions(o, origin) {
|
|
|
934
950
|
* @param {Map<string, *>} options - Options
|
|
935
951
|
* @param {HTMLElement} topDiv - Top div
|
|
936
952
|
* @param {SunEditor.FrameOptions} targetOptions - `editor.frameOptions`
|
|
953
|
+
* @param {string} formFieldPrefix - Prefix for generated form field ids
|
|
937
954
|
* @returns {{bottomBar: ReturnType<CreateStatusbar>, wysiwygFrame: HTMLElement, codeView: HTMLElement, markdownView: HTMLElement, placeholder: HTMLElement}}
|
|
938
955
|
*/
|
|
939
|
-
function _initTargetElements(key, options, topDiv, targetOptions) {
|
|
956
|
+
function _initTargetElements(key, options, topDiv, targetOptions, formFieldPrefix) {
|
|
940
957
|
const editorStyles = targetOptions.get('_defaultStyles');
|
|
941
958
|
/** top div */
|
|
942
959
|
topDiv.style.cssText = editorStyles.top;
|
|
@@ -990,10 +1007,10 @@ function _initTargetElements(key, options, topDiv, targetOptions) {
|
|
|
990
1007
|
}
|
|
991
1008
|
|
|
992
1009
|
// textarea for code view
|
|
993
|
-
const textarea = dom.utils.createElement('TEXTAREA', { class: 'se-wrapper-inner se-code-viewer', style: editorStyles.frame });
|
|
1010
|
+
const textarea = dom.utils.createElement('TEXTAREA', { id: formFieldPrefix + '-code-viewer-' + (key || 'default'), class: 'se-wrapper-inner se-code-viewer', style: editorStyles.frame, autocomplete: 'off' });
|
|
994
1011
|
|
|
995
1012
|
// textarea for markdown view
|
|
996
|
-
const markdownTextarea = dom.utils.createElement('TEXTAREA', { class: 'se-wrapper-inner se-markdown-viewer', style: editorStyles.frame });
|
|
1013
|
+
const markdownTextarea = dom.utils.createElement('TEXTAREA', { id: formFieldPrefix + '-markdown-viewer-' + (key || 'default'), class: 'se-wrapper-inner se-markdown-viewer', style: editorStyles.frame, autocomplete: 'off' });
|
|
997
1014
|
|
|
998
1015
|
const placeholder = dom.utils.createElement('SPAN', { class: 'se-placeholder' });
|
|
999
1016
|
if (targetOptions.get('placeholder')) {
|
|
@@ -162,28 +162,19 @@ class DocumentType {
|
|
|
162
162
|
|
|
163
163
|
// page break
|
|
164
164
|
let pageBreakHeight = 0;
|
|
165
|
-
|
|
166
|
-
let additionalPages = 0;
|
|
165
|
+
const breakPoints = [];
|
|
167
166
|
if (pageBreaks.length > 0) {
|
|
168
167
|
pageBreakHeight = pageBreaks[0].offsetHeight;
|
|
169
168
|
for (let i = 0; i < pageBreaks.length; i++) {
|
|
170
|
-
|
|
171
|
-
const sectionHeight = breakPosition - lastBreakPosition;
|
|
172
|
-
if (sectionHeight % A4_PAGE_HEIGHT !== 0) additionalPages++;
|
|
173
|
-
lastBreakPosition = breakPosition;
|
|
169
|
+
breakPoints.push({ top: pageBreaks[i].offsetTop, end: pageBreaks[i].offsetTop + pageBreakHeight / 2 });
|
|
174
170
|
}
|
|
175
|
-
|
|
176
|
-
const lastSectionHeight = mirrorHeight - lastBreakPosition;
|
|
177
|
-
if (lastSectionHeight > 0 && lastSectionHeight % A4_PAGE_HEIGHT !== 0) additionalPages++;
|
|
178
171
|
}
|
|
179
172
|
|
|
180
173
|
const scrollTop = !this.#isScrollable(this.#fc) ? 0 : this._getWWScrollTop();
|
|
181
|
-
const
|
|
182
|
-
const wwWidth = this.#wwFrame.offsetWidth + 1;
|
|
183
|
-
const pages = [];
|
|
174
|
+
const pages = [{ number: 0, top: 0 }];
|
|
184
175
|
|
|
185
|
-
for (let i = 0; i <
|
|
186
|
-
pages.push({ number:
|
|
176
|
+
for (let i = 0; i < breakPoints.length; i++) {
|
|
177
|
+
pages.push({ number: 0, top: breakPoints[i].top + pageBreakHeight / 2, isBreak: true });
|
|
187
178
|
}
|
|
188
179
|
|
|
189
180
|
this.#mirrorCache = 0;
|
|
@@ -191,14 +182,27 @@ class DocumentType {
|
|
|
191
182
|
const mChr = this.#mirror.children;
|
|
192
183
|
this._initializeCache(mChr);
|
|
193
184
|
|
|
194
|
-
|
|
185
|
+
// Calculate page positions per section (between page breaks)
|
|
186
|
+
const sectionStarts = [0, ...breakPoints.map((b) => b.end)];
|
|
187
|
+
const sectionEnds = [...breakPoints.map((b) => b.top), mirrorHeight];
|
|
188
|
+
|
|
189
|
+
for (let s = 0; s < sectionStarts.length; s++) {
|
|
190
|
+
const sStart = sectionStarts[s];
|
|
191
|
+
const sEnd = sectionEnds[s];
|
|
192
|
+
let t = sStart;
|
|
193
|
+
let isFirst = s === 0;
|
|
195
194
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
if (
|
|
201
|
-
|
|
195
|
+
while (true) {
|
|
196
|
+
t += A4_PAGE_HEIGHT + (isFirst ? this.#paddingTop + this.#paddingBottom : this.#paddingTop);
|
|
197
|
+
isFirst = false;
|
|
198
|
+
|
|
199
|
+
if (t >= sEnd) break;
|
|
200
|
+
|
|
201
|
+
if (!pages.some((p) => Math.abs(p.top - t) < 3)) {
|
|
202
|
+
const top = this._calcPageBreakTop(t, chr, mChr, pages);
|
|
203
|
+
if (top === null) break;
|
|
204
|
+
pages.push({ number: 0, top });
|
|
205
|
+
}
|
|
202
206
|
}
|
|
203
207
|
}
|
|
204
208
|
|
|
@@ -214,8 +218,8 @@ class DocumentType {
|
|
|
214
218
|
this.#page.innerHTML = '';
|
|
215
219
|
this.#pages = [];
|
|
216
220
|
|
|
217
|
-
|
|
218
|
-
|
|
221
|
+
const wwWidth = this.#wwFrame.offsetWidth + 1;
|
|
222
|
+
for (let i = 0, t; i < pages.length; i++) {
|
|
219
223
|
t = pages[i].top;
|
|
220
224
|
if (mirrorHeight < t) break;
|
|
221
225
|
|
|
@@ -249,10 +253,11 @@ class DocumentType {
|
|
|
249
253
|
* @param {number} t - The initial top position value to be adjusted.
|
|
250
254
|
* @param {HTMLCollection} chr - The elements array in the current (main) page.
|
|
251
255
|
* @param {HTMLCollection} mChr - The elements array in the mirrored page.
|
|
256
|
+
* @param {Array.<{number: number, top: number, isBreak?: boolean}>} [pages] - The pages array containing page break info.
|
|
252
257
|
* @returns {number|null} The adjusted top value.
|
|
253
258
|
*/
|
|
254
|
-
_calcPageBreakTop(t, chr, mChr) {
|
|
255
|
-
const { ci } = this._getElementAtPosition(t, mChr);
|
|
259
|
+
_calcPageBreakTop(t, chr, mChr, pages) {
|
|
260
|
+
const { ci } = this._getElementAtPosition(t, mChr, pages);
|
|
256
261
|
const mel = /** @type {HTMLElement} */ (mChr[ci]);
|
|
257
262
|
const el = /** @type {HTMLElement} */ (chr[ci]);
|
|
258
263
|
if (!mel || !el) return null;
|
|
@@ -290,22 +295,39 @@ class DocumentType {
|
|
|
290
295
|
* @description Retrieves the element at a given position.
|
|
291
296
|
* @param {number} pageTop - The vertical position to check.
|
|
292
297
|
* @param {HTMLCollection} mChr - List of mirrored elements.
|
|
298
|
+
* @param {Array.<{number: number, top: number, isBreak?: boolean}>} [pages] - The pages array containing page break info for skipping break elements.
|
|
293
299
|
* @returns {{ci: number, cm: number, ch: number}} The closest element and its related data.
|
|
294
300
|
* - ci: The index of the closest element.
|
|
295
301
|
* - cm: The distance between the top of the closest element and the given position.
|
|
296
302
|
* - ch: The height of the closest element.
|
|
297
303
|
*/
|
|
298
|
-
_getElementAtPosition(pageTop, mChr) {
|
|
304
|
+
_getElementAtPosition(pageTop, mChr, pages) {
|
|
299
305
|
let start = this.#mirrorCache;
|
|
300
306
|
let end = mChr.length - 1;
|
|
301
307
|
|
|
308
|
+
// Reset cache if target position is before cached position (crossing section boundaries)
|
|
309
|
+
if (start > 0) {
|
|
310
|
+
const cachedPos = this.#positionCache.get(start);
|
|
311
|
+
if (cachedPos && pageTop < cachedPos.top) {
|
|
312
|
+
start = 0;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
302
316
|
while (start <= end) {
|
|
303
317
|
const mid = Math.floor((start + end) / 2);
|
|
304
318
|
const { top, height, bottom } = this.#positionCache.get(mid);
|
|
305
319
|
|
|
306
320
|
if (pageTop >= top && pageTop <= bottom) {
|
|
307
|
-
|
|
308
|
-
|
|
321
|
+
let ci = mid;
|
|
322
|
+
// Skip page break elements — use adjacent content element
|
|
323
|
+
if (pages && dom.utils.hasClass(mChr[ci], 'se-page-break')) {
|
|
324
|
+
ci = ci + 1 < mChr.length ? ci + 1 : Math.max(0, ci - 1);
|
|
325
|
+
const adjPos = this.#positionCache.get(ci);
|
|
326
|
+
this.#mirrorCache = ci;
|
|
327
|
+
return { ci, cm: pageTop - adjPos.bottom, ch: adjPos.height };
|
|
328
|
+
}
|
|
329
|
+
this.#mirrorCache = ci;
|
|
330
|
+
return { ci, cm: pageTop - bottom, ch: height };
|
|
309
331
|
}
|
|
310
332
|
|
|
311
333
|
if (pageTop < top) {
|
|
@@ -315,7 +337,11 @@ class DocumentType {
|
|
|
315
337
|
}
|
|
316
338
|
}
|
|
317
339
|
|
|
318
|
-
|
|
340
|
+
let closestIndex = mChr[start] ? start : end;
|
|
341
|
+
// Skip page break elements for closest match
|
|
342
|
+
if (pages && dom.utils.hasClass(mChr[closestIndex], 'se-page-break')) {
|
|
343
|
+
closestIndex = closestIndex + 1 < mChr.length ? closestIndex + 1 : Math.max(0, closestIndex - 1);
|
|
344
|
+
}
|
|
319
345
|
this.#mirrorCache = closestIndex;
|
|
320
346
|
const iElement = this.#positionCache.get(closestIndex);
|
|
321
347
|
return { ci: closestIndex, cm: pageTop - iElement.bottom, ch: iElement.height };
|
|
@@ -151,6 +151,7 @@ class Browser {
|
|
|
151
151
|
// init
|
|
152
152
|
browserFrame.appendChild(dom.utils.createElement('DIV', { class: 'se-browser-back' }));
|
|
153
153
|
browserFrame.appendChild(content);
|
|
154
|
+
browserFrame.setAttribute('popover', 'manual');
|
|
154
155
|
this.#$.contextProvider.carrierWrapper.appendChild(browserFrame);
|
|
155
156
|
|
|
156
157
|
this.#$.eventManager.addEvent(this.tagArea, 'click', this.#OnClickTag.bind(this));
|
|
@@ -197,6 +198,7 @@ class Browser {
|
|
|
197
198
|
|
|
198
199
|
this.titleArea.textContent = params.title || this.title;
|
|
199
200
|
this.area.style.display = 'block';
|
|
201
|
+
this.area.showPopover?.();
|
|
200
202
|
this.#$.ui.opendBrowser = this;
|
|
201
203
|
this.closeArrow = this.#$.options.get('_rtl') ? this.#$.icons.menu_arrow_left : this.#$.icons.menu_arrow_right;
|
|
202
204
|
|
|
@@ -217,6 +219,7 @@ class Browser {
|
|
|
217
219
|
this.#removeGlobalEvent();
|
|
218
220
|
this.apiManager.cancel();
|
|
219
221
|
|
|
222
|
+
this.area.hidePopover?.();
|
|
220
223
|
this.area.style.display = 'none';
|
|
221
224
|
this.selectedTags = [];
|
|
222
225
|
this.items = [];
|
|
@@ -110,6 +110,7 @@ class Controller {
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
// add element
|
|
113
|
+
this.form.setAttribute('popover', 'manual');
|
|
113
114
|
this.#$.contextProvider.carrierWrapper.appendChild(element);
|
|
114
115
|
|
|
115
116
|
// init
|
|
@@ -394,6 +395,7 @@ class Controller {
|
|
|
394
395
|
* @description Hide controller at editor area (link button, image resize button..)
|
|
395
396
|
*/
|
|
396
397
|
#controllerOff() {
|
|
398
|
+
this.form.hidePopover?.();
|
|
397
399
|
this.form.style.display = 'none';
|
|
398
400
|
this.#$.ui.opendControllers = this.#$.ui.opendControllers.filter((v) => v.form !== this.form);
|
|
399
401
|
if (this.#$.ui.currentControllerName !== this.kind && this.#$.ui.opendControllers.length > 0) return;
|
|
@@ -464,6 +466,7 @@ class Controller {
|
|
|
464
466
|
|
|
465
467
|
controller.style.zIndex = this.toTop ? INDEX_0 : this.#reserveIndex ? INDEX_S_1 : INDEX_1;
|
|
466
468
|
controller.style.visibility = '';
|
|
469
|
+
controller.showPopover?.();
|
|
467
470
|
return true;
|
|
468
471
|
}
|
|
469
472
|
|
|
@@ -282,10 +282,18 @@ class Figure {
|
|
|
282
282
|
const cover = dom.query.getParentElement(element, 'FIGURE', 2);
|
|
283
283
|
const inlineCover = dom.query.getParentElement(element, 'SPAN', 2);
|
|
284
284
|
const anyCover = cover || inlineCover;
|
|
285
|
-
|
|
285
|
+
let target = dom.query.getParentElement(element, (current) => current.parentElement === anyCover, 0) || element;
|
|
286
|
+
|
|
287
|
+
// When image is wrapped by anchor, target becomes <a> instead of <img>
|
|
288
|
+
if (dom.check.isAnchor(target)) {
|
|
289
|
+
const imgEl = target.querySelector(':scope > img');
|
|
290
|
+
if (imgEl) {
|
|
291
|
+
target = imgEl;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
286
294
|
|
|
287
295
|
return {
|
|
288
|
-
target,
|
|
296
|
+
target: /** @type {HTMLElement} */ (target),
|
|
289
297
|
container: dom.query.getParentElement(target, Figure.is, 3) || cover,
|
|
290
298
|
cover: cover,
|
|
291
299
|
inlineCover: dom.utils.hasClass(inlineCover, 'se-inline-component') ? /** @type {HTMLElement} */ (inlineCover) : null,
|
|
@@ -734,12 +742,23 @@ class Figure {
|
|
|
734
742
|
const { container, inlineCover, target } = Figure.GetContainer(targetNode);
|
|
735
743
|
const { w, h } = this.getSize(target);
|
|
736
744
|
|
|
745
|
+
// Check if target is wrapped by an anchor
|
|
746
|
+
const anchorEl = dom.check.isAnchor(target.parentNode) ? target.parentNode : null;
|
|
747
|
+
|
|
737
748
|
const newTarget = /** @type {HTMLElement} */ (target.cloneNode(false));
|
|
738
749
|
newTarget.style.width = '';
|
|
739
750
|
newTarget.style.height = '';
|
|
740
751
|
newTarget.removeAttribute('width');
|
|
741
752
|
newTarget.removeAttribute('height');
|
|
742
753
|
|
|
754
|
+
// Preserve anchor wrapper if exists
|
|
755
|
+
let elementToInsert = newTarget;
|
|
756
|
+
if (anchorEl) {
|
|
757
|
+
const newAnchor = /** @type {HTMLElement} */ (anchorEl.cloneNode(false));
|
|
758
|
+
newAnchor.appendChild(newTarget);
|
|
759
|
+
elementToInsert = newAnchor;
|
|
760
|
+
}
|
|
761
|
+
|
|
743
762
|
switch (formatStyle) {
|
|
744
763
|
case 'inline': {
|
|
745
764
|
if (inlineCover) break;
|
|
@@ -748,7 +767,7 @@ class Figure {
|
|
|
748
767
|
const next = container.nextElementSibling;
|
|
749
768
|
const parent = container.parentElement;
|
|
750
769
|
|
|
751
|
-
const figure = Figure.CreateInlineContainer(
|
|
770
|
+
const figure = Figure.CreateInlineContainer(elementToInsert);
|
|
752
771
|
dom.utils.addClass(
|
|
753
772
|
figure.container,
|
|
754
773
|
container.className
|
|
@@ -777,7 +796,7 @@ class Figure {
|
|
|
777
796
|
dom.utils.removeItem(s.previousElementSibling);
|
|
778
797
|
}
|
|
779
798
|
|
|
780
|
-
const figure = Figure.CreateContainer(
|
|
799
|
+
const figure = Figure.CreateContainer(elementToInsert);
|
|
781
800
|
dom.utils.addClass(
|
|
782
801
|
figure.container,
|
|
783
802
|
container.className
|
|
@@ -162,6 +162,7 @@ class Modal {
|
|
|
162
162
|
|
|
163
163
|
dom.utils.addClass(this.#modalArea, 'se-backdrop-show');
|
|
164
164
|
dom.utils.addClass(this.form, 'se-modal-show');
|
|
165
|
+
this.#modalArea.showPopover?.();
|
|
165
166
|
|
|
166
167
|
if (this.#resizeBody) {
|
|
167
168
|
const offset = this.#saveOffset();
|
|
@@ -197,6 +198,7 @@ class Modal {
|
|
|
197
198
|
this.#bindClose &&= this.#$.eventManager.removeGlobalEvent(this.#bindClose);
|
|
198
199
|
|
|
199
200
|
// close
|
|
201
|
+
this.#modalArea.hidePopover?.();
|
|
200
202
|
dom.utils.removeClass(this.#modalArea, 'se-backdrop-show');
|
|
201
203
|
dom.utils.removeClass(this.form, 'se-modal-show');
|
|
202
204
|
|