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.
Files changed (35) hide show
  1. package/README.md +1 -1
  2. package/dist/suneditor.min.css +1 -1
  3. package/dist/suneditor.min.js +1 -1
  4. package/package.json +9 -6
  5. package/src/assets/suneditor.css +28 -2
  6. package/src/core/event/handlers/handler_ww_dragDrop.js +20 -0
  7. package/src/core/logic/dom/html.js +7 -15
  8. package/src/core/logic/panel/menu.js +4 -0
  9. package/src/core/logic/shell/ui.js +13 -2
  10. package/src/core/schema/options.js +16 -16
  11. package/src/core/section/constructor.js +29 -22
  12. package/src/core/section/documentType.js +55 -29
  13. package/src/modules/contract/Browser.js +15 -11
  14. package/src/modules/contract/Controller.js +3 -0
  15. package/src/modules/contract/Figure.js +26 -4
  16. package/src/modules/contract/Modal.js +14 -1
  17. package/src/modules/ui/ModalAnchorEditor.js +8 -3
  18. package/src/plugins/browser/audioGallery.js +6 -0
  19. package/src/plugins/browser/fileBrowser.js +6 -0
  20. package/src/plugins/browser/fileGallery.js +6 -0
  21. package/src/plugins/browser/imageGallery.js +6 -0
  22. package/src/plugins/browser/videoGallery.js +6 -0
  23. package/src/plugins/dropdown/table/services/table.style.js +21 -12
  24. package/src/plugins/modal/embed.js +41 -1
  25. package/src/plugins/modal/image/index.js +2 -1
  26. package/types/core/schema/options.d.ts +29 -37
  27. package/types/core/section/documentType.d.ts +17 -1
  28. package/types/modules/contract/Browser.d.ts +7 -7
  29. package/types/modules/ui/ModalAnchorEditor.d.ts +6 -1
  30. package/types/plugins/browser/audioGallery.d.ts +16 -0
  31. package/types/plugins/browser/fileBrowser.d.ts +16 -0
  32. package/types/plugins/browser/fileGallery.d.ts +16 -0
  33. package/types/plugins/browser/imageGallery.d.ts +16 -0
  34. package/types/plugins/browser/videoGallery.d.ts +16 -0
  35. 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.2",
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 \"src/**/*.js\" --fix",
61
+ "lint:fix-js": "npx eslint src/ --fix",
59
62
  "lint:fix-ts": "npx eslint types/ --fix",
60
- "lint:fix-all": "npx eslint \"src/**/*.js\" types/ --fix",
61
- "lint": "npx eslint \"src/**/*.js\" types/ && npm run lint:type && npm run check:arch",
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.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 >= 121",
137
+ "firefox >= 125",
135
138
  "safari >= 17.2",
136
139
  "opera >= 105",
137
140
  "samsung >= 23",
@@ -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: 1px;
4557
- background: var(--se-main-background-color);
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 stylesObj = {
81
- ...splitTagStyles,
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(stylesObj).join('|')})$`, 'i');
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.#textStyleTags.includes(tagName)) {
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.#cleanStyleTagKeyRegExp.test(tagName)) {
1974
- v = this.#cleanStyle(m, v, tagName);
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')).style.display = 'block';
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')).style.display = 'none';
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 (`spanStyles`/`lineStyles`/`allUsedStyles`)
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 for HTML tags. Key is tag name(s), value is pipe-delimited 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
- * 'table|td': 'border|color|background-color',
401
- * hr: 'border-top'
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 (`spanStyles`/`lineStyles`/`allUsedStyles`)
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
- editor_carrier_wrapper.appendChild(loadingBox.cloneNode(true));
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('TEXTAREA', { class: 'se-code-view-line', readonly: 'true' }, null);
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('TEXTAREA', { class: 'se-markdown-view-line', readonly: 'true' }, null);
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')) {