suneditor 3.1.3 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. package/dist/suneditor-contents.min.css +1 -1
  2. package/dist/suneditor.min.css +28 -1
  3. package/dist/suneditor.min.js +1 -1
  4. package/package.json +2 -1
  5. package/src/assets/design/color.css +12 -0
  6. package/src/assets/design/size.css +9 -2
  7. package/src/assets/icons/defaultIcons.js +96 -47
  8. package/src/assets/suneditor-contents.css +3 -2
  9. package/src/assets/suneditor.css +480 -31
  10. package/src/core/config/contextProvider.js +2 -1
  11. package/src/core/config/eventManager.js +41 -2
  12. package/src/core/config/optionProvider.js +23 -2
  13. package/src/core/editor.js +32 -14
  14. package/src/core/event/actions/index.js +76 -9
  15. package/src/core/event/effects/common.registry.js +2 -1
  16. package/src/core/event/effects/keydown.registry.js +169 -33
  17. package/src/core/event/effects/ruleHelpers.js +20 -6
  18. package/src/core/event/eventOrchestrator.js +136 -23
  19. package/src/core/event/handlers/handler_toolbar.js +4 -2
  20. package/src/core/event/handlers/handler_ww_dragDrop.js +10 -0
  21. package/src/core/event/handlers/handler_ww_input.js +9 -2
  22. package/src/core/event/handlers/handler_ww_key.js +86 -17
  23. package/src/core/event/handlers/handler_ww_mouse.js +45 -8
  24. package/src/core/event/ports.js +23 -5
  25. package/src/core/event/reducers/keydown.reducer.js +15 -2
  26. package/src/core/event/rules/keydown.rule.arrow.js +12 -2
  27. package/src/core/event/rules/keydown.rule.backspace.js +110 -15
  28. package/src/core/event/rules/keydown.rule.delete.js +62 -7
  29. package/src/core/event/rules/keydown.rule.enter.js +62 -31
  30. package/src/core/event/support/defaultLineManager.js +9 -2
  31. package/src/core/event/support/selectionState.js +13 -3
  32. package/src/core/kernel/coreKernel.js +1 -0
  33. package/src/core/logic/dom/char.js +13 -3
  34. package/src/core/logic/dom/format.js +171 -39
  35. package/src/core/logic/dom/html.js +357 -87
  36. package/src/core/logic/dom/inline.js +229 -34
  37. package/src/core/logic/dom/listFormat.js +111 -20
  38. package/src/core/logic/dom/nodeTransform.js +36 -11
  39. package/src/core/logic/dom/offset.js +116 -31
  40. package/src/core/logic/dom/selection.js +147 -29
  41. package/src/core/logic/panel/blockHandle.js +785 -0
  42. package/src/core/logic/panel/blockResolver.js +278 -0
  43. package/src/core/logic/panel/finder.js +16 -6
  44. package/src/core/logic/panel/menu.js +119 -18
  45. package/src/core/logic/panel/toolbar.js +75 -19
  46. package/src/core/logic/panel/viewer.js +76 -20
  47. package/src/core/logic/shell/_commandExecutor.js +44 -9
  48. package/src/core/logic/shell/commandDispatcher.js +46 -4
  49. package/src/core/logic/shell/component.js +102 -25
  50. package/src/core/logic/shell/focusManager.js +13 -3
  51. package/src/core/logic/shell/history.js +21 -6
  52. package/src/core/logic/shell/pluginManager.js +21 -13
  53. package/src/core/logic/shell/shortcuts.js +9 -1
  54. package/src/core/logic/shell/ui.js +139 -37
  55. package/src/core/schema/frameContext.js +34 -3
  56. package/src/core/schema/options.js +61 -19
  57. package/src/core/section/constructor.js +537 -103
  58. package/src/core/section/documentType.js +35 -6
  59. package/src/helper/converter.js +24 -7
  60. package/src/helper/dom/domCheck.js +25 -5
  61. package/src/helper/dom/domQuery.js +2 -1
  62. package/src/helper/dom/domUtils.js +17 -4
  63. package/src/helper/env.js +11 -2
  64. package/src/helper/keyCodeMap.js +6 -2
  65. package/src/helper/markdown.js +24 -5
  66. package/src/helper/msOffice.js +9 -2
  67. package/src/interfaces/plugins.js +1 -1
  68. package/src/langs/ckb.js +0 -1
  69. package/src/langs/cs.js +0 -1
  70. package/src/langs/da.js +0 -1
  71. package/src/langs/de.js +0 -1
  72. package/src/langs/en.js +0 -1
  73. package/src/langs/es.js +0 -1
  74. package/src/langs/fa.js +0 -1
  75. package/src/langs/fr.js +0 -1
  76. package/src/langs/he.js +0 -1
  77. package/src/langs/hu.js +0 -1
  78. package/src/langs/index.js +27 -1
  79. package/src/langs/it.js +0 -1
  80. package/src/langs/ja.js +0 -1
  81. package/src/langs/km.js +0 -1
  82. package/src/langs/ko.js +0 -1
  83. package/src/langs/lv.js +0 -1
  84. package/src/langs/nl.js +0 -1
  85. package/src/langs/pl.js +0 -1
  86. package/src/langs/pt_br.js +0 -1
  87. package/src/langs/ro.js +0 -1
  88. package/src/langs/ru.js +0 -1
  89. package/src/langs/se.js +0 -1
  90. package/src/langs/tr.js +0 -1
  91. package/src/langs/uk.js +0 -1
  92. package/src/langs/ur.js +0 -1
  93. package/src/langs/zh_cn.js +0 -1
  94. package/src/modules/contract/Browser.js +68 -23
  95. package/src/modules/contract/ColorPicker.js +12 -4
  96. package/src/modules/contract/Controller.js +37 -7
  97. package/src/modules/contract/Figure.js +159 -36
  98. package/src/modules/contract/HueSlider.js +27 -4
  99. package/src/modules/contract/Modal.js +62 -11
  100. package/src/modules/manager/FileManager.js +50 -8
  101. package/src/modules/ui/CommandMenu.js +597 -0
  102. package/src/modules/ui/ModalAnchorEditor.js +41 -9
  103. package/src/modules/ui/SelectMenu.js +481 -36
  104. package/src/modules/ui/index.js +1 -0
  105. package/src/plugins/browser/audioGallery.js +8 -1
  106. package/src/plugins/browser/fileBrowser.js +15 -2
  107. package/src/plugins/browser/fileGallery.js +8 -1
  108. package/src/plugins/browser/imageGallery.js +24 -3
  109. package/src/plugins/browser/videoGallery.js +19 -4
  110. package/src/plugins/command/blockquote.js +6 -1
  111. package/src/plugins/command/codeBlock.js +43 -5
  112. package/src/plugins/command/exportPDF.js +20 -4
  113. package/src/plugins/command/fileUpload.js +46 -11
  114. package/src/plugins/command/list_bulleted.js +6 -1
  115. package/src/plugins/command/list_numbered.js +6 -1
  116. package/src/plugins/dropdown/align.js +21 -33
  117. package/src/plugins/dropdown/backgroundColor.js +10 -2
  118. package/src/plugins/dropdown/blockStyle.js +17 -22
  119. package/src/plugins/dropdown/font.js +34 -34
  120. package/src/plugins/dropdown/hr.js +15 -43
  121. package/src/plugins/dropdown/layout.js +10 -27
  122. package/src/plugins/dropdown/lineHeight.js +10 -33
  123. package/src/plugins/dropdown/list.js +19 -25
  124. package/src/plugins/dropdown/paragraphStyle.js +16 -24
  125. package/src/plugins/dropdown/table/index.js +72 -17
  126. package/src/plugins/dropdown/table/render/table.html.js +3 -1
  127. package/src/plugins/dropdown/table/services/table.cell.js +33 -7
  128. package/src/plugins/dropdown/table/services/table.clipboard.js +5 -1
  129. package/src/plugins/dropdown/table/services/table.grid.js +40 -9
  130. package/src/plugins/dropdown/table/services/table.resize.js +55 -11
  131. package/src/plugins/dropdown/table/services/table.selection.js +27 -7
  132. package/src/plugins/dropdown/table/services/table.style.js +120 -20
  133. package/src/plugins/dropdown/template.js +13 -29
  134. package/src/plugins/dropdown/textStyle.js +22 -35
  135. package/src/plugins/field/autocomplete.js +8 -4
  136. package/src/plugins/field/slashCommand.js +297 -0
  137. package/src/plugins/index.js +3 -0
  138. package/src/plugins/input/fontSize.js +37 -8
  139. package/src/plugins/input/pageNavigator.js +7 -1
  140. package/src/plugins/modal/audio.js +71 -17
  141. package/src/plugins/modal/drawing.js +41 -11
  142. package/src/plugins/modal/embed.js +132 -22
  143. package/src/plugins/modal/image/index.js +115 -28
  144. package/src/plugins/modal/image/services/image.size.js +9 -2
  145. package/src/plugins/modal/image/services/image.upload.js +38 -4
  146. package/src/plugins/modal/link.js +9 -2
  147. package/src/plugins/modal/math.js +10 -2
  148. package/src/plugins/modal/video/index.js +112 -26
  149. package/src/plugins/modal/video/render/video.html.js +4 -1
  150. package/src/plugins/modal/video/services/video.size.js +15 -4
  151. package/src/plugins/modal/video/services/video.upload.js +10 -2
  152. package/src/plugins/popup/anchor.js +14 -2
  153. package/src/suneditor.js +8 -2
  154. package/src/themes/cobalt.css +12 -0
  155. package/src/themes/cream.css +12 -0
  156. package/src/themes/dark.css +12 -0
  157. package/src/themes/midnight.css +12 -0
  158. package/src/typedef.js +32 -21
  159. package/types/assets/icons/defaultIcons.d.ts +1 -0
  160. package/types/core/config/contextProvider.d.ts +7 -1
  161. package/types/core/config/eventManager.d.ts +37 -4
  162. package/types/core/config/optionProvider.d.ts +5 -1
  163. package/types/core/event/actions/index.d.ts +44 -6
  164. package/types/core/event/effects/keydown.registry.d.ts +37 -7
  165. package/types/core/event/effects/ruleHelpers.d.ts +6 -1
  166. package/types/core/event/eventOrchestrator.d.ts +6 -1
  167. package/types/core/event/handlers/handler_ww_clipboard.d.ts +15 -3
  168. package/types/core/event/handlers/handler_ww_dragDrop.d.ts +14 -2
  169. package/types/core/event/handlers/handler_ww_input.d.ts +10 -2
  170. package/types/core/event/handlers/handler_ww_key.d.ts +10 -2
  171. package/types/core/event/handlers/handler_ww_mouse.d.ts +25 -5
  172. package/types/core/event/ports.d.ts +7 -2
  173. package/types/core/event/rules/keydown.rule.backspace.d.ts +6 -1
  174. package/types/core/kernel/store.d.ts +4 -1
  175. package/types/core/logic/dom/format.d.ts +32 -14
  176. package/types/core/logic/dom/html.d.ts +11 -3
  177. package/types/core/logic/dom/nodeTransform.d.ts +6 -6
  178. package/types/core/logic/panel/blockHandle.d.ts +64 -0
  179. package/types/core/logic/panel/blockResolver.d.ts +50 -0
  180. package/types/core/logic/panel/menu.d.ts +72 -3
  181. package/types/core/logic/shell/commandDispatcher.d.ts +8 -0
  182. package/types/core/logic/shell/component.d.ts +5 -3
  183. package/types/core/logic/shell/shortcuts.d.ts +10 -1
  184. package/types/core/logic/shell/ui.d.ts +7 -1
  185. package/types/core/schema/context.d.ts +7 -1
  186. package/types/core/schema/frameContext.d.ts +36 -4
  187. package/types/core/schema/options.d.ts +110 -37
  188. package/types/core/section/constructor.d.ts +38 -1
  189. package/types/events.d.ts +208 -32
  190. package/types/helper/converter.d.ts +4 -2
  191. package/types/helper/dom/domCheck.d.ts +12 -2
  192. package/types/helper/dom/domQuery.d.ts +35 -7
  193. package/types/helper/dom/domUtils.d.ts +4 -1
  194. package/types/interfaces/plugins.d.ts +2 -2
  195. package/types/langs/_Lang.d.ts +0 -1
  196. package/types/modules/contract/Browser.d.ts +7 -7
  197. package/types/modules/contract/ColorPicker.d.ts +2 -2
  198. package/types/modules/contract/Controller.d.ts +7 -0
  199. package/types/modules/contract/Figure.d.ts +31 -4
  200. package/types/modules/ui/CommandMenu.d.ts +262 -0
  201. package/types/modules/ui/ModalAnchorEditor.d.ts +6 -1
  202. package/types/modules/ui/SelectMenu.d.ts +56 -3
  203. package/types/modules/ui/index.d.ts +1 -0
  204. package/types/plugins/browser/audioGallery.d.ts +17 -1
  205. package/types/plugins/browser/fileBrowser.d.ts +17 -1
  206. package/types/plugins/browser/fileGallery.d.ts +17 -1
  207. package/types/plugins/browser/imageGallery.d.ts +17 -1
  208. package/types/plugins/browser/videoGallery.d.ts +17 -1
  209. package/types/plugins/dropdown/align.d.ts +1 -1
  210. package/types/plugins/dropdown/blockStyle.d.ts +3 -1
  211. package/types/plugins/dropdown/table/index.d.ts +4 -1
  212. package/types/plugins/dropdown/table/services/table.clipboard.d.ts +5 -1
  213. package/types/plugins/dropdown/table/services/table.grid.d.ts +10 -2
  214. package/types/plugins/field/autocomplete.d.ts +0 -1
  215. package/types/plugins/field/slashCommand.d.ts +165 -0
  216. package/types/plugins/index.d.ts +3 -0
  217. package/types/plugins/modal/embed.d.ts +34 -0
  218. package/types/plugins/modal/link.d.ts +4 -1
  219. package/types/typedef.d.ts +48 -23
