suneditor 3.1.2 → 3.1.4
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/dom/html.js +7 -15
- package/src/core/logic/panel/menu.js +4 -0
- package/src/core/logic/shell/ui.js +13 -2
- package/src/core/schema/options.js +16 -16
- package/src/core/section/constructor.js +29 -22
- package/src/core/section/documentType.js +55 -29
- package/src/modules/contract/Browser.js +15 -11
- package/src/modules/contract/Controller.js +3 -0
- package/src/modules/contract/Figure.js +26 -4
- package/src/modules/contract/Modal.js +14 -1
- package/src/modules/ui/ModalAnchorEditor.js +8 -3
- package/src/plugins/browser/audioGallery.js +6 -0
- package/src/plugins/browser/fileBrowser.js +6 -0
- package/src/plugins/browser/fileGallery.js +6 -0
- package/src/plugins/browser/imageGallery.js +6 -0
- package/src/plugins/browser/videoGallery.js +6 -0
- package/src/plugins/dropdown/table/services/table.style.js +21 -12
- package/src/plugins/modal/embed.js +41 -1
- package/src/plugins/modal/image/index.js +2 -1
- package/types/core/schema/options.d.ts +29 -37
- package/types/core/section/documentType.d.ts +17 -1
- package/types/modules/contract/Browser.d.ts +7 -7
- package/types/modules/ui/ModalAnchorEditor.d.ts +6 -1
- package/types/plugins/browser/audioGallery.d.ts +16 -0
- package/types/plugins/browser/fileBrowser.d.ts +16 -0
- package/types/plugins/browser/fileGallery.d.ts +16 -0
- package/types/plugins/browser/imageGallery.d.ts +16 -0
- package/types/plugins/browser/videoGallery.d.ts +16 -0
- package/types/plugins/modal/embed.d.ts +34 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "suneditor",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.4",
|
|
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
|
}
|
|
@@ -77,18 +77,10 @@ class HTML {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
const stylesMap = new Map();
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
line: options.get('_lineStylesRegExp'),
|
|
83
|
-
};
|
|
84
|
-
this.#textStyleTags.forEach((v) => {
|
|
85
|
-
stylesObj[v] = options.get('_textStylesRegExp');
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
for (const key in stylesObj) {
|
|
89
|
-
stylesMap.set(new RegExp(`^(${key})$`), stylesObj[key]);
|
|
80
|
+
for (const key in splitTagStyles) {
|
|
81
|
+
stylesMap.set(new RegExp(`^(${key})$`), splitTagStyles[key]);
|
|
90
82
|
}
|
|
91
|
-
this.#cleanStyleTagKeyRegExp = new RegExp(`^(${Object.keys(
|
|
83
|
+
this.#cleanStyleTagKeyRegExp = new RegExp(`^(${Object.keys(splitTagStyles).join('|')})$`, 'i');
|
|
92
84
|
this.#cleanStyleRegExpMap = stylesMap;
|
|
93
85
|
|
|
94
86
|
// font size unit
|
|
@@ -1966,12 +1958,12 @@ class HTML {
|
|
|
1966
1958
|
v.push(sv[0]);
|
|
1967
1959
|
}
|
|
1968
1960
|
} else if (!v || !_RE_STYLE_EQ.test(v.toString())) {
|
|
1969
|
-
if (this.#
|
|
1961
|
+
if (this.#cleanStyleTagKeyRegExp.test(tagName)) {
|
|
1970
1962
|
v = this.#cleanStyle(m, v, tagName);
|
|
1971
1963
|
} else if (this.#$.format.isLine(tagName)) {
|
|
1972
|
-
v = this.#cleanStyle(m, v, 'line');
|
|
1973
|
-
} else if (this.#
|
|
1974
|
-
v = this.#cleanStyle(m, v,
|
|
1964
|
+
v = this.#cleanStyle(m, v, '@line');
|
|
1965
|
+
} else if (this.#textStyleTags.includes(tagName)) {
|
|
1966
|
+
v = this.#cleanStyle(m, v, '@text');
|
|
1975
1967
|
}
|
|
1976
1968
|
}
|
|
1977
1969
|
|
|
@@ -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
|
}
|
|
@@ -67,6 +67,8 @@ export const DEFAULTS = {
|
|
|
67
67
|
'vertical-align|visibility|' +
|
|
68
68
|
'white-space|word-break|word-wrap',
|
|
69
69
|
TAG_STYLES: {
|
|
70
|
+
'@text': 'font-family|font-size|color|background-color|width|height',
|
|
71
|
+
'@line': 'text-align|margin|margin-left|margin-right|line-height',
|
|
70
72
|
'table|th|td': 'border|border-[a-z]+|color|background-color|text-align|float|font-weight|text-decoration|font-style|vertical-align',
|
|
71
73
|
'table|td': 'width',
|
|
72
74
|
tr: 'height',
|
|
@@ -78,8 +80,6 @@ export const DEFAULTS = {
|
|
|
78
80
|
'img|video|iframe': 'transform|transform-origin|width|min-width|max-width|height|min-height|max-height|float|margin|margin-top',
|
|
79
81
|
hr: '',
|
|
80
82
|
},
|
|
81
|
-
SPAN_STYLES: 'font-family|font-size|color|background-color|width|height',
|
|
82
|
-
LINE_STYLES: 'text-align|margin|margin-left|margin-right|line-height',
|
|
83
83
|
|
|
84
84
|
RETAIN_STYLE_MODE: ['repeat', 'always', 'none'],
|
|
85
85
|
};
|
|
@@ -317,7 +317,7 @@ export const DEFAULTS = {
|
|
|
317
317
|
* - `classFilter`: Filters disallowed CSS class names (`allowedClassName`)
|
|
318
318
|
* - `textStyleTagFilter`: Filters text style tags (b, i, u, span, etc.)
|
|
319
319
|
* - `attrFilter`: Filters disallowed HTML attributes (`attributeWhitelist`/`attributeBlacklist`)
|
|
320
|
-
* - `styleFilter`: Filters disallowed inline styles (`
|
|
320
|
+
* - `styleFilter`: Filters disallowed inline styles (per-tag from `tagStyles`)
|
|
321
321
|
* ```js
|
|
322
322
|
* // disable only attribute and style filters
|
|
323
323
|
* {
|
|
@@ -363,7 +363,7 @@ export const DEFAULTS = {
|
|
|
363
363
|
* attributeWhitelist: {
|
|
364
364
|
* a: 'href|target',
|
|
365
365
|
* img: 'src|alt',
|
|
366
|
-
* '*': 'id|data
|
|
366
|
+
* '*': 'id|data-[^\s]+'
|
|
367
367
|
* }
|
|
368
368
|
* }
|
|
369
369
|
* ```
|
|
@@ -393,19 +393,23 @@ export const DEFAULTS = {
|
|
|
393
393
|
* ```js
|
|
394
394
|
* { allUsedStyles: 'color|background-color|text-shadow' }
|
|
395
395
|
* ```
|
|
396
|
-
* @property {Object<string, string>} [tagStyles={}] - Specifies allowed styles
|
|
396
|
+
* @property {Object<string, string>} [tagStyles={}] - Specifies allowed CSS styles per HTML tag.
|
|
397
|
+
* - Key is a tag name, multiple tags joined with `|`, or a category sentinel (`@text`, `@line`).
|
|
398
|
+
* - Value is a pipe-delimited list of allowed style names.
|
|
399
|
+
* - Resolution order when filtering an element: explicit tag entry → `@line` (for formatLine elements) → `@text` (for textStyleTags).
|
|
400
|
+
* - An explicit tag entry **replaces** the category default — include category styles in the value if you want both.
|
|
401
|
+
* - Merged with {@link DEFAULTS.TAG_STYLES}; user-supplied keys win.
|
|
397
402
|
* ```js
|
|
398
403
|
* {
|
|
399
404
|
* tagStyles: {
|
|
400
|
-
* '
|
|
401
|
-
*
|
|
405
|
+
* '@text': 'color|font-size|background-color', // default for span, b, i, em, ...
|
|
406
|
+
* '@line': 'text-align|margin|line-height', // default for p, h1-h6, div, li, ...
|
|
407
|
+
* 'table|td': 'border|color|background-color', // per-tag whitelist
|
|
408
|
+
* div: 'color', // explicit override; ignores `@line` default
|
|
409
|
+
* hr: 'border-top',
|
|
402
410
|
* }
|
|
403
411
|
* }
|
|
404
412
|
* ```
|
|
405
|
-
* @property {string} [spanStyles=CONSTANTS.SPAN_STYLES] - Specifies allowed styles for the `span` tag.
|
|
406
|
-
* - The default follows {@link DEFAULTS.SPAN_STYLES}
|
|
407
|
-
* @property {string} [lineStyles=CONSTANTS.LINE_STYLES] - Specifies allowed styles for the `line` element (p..).
|
|
408
|
-
* - The default follows {@link DEFAULTS.LINE_STYLES}
|
|
409
413
|
* @property {Array<string>} [fontSizeUnits=CONSTANTS.SIZE_UNITS] - Allowed font size units.
|
|
410
414
|
* - The default follows {@link DEFAULTS.SIZE_UNITS}
|
|
411
415
|
* @property {"repeat"|"always"|"none"} [retainStyleMode="repeat"] - Determines how inline elements (e.g. `<span>`, `<strong>`) are handled when deleting text.
|
|
@@ -625,8 +629,6 @@ export const DEFAULTS = {
|
|
|
625
629
|
* @property {string[]} [_reverseCommandArray] - Internal key shortcut matcher for reverse commands.
|
|
626
630
|
* @property {string} [_subMode] - Sub toolbar mode (e.g., `balloon`).
|
|
627
631
|
* @property {string[]} [_textStyleTags] - Tag names used for text styling, plus span/li.
|
|
628
|
-
* @property {RegExp} [_textStylesRegExp] - Regex to match inline styles (e.g., fontSize, color).
|
|
629
|
-
* @property {RegExp} [_lineStylesRegExp] - Regex to match line styles (e.g., text-align, padding).
|
|
630
632
|
* @property {Object<string, string>} [_defaultStyleTagMap] - Mapping HTML tag => standard tag.
|
|
631
633
|
* @property {Object<string, string>} [_styleCommandMap] - Mapping HTML tag => command (e.g., bold, underline).
|
|
632
634
|
* @property {Object<string, string>} [_defaultTagCommand] - Mapping command => preferred tag.
|
|
@@ -723,8 +725,6 @@ export const OPTION_FIXED_FLAG = {
|
|
|
723
725
|
convertTextTags: 'fixed',
|
|
724
726
|
__tagStyles: 'fixed',
|
|
725
727
|
tagStyles: 'fixed',
|
|
726
|
-
spanStyles: 'fixed',
|
|
727
|
-
lineStyles: 'fixed',
|
|
728
728
|
textDirection: true,
|
|
729
729
|
reverseButtons: 'fixed',
|
|
730
730
|
historyStackDelayTime: true,
|
|
@@ -788,7 +788,7 @@ export const OPTION_FIXED_FLAG = {
|
|
|
788
788
|
* @property {boolean} classFilter - Filters disallowed CSS class names (`allowedClassName`)
|
|
789
789
|
* @property {boolean} textStyleTagFilter - Filters text style tags (b, i, u, span, etc.)
|
|
790
790
|
* @property {boolean} attrFilter - Filters disallowed HTML attributes (`attributeWhitelist`/`attributeBlacklist`)
|
|
791
|
-
* @property {boolean} styleFilter - Filters disallowed inline styles (`
|
|
791
|
+
* @property {boolean} styleFilter - Filters disallowed inline styles (per-tag from `tagStyles`)
|
|
792
792
|
*/
|
|
793
793
|
|
|
794
794
|
/**
|
|
@@ -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);
|
|
@@ -500,8 +516,6 @@ export function InitOptions(options, editorTargets, plugins) {
|
|
|
500
516
|
return _default;
|
|
501
517
|
}, {}),
|
|
502
518
|
);
|
|
503
|
-
o.set('_textStylesRegExp', new RegExp(`\\s*[^-a-zA-Z](${DEFAULTS.SPAN_STYLES}${options.spanStyles ? '|' + options.spanStyles : ''})\\s*:[^;]+(?!;)*`, 'gi'));
|
|
504
|
-
o.set('_lineStylesRegExp', new RegExp(`\\s*[^-a-zA-Z](${DEFAULTS.LINE_STYLES}${options.lineStyles ? '|' + options.lineStyles : ''})\\s*:[^;]+(?!;)*`, 'gi'));
|
|
505
519
|
o.set('_defaultStyleTagMap', {
|
|
506
520
|
strong: textTags.bold,
|
|
507
521
|
b: textTags.bold,
|
|
@@ -744,21 +758,13 @@ export function InitOptions(options, editorTargets, plugins) {
|
|
|
744
758
|
|
|
745
759
|
/** Create all used styles */
|
|
746
760
|
const allUsedStyles = new Set(DEFAULTS.CONTENT_STYLES.split('|'));
|
|
747
|
-
const _ss = options.spanStyles?.split('|') || [];
|
|
748
761
|
const _ls = o.get('__listCommonStyle');
|
|
749
|
-
const _dts = DEFAULTS.SPAN_STYLES.split('|');
|
|
750
|
-
for (let i = 0, len = _dts.length; i < len; i++) {
|
|
751
|
-
allUsedStyles.add(_dts[i]);
|
|
752
|
-
}
|
|
753
762
|
for (const _ts of Object.values(o.get('tagStyles'))) {
|
|
754
763
|
const _tss = _ts.split('|');
|
|
755
764
|
for (let i = 0, len = _tss.length; i < len; i++) {
|
|
756
765
|
allUsedStyles.add(_tss[i]);
|
|
757
766
|
}
|
|
758
767
|
}
|
|
759
|
-
for (let i = 0, len = _ss.length; i < len; i++) {
|
|
760
|
-
allUsedStyles.add(_ss[i]);
|
|
761
|
-
}
|
|
762
768
|
for (let i = 0, len = _ls.length; i < len; i++) {
|
|
763
769
|
allUsedStyles.add(_ls[i]);
|
|
764
770
|
}
|
|
@@ -934,9 +940,10 @@ function InitFrameOptions(o, origin) {
|
|
|
934
940
|
* @param {Map<string, *>} options - Options
|
|
935
941
|
* @param {HTMLElement} topDiv - Top div
|
|
936
942
|
* @param {SunEditor.FrameOptions} targetOptions - `editor.frameOptions`
|
|
943
|
+
* @param {string} formFieldPrefix - Prefix for generated form field ids
|
|
937
944
|
* @returns {{bottomBar: ReturnType<CreateStatusbar>, wysiwygFrame: HTMLElement, codeView: HTMLElement, markdownView: HTMLElement, placeholder: HTMLElement}}
|
|
938
945
|
*/
|
|
939
|
-
function _initTargetElements(key, options, topDiv, targetOptions) {
|
|
946
|
+
function _initTargetElements(key, options, topDiv, targetOptions, formFieldPrefix) {
|
|
940
947
|
const editorStyles = targetOptions.get('_defaultStyles');
|
|
941
948
|
/** top div */
|
|
942
949
|
topDiv.style.cssText = editorStyles.top;
|
|
@@ -990,10 +997,10 @@ function _initTargetElements(key, options, topDiv, targetOptions) {
|
|
|
990
997
|
}
|
|
991
998
|
|
|
992
999
|
// textarea for code view
|
|
993
|
-
const textarea = dom.utils.createElement('TEXTAREA', { class: 'se-wrapper-inner se-code-viewer', style: editorStyles.frame });
|
|
1000
|
+
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
1001
|
|
|
995
1002
|
// textarea for markdown view
|
|
996
|
-
const markdownTextarea = dom.utils.createElement('TEXTAREA', { class: 'se-wrapper-inner se-markdown-viewer', style: editorStyles.frame });
|
|
1003
|
+
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
1004
|
|
|
998
1005
|
const placeholder = dom.utils.createElement('SPAN', { class: 'se-placeholder' });
|
|
999
1006
|
if (targetOptions.get('placeholder')) {
|