@@ -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
@@ -97,7 +89,10 @@ class HTML {
97
89
  // extra tags
98
90
  const allowedExtraTags = options.get('_allowedExtraTag');
99
91
  const disallowedExtraTags = options.get('_disallowedExtraTag');
100
- this.#disallowedTagsRegExp = new RegExp(`<(${disallowedExtraTags})[^>]*>([\\s\\S]*?)<\\/\\1>|<(${disallowedExtraTags})[^>]*\\/?>`, 'gi');
92
+ this.#disallowedTagsRegExp = new RegExp(
93
+ `<(${disallowedExtraTags})[^>]*>([\\s\\S]*?)<\\/\\1>|<(${disallowedExtraTags})[^>]*\\/?>`,
94
+ 'gi',
95
+ );
101
96
  this.#disallowedTagNameRegExp = new RegExp(`^(${disallowedExtraTags})$`, 'i');
102
97
  this.#allowedTagNameRegExp = new RegExp(`^(${allowedExtraTags})$`, 'i');
103
98
 
@@ -112,18 +107,29 @@ class HTML {
112
107
  for (let i = 0; i < allowStyleNodes.length; i++) {
113
108
  disallowStyleNodes.splice(disallowStyleNodes.indexOf(allowStyleNodes[i].toLowerCase()), 1);
114
109
  }
115
- this.#disallowedStyleNodesRegExp = disallowStyleNodes.length === 0 ? null : new RegExp('(<\\/?)(' + disallowStyleNodes.join('|') + ')\\b\\s*([^>^<]+)?\\s*(?=>)', 'gi');
110
+ this.#disallowedStyleNodesRegExp =
111
+ disallowStyleNodes.length === 0
112
+ ? null
113
+ : new RegExp('(<\\/?)(' + disallowStyleNodes.join('|') + ')\\b\\s*([^>^<]+)?\\s*(?=>)', 'gi');
116
114
 
117
115
  // whitelist
118
116
  // tags
119
117
  const defaultAttr = options.get('__defaultAttributeWhitelist');
120
- this.#allowHTMLComment = options.get('_editorElementWhitelist').includes('//') || options.get('_editorElementWhitelist') === '*';
118
+ this.#allowHTMLComment =
119
+ options.get('_editorElementWhitelist').includes('//') || options.get('_editorElementWhitelist') === '*';
121
120
  // html check
122
- this.#htmlCheckWhitelistRegExp = new RegExp('^(' + GetRegList(options.get('_editorElementWhitelist').replace('|//', ''), '') + ')$', 'i');
121
+ this.#htmlCheckWhitelistRegExp = new RegExp(
122
+ '^(' + GetRegList(options.get('_editorElementWhitelist').replace('|//', ''), '') + ')$',
123
+ 'i',
124
+ );
123
125
  this.#htmlCheckBlacklistRegExp = new RegExp('^(' + (options.get('elementBlacklist') || '^') + ')$', 'i');
124
126
  // elements
125
- this.#elementWhitelistRegExp = converter.createElementWhitelist(GetRegList(options.get('_editorElementWhitelist').replace('|//', '|<!--|-->'), ''));
126
- this.#elementBlacklistRegExp = converter.createElementBlacklist(options.get('elementBlacklist').replace('|//', '|<!--|-->'));
127
+ this.#elementWhitelistRegExp = converter.createElementWhitelist(
128
+ GetRegList(options.get('_editorElementWhitelist').replace('|//', '|<!--|-->'), ''),
129
+ );
130
+ this.#elementBlacklistRegExp = converter.createElementBlacklist(
131
+ options.get('elementBlacklist').replace('|//', '|<!--|-->'),
132
+ );
127
133
  // attributes
128
134
  const regEndStr = '\\s*=\\s*(")[^"]*\\1';
129
135
  const _wAttr = options.get('attributeWhitelist');
@@ -142,7 +148,16 @@ class HTML {
142
148
  }
143
149
  }
144
150
 
145
- this.#attributeWhitelistRegExp = new RegExp('\\s(?:' + (allAttr || defaultAttr) + '|' + REQUIRED_DATA_ATTRS + (options.get('v2Migration') ? V2_MIG_DATA_ATTRS : '') + ')' + regEndStr, 'ig');
151
+ this.#attributeWhitelistRegExp = new RegExp(
152
+ '\\s(?:' +
153
+ (allAttr || defaultAttr) +
154
+ '|' +
155
+ REQUIRED_DATA_ATTRS +
156
+ (options.get('v2Migration') ? V2_MIG_DATA_ATTRS : '') +
157
+ ')' +
158
+ regEndStr,
159
+ 'ig',
160
+ );
146
161
  this.#attributeWhitelist = tagsAttr;
147
162
 
148
163
  // blacklist
@@ -174,7 +189,7 @@ class HTML {
174
189
  * @param {Object} params - Filtering parameters.
175
190
  * @param {string} [params.tagWhitelist] - Allowed tags, specified as a string with tags separated by `'|'`. (e.g. `"div|p|span"`).
176
191
  * @param {string} [params.tagBlacklist] - Disallowed tags, specified as a string with tags separated by `'|'`. (e.g. `"script|iframe"`).
177
- * @param {(node: Node) => Node | string | null} [params.validate] - Function to validate and modify individual nodes.
192
+ * @param {(node: *) => Node | string | null} [params.validate] - Function to validate and modify individual nodes.
178
193
  * - Return `null` to remove the node.
179
194
  * - Return a `Node` to replace the current node.
180
195
  * - Return a `string` to replace the node's `outerHTML`.
@@ -252,14 +267,18 @@ class HTML {
252
267
  * });
253
268
  */
254
269
  clean(html, { forceFormat, whitelist, blacklist, _freeCodeViewMode } = {}) {
255
- const { tagFilter, formatFilter, classFilter, textStyleTagFilter, attrFilter, styleFilter } = this.#options.get('strictMode');
270
+ const { tagFilter, formatFilter, classFilter, textStyleTagFilter, attrFilter, styleFilter } =
271
+ this.#options.get('strictMode');
256
272
  let cleanData = '';
257
273
 
258
274
  html = this.compress(html);
259
275
 
260
276
  if (tagFilter) {
261
277
  html = html.replace(this.#disallowedTagsRegExp, '');
262
- html = this.#deleteDisallowedTags(html, this.#elementWhitelistRegExp, this.#elementBlacklistRegExp).replace(/<br\/?>$/i, '');
278
+ html = this.#deleteDisallowedTags(html, this.#elementWhitelistRegExp, this.#elementBlacklistRegExp).replace(
279
+ /<br\/?>$/i,
280
+ '',
281
+ );
263
282
  }
264
283
 
265
284
  if (this.#autoStyleify) {
@@ -277,7 +296,15 @@ class HTML {
277
296
 
278
297
  if (tagFilter) {
279
298
  try {
280
- this.#consistencyCheckOfHTML(domParser, this.#htmlCheckWhitelistRegExp, this.#htmlCheckBlacklistRegExp, tagFilter, formatFilter, classFilter, _freeCodeViewMode);
299
+ this.#consistencyCheckOfHTML(
300
+ domParser,
301
+ this.#htmlCheckWhitelistRegExp,
302
+ this.#htmlCheckBlacklistRegExp,
303
+ tagFilter,
304
+ formatFilter,
305
+ classFilter,
306
+ _freeCodeViewMode,
307
+ );
281
308
  } catch (error) {
282
309
  console.warn('[SUNEDITOR.html.clean.fail]', error.message);
283
310
  }
@@ -322,8 +349,16 @@ class HTML {
322
349
 
323
350
  // whitelist, blacklist
324
351
  if (tagFilter) {
325
- if (whitelist) cleanData = cleanData.replace(typeof whitelist === 'string' ? converter.createElementWhitelist(whitelist) : whitelist, '');
326
- if (blacklist) cleanData = cleanData.replace(typeof blacklist === 'string' ? converter.createElementBlacklist(blacklist) : blacklist, '');
352
+ if (whitelist)
353
+ cleanData = cleanData.replace(
354
+ typeof whitelist === 'string' ? converter.createElementWhitelist(whitelist) : whitelist,
355
+ '',
356
+ );
357
+ if (blacklist)
358
+ cleanData = cleanData.replace(
359
+ typeof blacklist === 'string' ? converter.createElementBlacklist(blacklist) : blacklist,
360
+ '',
361
+ );
327
362
  }
328
363
 
329
364
  if (textStyleTagFilter) {
@@ -353,7 +388,8 @@ class HTML {
353
388
  * editor.html.insert('<div class="custom">Content</div>', { skipCleaning: true });
354
389
  */
355
390
  insert(html, { selectInserted, skipCharCount, skipCleaning } = {}) {
356
- if (!this.#frameContext.get('wysiwyg').contains(this.#$.selection.get().focusNode)) this.#$.focusManager.focus();
391
+ if (!this.#frameContext.get('wysiwyg').contains(this.#$.selection.get().focusNode))
392
+ this.#$.focusManager.focus();
357
393
 
358
394
  this.remove();
359
395
  this.#$.focusManager.focus();
@@ -372,7 +408,8 @@ class HTML {
372
408
  const domTree = domParser.childNodes;
373
409
 
374
410
  if (!skipCharCount) {
375
- const type = this.#frameOptions.get('charCounter_type') === 'byte-html' ? 'outerHTML' : 'textContent';
411
+ const type =
412
+ this.#frameOptions.get('charCounter_type') === 'byte-html' ? 'outerHTML' : 'textContent';
376
413
  let checkHTML = '';
377
414
  for (let i = 0, len = domTree.length; i < len; i++) {
378
415
  checkHTML += domTree[i][type];
@@ -470,13 +507,18 @@ class HTML {
470
507
  let range = null;
471
508
 
472
509
  if (afterNode) {
473
- const afterNewLine = this.#$.format.isLine(afterNode) || this.#$.format.isBlock(afterNode) || this.#$.component.is(afterNode) ? this.#$.format.addLine(afterNode, null) : afterNode;
510
+ const afterNewLine =
511
+ this.#$.format.isLine(afterNode) || this.#$.format.isBlock(afterNode) || this.#$.component.is(afterNode)
512
+ ? this.#$.format.addLine(afterNode, null)
513
+ : afterNode;
474
514
  range = this.#$.selection.setRange(afterNewLine, 1, afterNewLine, 1);
475
515
  } else {
476
516
  range = this.#$.selection.getRange();
477
517
  }
478
518
 
479
- let line = dom.check.isListCell(range.commonAncestorContainer) ? range.commonAncestorContainer : this.#$.format.getLine(this.#$.selection.getNode(), null);
519
+ let line = dom.check.isListCell(range.commonAncestorContainer)
520
+ ? range.commonAncestorContainer
521
+ : this.#$.format.getLine(this.#$.selection.getNode(), null);
480
522
  let insertListCell = dom.check.isListCell(line) && (dom.check.isListCell(oNode) || dom.check.isList(oNode));
481
523
 
482
524
  let parentNode,
@@ -484,7 +526,8 @@ class HTML {
484
526
  tempAfterNode,
485
527
  tempParentNode = null;
486
528
  const freeFormat = this.#$.format.isBrLine(line);
487
- const isFormats = this.#$.format.isLine(oNode) || this.#$.format.isBlock(oNode) || this.#$.component.isBasic(oNode);
529
+ const isFormats =
530
+ this.#$.format.isLine(oNode) || this.#$.format.isBlock(oNode) || this.#$.component.isBasic(oNode);
488
531
 
489
532
  if (insertListCell) {
490
533
  tempAfterNode = afterNode || dom.check.isList(oNode) ? line.lastChild : line.nextElementSibling;
@@ -519,7 +562,11 @@ class HTML {
519
562
  const depthFormat = dom.query.getParentElement(container, (current) => {
520
563
  return this.#$.format.isBlock(current) || dom.check.isListCell(current);
521
564
  });
522
- afterNode = this.#$.nodeTransform.split(container, r.offset, !depthFormat ? 0 : dom.query.getNodeDepth(depthFormat) + 1);
565
+ afterNode = this.#$.nodeTransform.split(
566
+ container,
567
+ r.offset,
568
+ !depthFormat ? 0 : dom.query.getNodeDepth(depthFormat) + 1,
569
+ );
523
570
  if (!afterNode) {
524
571
  if (!dom.check.isListCell(line)) {
525
572
  tempAfterNode = afterNode = line;
@@ -530,7 +577,11 @@ class HTML {
530
577
  let newCell = null;
531
578
  if (!isEdge) {
532
579
  newCell = line.cloneNode(false);
533
- newCell.appendChild(afterNode.textContent.trim() ? afterNode : dom.utils.createTextNode(unicode.zeroWidthSpace));
580
+ newCell.appendChild(
581
+ afterNode.textContent.trim()
582
+ ? afterNode
583
+ : dom.utils.createTextNode(unicode.zeroWidthSpace),
584
+ );
534
585
  }
535
586
  if (subList) {
536
587
  if (!newCell) {
@@ -550,13 +601,22 @@ class HTML {
550
601
  }
551
602
  }
552
603
 
553
- range = !afterNode && !isFormats ? this.#$.selection.getRangeAndAddLine(this.#$.selection.getRange(), null) : this.#$.selection.getRange();
604
+ range =
605
+ !afterNode && !isFormats
606
+ ? this.#$.selection.getRangeAndAddLine(this.#$.selection.getRange(), null)
607
+ : this.#$.selection.getRange();
554
608
  const commonCon = range.commonAncestorContainer;
555
609
  const startOff = range.startOffset;
556
610
  const endOff = range.endOffset;
557
611
  const formatRange = range.startContainer === commonCon && this.#$.format.isLine(commonCon);
558
- const startCon = formatRange ? commonCon.childNodes[startOff] || commonCon.childNodes[0] || range.startContainer : range.startContainer;
559
- const endCon = formatRange ? commonCon.childNodes[endOff] || commonCon.childNodes[commonCon.childNodes.length - 1] || range.endContainer : range.endContainer;
612
+ const startCon = formatRange
613
+ ? commonCon.childNodes[startOff] || commonCon.childNodes[0] || range.startContainer
614
+ : range.startContainer;
615
+ const endCon = formatRange
616
+ ? commonCon.childNodes[endOff] ||
617
+ commonCon.childNodes[commonCon.childNodes.length - 1] ||
618
+ range.endContainer
619
+ : range.endContainer;
560
620
 
561
621
  if (!insertListCell) {
562
622
  if (!afterNode) {
@@ -568,18 +628,25 @@ class HTML {
568
628
  /** No Select range node */
569
629
  if (range.collapsed) {
570
630
  if (commonCon.nodeType === 3) {
571
- if (commonCon.textContent.length > endOff) afterNode = /** @type {Text} */ (commonCon).splitText(endOff);
631
+ if (commonCon.textContent.length > endOff)
632
+ afterNode = /** @type {Text} */ (commonCon).splitText(endOff);
572
633
  else afterNode = commonCon.nextSibling;
573
634
  } else {
574
635
  if (!dom.check.isBreak(parentNode)) {
575
636
  const c = parentNode.childNodes[startOff];
576
- const focusNode = c?.nodeType === 3 && dom.check.isZeroWidth(c) && dom.check.isBreak(c.nextSibling) ? c.nextSibling : c;
637
+ const focusNode =
638
+ c?.nodeType === 3 && dom.check.isZeroWidth(c) && dom.check.isBreak(c.nextSibling)
639
+ ? c.nextSibling
640
+ : c;
577
641
  if (focusNode) {
578
642
  if (!focusNode.nextSibling && dom.check.isBreak(focusNode)) {
579
643
  parentNode.removeChild(focusNode);
580
644
  afterNode = null;
581
645
  } else {
582
- afterNode = dom.check.isBreak(focusNode) && !dom.check.isBreak(oNode) ? focusNode : focusNode.nextSibling;
646
+ afterNode =
647
+ dom.check.isBreak(focusNode) && !dom.check.isBreak(oNode)
648
+ ? focusNode
649
+ : focusNode.nextSibling;
583
650
  }
584
651
  } else {
585
652
  afterNode = null;
@@ -598,7 +665,8 @@ class HTML {
598
665
  else afterNode = /** @type {Text} */ (endCon).splitText(endOff);
599
666
 
600
667
  let removeNode = startCon;
601
- if (!dom.check.isEdgePoint(startCon, startOff)) removeNode = /** @type {Text} */ (startCon).splitText(startOff);
668
+ if (!dom.check.isEdgePoint(startCon, startOff))
669
+ removeNode = /** @type {Text} */ (startCon).splitText(startOff);
602
670
 
603
671
  parentNode.removeChild(removeNode);
604
672
  if (parentNode.childNodes.length === 0 && isFormats) {
@@ -613,7 +681,12 @@ class HTML {
613
681
  if (this.#$.format.isLine(container)) {
614
682
  container.innerHTML = '<br>';
615
683
  } else if (this.#$.format.isBlock(container)) {
616
- container.innerHTML = '<' + this.#options.get('defaultLine') + '><br></' + this.#options.get('defaultLine') + '>';
684
+ container.innerHTML =
685
+ '<' +
686
+ this.#options.get('defaultLine') +
687
+ '><br></' +
688
+ this.#options.get('defaultLine') +
689
+ '>';
617
690
  }
618
691
  }
619
692
 
@@ -634,10 +707,16 @@ class HTML {
634
707
  afterNode = null;
635
708
  }
636
709
  } else if (dom.check.isWysiwygFrame(container) && !this.#$.format.isLine(oNode)) {
637
- parentNode = container.appendChild(dom.utils.createElement(this.#options.get('defaultLine')));
710
+ parentNode = container.appendChild(
711
+ dom.utils.createElement(this.#options.get('defaultLine')),
712
+ );
638
713
  afterNode = null;
639
714
  } else {
640
- afterNode = isFormats ? endCon : container === prevContainer ? container.nextSibling : container;
715
+ afterNode = isFormats
716
+ ? endCon
717
+ : container === prevContainer
718
+ ? container.nextSibling
719
+ : container;
641
720
  parentNode = !afterNode || !afterNode.parentNode ? commonCon : afterNode.parentNode;
642
721
  }
643
722
 
@@ -663,13 +742,22 @@ class HTML {
663
742
  afterNode = null;
664
743
  }
665
744
 
666
- if (this.#$.format.isLine(oNode) || this.#$.format.isBlock(oNode) || (!dom.check.isListCell(parentNode) && this.#$.component.isBasic(oNode))) {
745
+ if (
746
+ this.#$.format.isLine(oNode) ||
747
+ this.#$.format.isBlock(oNode) ||
748
+ (!dom.check.isListCell(parentNode) && this.#$.component.isBasic(oNode))
749
+ ) {
667
750
  const oldParent = parentNode;
668
751
  if (dom.check.isListCell(afterNode)) {
669
752
  parentNode = afterNode.previousElementSibling || afterNode;
670
753
  } else if (!originAfter && !afterNode) {
671
754
  const r = this.remove();
672
- const container = r.container.nodeType === 3 ? (dom.check.isListCell(this.#$.format.getLine(r.container, null)) ? r.container : this.#$.format.getLine(r.container, null) || r.container.parentNode) : r.container;
755
+ const container =
756
+ r.container.nodeType === 3
757
+ ? dom.check.isListCell(this.#$.format.getLine(r.container, null))
758
+ ? r.container
759
+ : this.#$.format.getLine(r.container, null) || r.container.parentNode
760
+ : r.container;
673
761
  const rangeCon = dom.check.isWysiwygFrame(container) || this.#$.format.isBlock(container);
674
762
  parentNode = rangeCon ? container : container.parentNode;
675
763
  afterNode = rangeCon ? null : container.nextSibling;
@@ -678,7 +766,13 @@ class HTML {
678
766
  if (oldParent.childNodes.length === 0 && parentNode !== oldParent) dom.utils.removeItem(oldParent);
679
767
  }
680
768
 
681
- if (isFormats && !freeFormat && !this.#$.format.isBlock(parentNode) && !dom.check.isListCell(parentNode) && !dom.check.isWysiwygFrame(parentNode)) {
769
+ if (
770
+ isFormats &&
771
+ !freeFormat &&
772
+ !this.#$.format.isBlock(parentNode) &&
773
+ !dom.check.isListCell(parentNode) &&
774
+ !dom.check.isWysiwygFrame(parentNode)
775
+ ) {
682
776
  afterNode = /** @type {HTMLElement} */ (parentNode).nextElementSibling;
683
777
  parentNode = parentNode.parentNode;
684
778
  }
@@ -770,7 +864,11 @@ class HTML {
770
864
  }
771
865
  }
772
866
 
773
- if (freeFormat && !dom.check.isList(oNode) && (this.#$.format.isLine(oNode) || this.#$.format.isBlock(oNode))) {
867
+ if (
868
+ freeFormat &&
869
+ !dom.check.isList(oNode) &&
870
+ (this.#$.format.isLine(oNode) || this.#$.format.isBlock(oNode))
871
+ ) {
774
872
  oNode = this.#setIntoFreeFormat(oNode);
775
873
  }
776
874
 
@@ -779,7 +877,11 @@ class HTML {
779
877
  if (oNode.nodeType === 3) {
780
878
  offset = oNode.textContent.length;
781
879
  this.#$.selection.setRange(oNode, offset, oNode, offset);
782
- } else if (!dom.check.isBreak(oNode) && !dom.check.isListCell(oNode) && this.#$.format.isLine(parentNode)) {
880
+ } else if (
881
+ !dom.check.isBreak(oNode) &&
882
+ !dom.check.isListCell(oNode) &&
883
+ this.#$.format.isLine(parentNode)
884
+ ) {
783
885
  let zeroWidth = null;
784
886
  if (!oNode.previousSibling || dom.check.isBreak(oNode.previousSibling)) {
785
887
  zeroWidth = dom.utils.createTextNode(unicode.zeroWidthSpace);
@@ -839,7 +941,12 @@ class HTML {
839
941
  let endCon = range.endContainer;
840
942
  let startOff = range.startOffset;
841
943
  let endOff = range.endOffset;
842
- const commonCon = /** @type {HTMLElement} */ (range.commonAncestorContainer.nodeType === 3 && range.commonAncestorContainer.parentNode === startCon.parentNode ? startCon.parentNode : range.commonAncestorContainer);
944
+ const commonCon = /** @type {HTMLElement} */ (
945
+ range.commonAncestorContainer.nodeType === 3 &&
946
+ range.commonAncestorContainer.parentNode === startCon.parentNode
947
+ ? startCon.parentNode
948
+ : range.commonAncestorContainer
949
+ );
843
950
 
844
951
  if (dom.check.isWysiwygFrame(startCon) && dom.check.isWysiwygFrame(endCon)) {
845
952
  this.set('');
@@ -860,7 +967,8 @@ class HTML {
860
967
  const next = compContainer.nextSibling || compContainer.previousSibling;
861
968
  const nextOffset = next === compContainer.previousSibling ? next?.textContent?.length || 1 : 0;
862
969
  const parentNext = parent.nextElementSibling || parent.previousElementSibling;
863
- const parentNextOffset = parentNext === parent.previousElementSibling ? parentNext?.textContent?.length || 1 : 0;
970
+ const parentNextOffset =
971
+ parentNext === parent.previousElementSibling ? parentNext?.textContent?.length || 1 : 0;
864
972
 
865
973
  dom.utils.removeItem(compContainer);
866
974
 
@@ -887,7 +995,10 @@ class HTML {
887
995
  };
888
996
  }
889
997
  } else {
890
- if ((commonCon.nodeType === 1 && startOff === 0 && endOff === 1) || (commonCon.nodeType === 3 && startOff === 0 && endOff === commonCon.textContent.length)) {
998
+ if (
999
+ (commonCon.nodeType === 1 && startOff === 0 && endOff === 1) ||
1000
+ (commonCon.nodeType === 3 && startOff === 0 && endOff === commonCon.textContent.length)
1001
+ ) {
891
1002
  const nextEl = dom.query.getNextDeepestNode(commonCon, this.#frameContext.get('wysiwyg'));
892
1003
  const prevEl = dom.query.getPreviousDeepestNode(commonCon, this.#frameContext.get('wysiwyg'));
893
1004
  const line = this.#$.format.getLine(commonCon);
@@ -946,7 +1057,11 @@ class HTML {
946
1057
 
947
1058
  if (childNodes.length > 0 && startIndex > -1 && endIndex > -1) {
948
1059
  for (let i = startIndex + 1, startNode = startCon; i >= 0; i--) {
949
- if (childNodes[i] === startNode.parentNode && childNodes[i].firstChild === startNode && startOff === 0) {
1060
+ if (
1061
+ childNodes[i] === startNode.parentNode &&
1062
+ childNodes[i].firstChild === startNode &&
1063
+ startOff === 0
1064
+ ) {
950
1065
  startIndex = i;
951
1066
  startNode = startNode.parentNode;
952
1067
  }
@@ -961,7 +1076,13 @@ class HTML {
961
1076
  }
962
1077
  } else {
963
1078
  if (childNodes.length === 0) {
964
- if (this.#$.format.isLine(commonCon) || this.#$.format.isBlock(commonCon) || dom.check.isWysiwygFrame(commonCon) || dom.check.isBreak(commonCon) || dom.check.isMedia(commonCon)) {
1079
+ if (
1080
+ this.#$.format.isLine(commonCon) ||
1081
+ this.#$.format.isBlock(commonCon) ||
1082
+ dom.check.isWysiwygFrame(commonCon) ||
1083
+ dom.check.isBreak(commonCon) ||
1084
+ dom.check.isMedia(commonCon)
1085
+ ) {
965
1086
  return {
966
1087
  container: commonCon,
967
1088
  offset: 0,
@@ -1010,7 +1131,9 @@ class HTML {
1010
1131
  const sc = /** @type {Text} */ (startCon);
1011
1132
  const ec = /** @type {Text} */ (endCon);
1012
1133
  if (item === endCon) {
1013
- beforeNode = dom.utils.createTextNode(sc.substringData(0, startOff) + ec.substringData(endOff, ec.length - endOff));
1134
+ beforeNode = dom.utils.createTextNode(
1135
+ sc.substringData(0, startOff) + ec.substringData(endOff, ec.length - endOff),
1136
+ );
1014
1137
  offset = startOff;
1015
1138
  } else {
1016
1139
  beforeNode = dom.utils.createTextNode(sc.substringData(0, startOff));
@@ -1053,7 +1176,12 @@ class HTML {
1053
1176
  container = endUl.previousSibling;
1054
1177
  offset = container.textContent.length;
1055
1178
  } else {
1056
- container = endCon && endCon.parentNode ? endCon : startCon && startCon.parentNode ? startCon : range.endContainer || range.startContainer;
1179
+ container =
1180
+ endCon && endCon.parentNode
1181
+ ? endCon
1182
+ : startCon && startCon.parentNode
1183
+ ? startCon
1184
+ : range.endContainer || range.startContainer;
1057
1185
  if (isStartEdge || isEndEdge) {
1058
1186
  if (isEndEdge) {
1059
1187
  if (container.nodeType === 1 && container.childNodes.length === 0) {
@@ -1083,7 +1211,10 @@ class HTML {
1083
1211
  if (rc) container = rc.sc || rc.ec || this.#frameContext.get('wysiwyg');
1084
1212
  }
1085
1213
 
1086
- if (!container || (container.nodeType === 1 && !this.#$.format.isLine(container) && !dom.check.isBreak(container))) {
1214
+ if (
1215
+ !container ||
1216
+ (container.nodeType === 1 && !this.#$.format.isLine(container) && !dom.check.isBreak(container))
1217
+ ) {
1087
1218
  container = nextFocusNodes?.sc || nextFocusNodes?.ec;
1088
1219
  offset = container?.nodeType === 3 ? container.textContent.length : 1;
1089
1220
  }
@@ -1120,7 +1251,18 @@ class HTML {
1120
1251
  for (let i = 0, len = rootKey.length, r; i < len; i++) {
1121
1252
  this.#$.facade.changeFrameContext(rootKey[i]);
1122
1253
 
1123
- const renderHTML = dom.utils.createElement('DIV', null, this._convertToCode(this.#frameContext.get('wysiwyg'), true));
1254
+ const renderHTML = dom.utils.createElement(
1255
+ 'DIV',
1256
+ null,
1257
+ this._convertToCode(this.#frameContext.get('wysiwyg'), true),
1258
+ );
1259
+
1260
+ const phLines = renderHTML.querySelectorAll('.se-placeholder-line');
1261
+ for (let j = 0, jlen = phLines.length; j < jlen; j++) {
1262
+ phLines[j].classList.remove('se-placeholder-line');
1263
+ phLines[j].removeAttribute('data-se-placeholder-line');
1264
+ if (!phLines[j].getAttribute('class')) phLines[j].removeAttribute('class');
1265
+ }
1124
1266
 
1125
1267
  const isTableCell = dom.check.isTableCell;
1126
1268
  const isEmptyLine = dom.check.isEmptyLine;
@@ -1155,13 +1297,17 @@ class HTML {
1155
1297
  const content = renderHTML.innerHTML;
1156
1298
  if (this.#frameOptions.get('iframe_fullPage')) {
1157
1299
  if (includeFullPage) {
1158
- const attrs = dom.utils.getAttributesToString(this.#frameContext.get('_wd').body, ['contenteditable']);
1300
+ const attrs = dom.utils.getAttributesToString(this.#frameContext.get('_wd').body, [
1301
+ 'contenteditable',
1302
+ ]);
1159
1303
  r = `<!DOCTYPE html><html>${this.#frameContext.get('_wd').head.outerHTML}<body ${attrs}>${content}</body></html>`;
1160
1304
  } else {
1161
1305
  r = content;
1162
1306
  }
1163
1307
  } else {
1164
- r = withFrame ? `<div class="${this.#options.get('_editableClass') + '' + (this.#options.get('_rtl') ? ' se-rtl' : '')}">${content}</div>` : renderHTML.innerHTML;
1308
+ r = withFrame
1309
+ ? `<div class="${this.#options.get('_editableClass') + '' + (this.#options.get('_rtl') ? ' se-rtl' : '')}">${content}</div>`
1310
+ : renderHTML.innerHTML;
1165
1311
  }
1166
1312
 
1167
1313
  resultValue[rootKey[i]] = r;
@@ -1183,7 +1329,10 @@ class HTML {
1183
1329
  set(html, { rootKey } = {}) {
1184
1330
  this.#$.ui.offCurrentController();
1185
1331
  this.#$.selection.removeRange();
1186
- const convertValue = html === null || html === undefined ? '' : this.clean(html, { forceFormat: true, whitelist: null, blacklist: null });
1332
+ const convertValue =
1333
+ html === null || html === undefined
1334
+ ? ''
1335
+ : this.clean(html, { forceFormat: true, whitelist: null, blacklist: null });
1187
1336
 
1188
1337
  if (!rootKey) rootKey = [this.#store.get('rootKey')];
1189
1338
  else if (!Array.isArray(rootKey)) rootKey = [rootKey];
@@ -1233,7 +1382,9 @@ class HTML {
1233
1382
  this.#$.history.push(false, rootKey[i]);
1234
1383
  this.#$.selection.scrollTo(children.at(-1));
1235
1384
  } else {
1236
- this.#$.viewer._setCodeView(this.#$.viewer._getCodeView() + '\n' + this._convertToCode(convertValue, false));
1385
+ this.#$.viewer._setCodeView(
1386
+ this.#$.viewer._getCodeView() + '\n' + this._convertToCode(convertValue, false),
1387
+ );
1237
1388
  }
1238
1389
  }
1239
1390
  }
@@ -1276,10 +1427,15 @@ class HTML {
1276
1427
  */
1277
1428
  async copy(content) {
1278
1429
  try {
1279
- if (typeof content !== 'string' && !dom.check.isElement(content) && !dom.check.isText(content)) return false;
1430
+ if (typeof content !== 'string' && !dom.check.isElement(content) && !dom.check.isText(content))
1431
+ return false;
1280
1432
 
1281
1433
  if ((await clipboard.write(content)) === false) {
1282
- this.#$.ui.showToast(this.#$.lang.message_copy_fail, this.#options.get('toastMessageTime').copy, 'error');
1434
+ this.#$.ui.showToast(
1435
+ this.#$.lang.message_copy_fail,
1436
+ this.#options.get('toastMessageTime').copy,
1437
+ 'error',
1438
+ );
1283
1439
  return false;
1284
1440
  }
1285
1441
  this.#$.ui.showToast(this.#$.lang.message_copy_success, this.#options.get('toastMessageTime').copy);
@@ -1305,8 +1461,14 @@ class HTML {
1305
1461
 
1306
1462
  for (let i = 0; i < rootKey.length; i++) {
1307
1463
  this.#$.facade.changeFrameContext(rootKey[i]);
1308
- if (ctx.head) this.#frameContext.get('_wd').head.innerHTML = ctx.head.replace(this.#disallowedTagsRegExp, '');
1309
- if (ctx.body) this.#frameContext.get('_wd').body.innerHTML = this.clean(ctx.body, { forceFormat: true, whitelist: null, blacklist: null });
1464
+ if (ctx.head)
1465
+ this.#frameContext.get('_wd').head.innerHTML = ctx.head.replace(this.#disallowedTagsRegExp, '');
1466
+ if (ctx.body)
1467
+ this.#frameContext.get('_wd').body.innerHTML = this.clean(ctx.body, {
1468
+ forceFormat: true,
1469
+ whitelist: null,
1470
+ blacklist: null,
1471
+ });
1310
1472
  this.#$.pluginManager.resetFileInfo();
1311
1473
  }
1312
1474
  }
@@ -1330,7 +1492,10 @@ class HTML {
1330
1492
  _convertToCode(html, comp) {
1331
1493
  let returnHTML = '';
1332
1494
  const wRegExp = RegExp;
1333
- const brReg = new wRegExp('^(BLOCKQUOTE|PRE|TABLE|THEAD|TBODY|TR|TH|TD|OL|UL|IMG|IFRAME|VIDEO|AUDIO|FIGURE|FIGCAPTION|HR|BR|CANVAS|SELECT)$', 'i');
1495
+ const brReg = new wRegExp(
1496
+ '^(BLOCKQUOTE|PRE|TABLE|THEAD|TBODY|TR|TH|TD|OL|UL|IMG|IFRAME|VIDEO|AUDIO|FIGURE|FIGCAPTION|HR|BR|CANVAS|SELECT)$',
1497
+ 'i',
1498
+ );
1334
1499
  const wDoc = typeof html === 'string' ? _d.createRange().createContextualFragment(html) : html;
1335
1500
  const isFormat = (current) => {
1336
1501
  return this.#$.format.isLine(current) || this.#$.component.is(current);
@@ -1358,11 +1523,20 @@ class HTML {
1358
1523
  continue;
1359
1524
  }
1360
1525
  if (node.nodeType === 3) {
1361
- if (!dom.check.isList(node.parentElement)) returnHTML += converter.htmlToEntity(/^\n+$/.test(/** @type {Text} */ (node).data) ? '' : /** @type {Text} */ (node).data);
1526
+ if (!dom.check.isList(node.parentElement))
1527
+ returnHTML += converter.htmlToEntity(
1528
+ /^\n+$/.test(/** @type {Text} */ (node).data) ? '' : /** @type {Text} */ (node).data,
1529
+ );
1362
1530
  continue;
1363
1531
  }
1364
1532
  if (node.childNodes.length === 0) {
1365
- returnHTML += (/^HR$/i.test(node.nodeName) ? brChar : '') + (/^PRE$/i.test(node.parentElement.nodeName) && /^BR$/i.test(node.nodeName) ? '' : elementIndent) + /** @type {HTMLElement} */ (node).outerHTML + br;
1533
+ returnHTML +=
1534
+ (/^HR$/i.test(node.nodeName) ? brChar : '') +
1535
+ (/^PRE$/i.test(node.parentElement.nodeName) && /^BR$/i.test(node.nodeName)
1536
+ ? ''
1537
+ : elementIndent) +
1538
+ /** @type {HTMLElement} */ (node).outerHTML +
1539
+ br;
1366
1540
  continue;
1367
1541
  }
1368
1542
 
@@ -1371,9 +1545,18 @@ class HTML {
1371
1545
  } else {
1372
1546
  tag = node.nodeName.toLowerCase();
1373
1547
  tagIndent = elementIndent || nodeRegTest ? indent : '';
1374
- returnHTML += (lineBR || (elementRegTest ? '' : br)) + tagIndent + /** @type {HTMLElement} */ (node).outerHTML.match(wRegExp('<' + tag + '[^>]*>', 'i'))[0] + br;
1548
+ returnHTML +=
1549
+ (lineBR || (elementRegTest ? '' : br)) +
1550
+ tagIndent +
1551
+ /** @type {HTMLElement} */ (node).outerHTML.match(wRegExp('<' + tag + '[^>]*>', 'i'))[0] +
1552
+ br;
1375
1553
  recursionFunc(node, indent + indentSize + '');
1376
- returnHTML += (/\n$/.test(returnHTML) ? tagIndent : '') + '</' + tag + '>' + (lineBR || br || elementRegTest ? brChar : /^(TH|TD)$/i.test(node.nodeName) ? brChar : '');
1554
+ returnHTML +=
1555
+ (/\n$/.test(returnHTML) ? tagIndent : '') +
1556
+ '</' +
1557
+ tag +
1558
+ '>' +
1559
+ (lineBR || br || elementRegTest ? brChar : /^(TH|TD)$/i.test(node.nodeName) ? brChar : '');
1377
1560
  }
1378
1561
  }
1379
1562
  })(wDoc, '');
@@ -1451,7 +1634,10 @@ class HTML {
1451
1634
  dom.query.getListChildNodes(
1452
1635
  node,
1453
1636
  (current) => {
1454
- return dom.check.isSpanWithoutAttr(current) && !dom.query.getParentElement(current, dom.check.isExcludeFormat);
1637
+ return (
1638
+ dom.check.isSpanWithoutAttr(current) &&
1639
+ !dom.query.getParentElement(current, dom.check.isExcludeFormat)
1640
+ );
1455
1641
  },
1456
1642
  null,
1457
1643
  ) || [];
@@ -1473,7 +1659,15 @@ class HTML {
1473
1659
  return dom.check.isSpanWithoutAttr(node) ? n.innerHTML : n.outerHTML;
1474
1660
  } else {
1475
1661
  const n = /** @type {HTMLElement} */ (node);
1476
- return '<' + defaultLine + '>' + (dom.check.isSpanWithoutAttr(node) ? n.innerHTML : n.outerHTML) + '</' + defaultLine + '>';
1662
+ return (
1663
+ '<' +
1664
+ defaultLine +
1665
+ '>' +
1666
+ (dom.check.isSpanWithoutAttr(node) ? n.innerHTML : n.outerHTML) +
1667
+ '</' +
1668
+ defaultLine +
1669
+ '>'
1670
+ );
1477
1671
  }
1478
1672
  }
1479
1673
  // text
@@ -1483,7 +1677,8 @@ class HTML {
1483
1677
  let html = '';
1484
1678
  for (let i = 0, tLen = textArray.length, text; i < tLen; i++) {
1485
1679
  text = textArray[i].trim();
1486
- if (text.length > 0) html += '<' + defaultLine + '>' + converter.htmlToEntity(text) + '</' + defaultLine + '>';
1680
+ if (text.length > 0)
1681
+ html += '<' + defaultLine + '>' + converter.htmlToEntity(text) + '</' + defaultLine + '>';
1487
1682
  }
1488
1683
  return html;
1489
1684
  }
@@ -1495,6 +1690,23 @@ class HTML {
1495
1690
  return '';
1496
1691
  }
1497
1692
 
1693
+ /**
1694
+ * @description Checks whether a node is a block-level container in which whitespace-only text
1695
+ * children are insignificant formatting whitespace (safe to drop), as opposed to an inline/line
1696
+ * @param {?Node} node Parent node of the whitespace text node (may be a `DocumentFragment`).
1697
+ * @returns {boolean} `true` if the node is a block-level container.
1698
+ */
1699
+ #isBlockLevelWhitespaceContext(node) {
1700
+ return (
1701
+ !node ||
1702
+ node.nodeType === 11 ||
1703
+ dom.check.isWysiwygFrame(node) ||
1704
+ dom.check.isList(node) ||
1705
+ dom.check.isTableElements(node) ||
1706
+ this.#$.format.isBlock(node)
1707
+ );
1708
+ }
1709
+
1498
1710
  /**
1499
1711
  * @description Fix tags that do not fit the editor format.
1500
1712
  * @param {DocumentFragment} documentFragment Document fragment `DOCUMENT_FRAGMENT_NODE` (nodeType === 11)
@@ -1505,7 +1717,15 @@ class HTML {
1505
1717
  * @param {boolean} classFilter Class name filter option
1506
1718
  * @param {boolean} _freeCodeViewMode Enforces strict HTML validation based on the editor`s policy
1507
1719
  */
1508
- #consistencyCheckOfHTML(documentFragment, htmlCheckWhitelistRegExp, htmlCheckBlacklistRegExp, tagFilter, formatFilter, classFilter, _freeCodeViewMode) {
1720
+ #consistencyCheckOfHTML(
1721
+ documentFragment,
1722
+ htmlCheckWhitelistRegExp,
1723
+ htmlCheckBlacklistRegExp,
1724
+ tagFilter,
1725
+ formatFilter,
1726
+ classFilter,
1727
+ _freeCodeViewMode,
1728
+ ) {
1509
1729
  const removeTags = [],
1510
1730
  emptyTags = [],
1511
1731
  wrongList = [],
@@ -1517,14 +1737,29 @@ class HTML {
1517
1737
  (current) => {
1518
1738
  if (current.nodeType !== 1) {
1519
1739
  if (formatFilter && dom.check.isList(current.parentElement)) removeTags.push(current);
1520
- if (current.nodeType === 3 && !current.textContent.trim()) removeTags.push(current);
1740
+ if (current.nodeType === 3) {
1741
+ // Remove empty text nodes, and collapsible whitespace-only nodes that render nothing
1742
+ if (
1743
+ !current.textContent ||
1744
+ (_RE_INSIGNIFICANT_WS.test(current.textContent) &&
1745
+ (this.#isBlockLevelWhitespaceContext(current.parentNode) ||
1746
+ !current.previousSibling !== !current.nextSibling))
1747
+ ) {
1748
+ removeTags.push(current);
1749
+ }
1750
+ }
1521
1751
  return false;
1522
1752
  }
1523
1753
 
1524
1754
  // tag filter
1525
1755
  if (tagFilter) {
1526
1756
  // white list
1527
- if (htmlCheckBlacklistRegExp.test(current.nodeName) || (!htmlCheckWhitelistRegExp.test(current.nodeName) && current.childNodes.length === 0 && dom.check.isExcludeFormat(current))) {
1757
+ if (
1758
+ htmlCheckBlacklistRegExp.test(current.nodeName) ||
1759
+ (!htmlCheckWhitelistRegExp.test(current.nodeName) &&
1760
+ current.childNodes.length === 0 &&
1761
+ dom.check.isExcludeFormat(current))
1762
+ ) {
1528
1763
  removeTags.push(current);
1529
1764
  return false;
1530
1765
  }
@@ -1542,7 +1777,9 @@ class HTML {
1542
1777
  !dom.check.isTableElements(current) &&
1543
1778
  !dom.check.isListCell(current) &&
1544
1779
  !dom.check.isAnchor(current) &&
1545
- (this.#$.format.isLine(current) || this.#$.format.isBlock(current) || this.#$.format.isTextStyleNode(current)) &&
1780
+ (this.#$.format.isLine(current) ||
1781
+ this.#$.format.isBlock(current) ||
1782
+ this.#$.format.isTextStyleNode(current)) &&
1546
1783
  current.childNodes.length === 0 &&
1547
1784
  nrtag
1548
1785
  ) {
@@ -1551,7 +1788,11 @@ class HTML {
1551
1788
  }
1552
1789
 
1553
1790
  // wrong list
1554
- if (dom.check.isList(current.parentNode) && !dom.check.isList(current) && !dom.check.isListCell(current)) {
1791
+ if (
1792
+ dom.check.isList(current.parentNode) &&
1793
+ !dom.check.isList(current) &&
1794
+ !dom.check.isListCell(current)
1795
+ ) {
1555
1796
  wrongList.push(current);
1556
1797
  return false;
1557
1798
  }
@@ -1585,7 +1826,9 @@ class HTML {
1585
1826
  current.parentNode !== documentFragment &&
1586
1827
  nrtag &&
1587
1828
  ((dom.check.isListCell(current) && !dom.check.isList(current.parentNode)) ||
1588
- ((this.#$.format.isLine(current) || this.#$.component.is(current)) && !this.#$.format.isBlock(current.parentNode) && !dom.query.getParentElement(current, this.#$.component.is.bind(this.#$.component))));
1829
+ ((this.#$.format.isLine(current) || this.#$.component.is(current)) &&
1830
+ !this.#$.format.isBlock(current.parentNode) &&
1831
+ !dom.query.getParentElement(current, this.#$.component.is.bind(this.#$.component))));
1589
1832
 
1590
1833
  return result;
1591
1834
  },
@@ -1709,7 +1952,13 @@ class HTML {
1709
1952
 
1710
1953
  if (n.nodeType === 8) {
1711
1954
  value += '<!-- ' + n.textContent + ' -->';
1712
- } else if (!/meta/i.test(n.nodeName) && !this.#$.format.isLine(n) && !this.#$.format.isBlock(n) && !this.#$.component.is(n) && !dom.check.isExcludeFormat(n)) {
1955
+ } else if (
1956
+ !/meta/i.test(n.nodeName) &&
1957
+ !this.#$.format.isLine(n) &&
1958
+ !this.#$.format.isBlock(n) &&
1959
+ !this.#$.component.is(n) &&
1960
+ !dom.check.isExcludeFormat(n)
1961
+ ) {
1713
1962
  f ||= dom.utils.createElement(this.#options.get('defaultLine'));
1714
1963
  if (this.#$.format.isTextStyleNode(n)) {
1715
1964
  /** @type {HTMLElement} */
@@ -1774,7 +2023,12 @@ class HTML {
1774
2023
 
1775
2024
  for (let i = 0, len = domTree.length, t; i < len; i++) {
1776
2025
  t = domTree[i];
1777
- if (t.nodeType === 1 && !this.#$.format.isTextStyleNode(t) && !dom.check.isBreak(t) && !this.#disallowedTagNameRegExp.test(t.nodeName)) {
2026
+ if (
2027
+ t.nodeType === 1 &&
2028
+ !this.#$.format.isTextStyleNode(t) &&
2029
+ !dom.check.isBreak(t) &&
2030
+ !this.#disallowedTagNameRegExp.test(t.nodeName)
2031
+ ) {
1778
2032
  requireFormat = true;
1779
2033
  break;
1780
2034
  }
@@ -1798,7 +2052,12 @@ class HTML {
1798
2052
  const face = (m.match(_RE_FACE_ATTR) || [])[1];
1799
2053
  const color = (m.match(_RE_COLOR_ATTR) || [])[1];
1800
2054
  if (size || face || color) {
1801
- sv = 'style="' + (size ? 'font-size:' + numbers.get(Number(size) / 3.333, 1) + 'rem;' : '') + (face ? 'font-family:' + face + ';' : '') + (color ? 'color:' + color + ';' : '') + '"';
2055
+ sv =
2056
+ 'style="' +
2057
+ (size ? 'font-size:' + numbers.get(Number(size) / 3.333, 1) + 'rem;' : '') +
2058
+ (face ? 'font-family:' + face + ';' : '') +
2059
+ (color ? 'color:' + color + ';' : '') +
2060
+ '"';
1802
2061
  }
1803
2062
  }
1804
2063
 
@@ -1831,7 +2090,10 @@ class HTML {
1831
2090
  case 'fontSize':
1832
2091
  if (!this.#$.plugins.fontSize) continue;
1833
2092
  if (!this.#fontSizeUnitRegExp.test(r[0])) {
1834
- r[0] = r[0].replace((r[0].match(_RE_CSS_VALUE) || [])[1], converter.toFontUnit.bind(null, this.#options.get('fontSizeUnits')[0]));
2093
+ r[0] = r[0].replace(
2094
+ (r[0].match(_RE_CSS_VALUE) || [])[1],
2095
+ converter.toFontUnit.bind(null, this.#options.get('fontSizeUnits')[0]),
2096
+ );
1835
2097
  }
1836
2098
  break;
1837
2099
  case 'color':
@@ -1966,12 +2228,12 @@ class HTML {
1966
2228
  v.push(sv[0]);
1967
2229
  }
1968
2230
  } else if (!v || !_RE_STYLE_EQ.test(v.toString())) {
1969
- if (this.#textStyleTags.includes(tagName)) {
2231
+ if (this.#cleanStyleTagKeyRegExp.test(tagName)) {
1970
2232
  v = this.#cleanStyle(m, v, tagName);
1971
2233
  } 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);
2234
+ v = this.#cleanStyle(m, v, '@line');
2235
+ } else if (this.#textStyleTags.includes(tagName)) {
2236
+ v = this.#cleanStyle(m, v, '@text');
1975
2237
  }
1976
2238
  }
1977
2239
 
@@ -2011,10 +2273,16 @@ class HTML {
2011
2273
  styleToTag.italic = { regex: /font-style\s*:\s*italic/i, tag: convertTextTags.italic };
2012
2274
  break;
2013
2275
  case 'underline':
2014
- styleToTag.underline = { regex: /text-decoration\s*:\s*underline/i, tag: convertTextTags.underline };
2276
+ styleToTag.underline = {
2277
+ regex: /text-decoration\s*:\s*underline/i,
2278
+ tag: convertTextTags.underline,
2279
+ };
2015
2280
  break;
2016
2281
  case 'strike':
2017
- styleToTag.strike = { regex: /text-decoration\s*:\s*line-through/i, tag: convertTextTags.strike };
2282
+ styleToTag.strike = {
2283
+ regex: /text-decoration\s*:\s*line-through/i,
2284
+ tag: convertTextTags.strike,
2285
+ };
2018
2286
  break;
2019
2287
  }
2020
2288
  });
@@ -2092,6 +2360,8 @@ const _RE_LEADING_SPACE = /^\s/;
2092
2360
 
2093
2361
  // #cleanStyle
2094
2362
  const _RE_TAG_ATTRS = /<[^\s]+\s(.+)/;
2363
+ // #consistencyCheckOfHTML: collapsible ASCII whitespace only (excludes &nbsp;/zero-width, which are meaningful content)
2364
+ const _RE_INSIGNIFICANT_WS = /^[ \t\n\r\f\v]+$/;
2095
2365
  const _RE_SIZE_ATTR = /\ssize="([^"]+)"/i;
2096
2366
  const _RE_FACE_ATTR = /\sface="([^"]+)"/i;
2097
2367
  const _RE_COLOR_ATTR = /\scolor="([^"]+)"/i;