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
@@ -19,6 +19,10 @@ import { Browser } from '../../modules/contract';
19
19
  * }
20
20
  * ```
21
21
  * @property {Object<string, string>} [headers] - Server request headers
22
+ * @property {string} [searchUrl] - Server-side search URL. When set, the keyword is sent to this URL
23
+ * as `?keyword=<value>` and the server response replaces the list. When not set, search filters the
24
+ * already-loaded items locally.
25
+ * @property {Object<string, string>} [searchHeaders] - Server-side search request headers
22
26
  * @property {string|((item: SunEditor.Module.Browser.File) => string)} [thumbnail] - Default thumbnail
23
27
  */
24
28
 
@@ -45,12 +49,15 @@ class AudioGallery extends PluginBrowser {
45
49
  this.onSelectfunction = null;
46
50
 
47
51
  // modules
48
- const thumbnail = typeof pluginOptions.thumbnail === 'string' ? pluginOptions.thumbnail : this.$.icons.audio_thumbnail;
52
+ const thumbnail =
53
+ typeof pluginOptions.thumbnail === 'string' ? pluginOptions.thumbnail : this.$.icons.audio_thumbnail;
49
54
  this.browser = new Browser(this, this.$, {
50
55
  title: this.$.lang.audioGallery,
51
56
  data: pluginOptions.data,
52
57
  url: pluginOptions.url,
53
58
  headers: pluginOptions.headers,
59
+ searchUrl: pluginOptions.searchUrl,
60
+ searchHeaders: pluginOptions.searchHeaders,
54
61
  selectorHandler: this.#SetItem.bind(this),
55
62
  columnSize: 4,
56
63
  className: 'se-audio-gallery',
@@ -26,6 +26,10 @@ import { Browser } from '../../modules/contract';
26
26
  * }
27
27
  * ```
28
28
  * @property {Object<string, string>} [headers] - Server request headers
29
+ * @property {string} [searchUrl] - Server-side search URL. When set, the keyword is sent to this URL
30
+ * as `?keyword=<value>` and the server response replaces the list. When not set, search filters the
31
+ * already-loaded items locally.
32
+ * @property {Object<string, string>} [searchHeaders] - Server-side search request headers
29
33
  * @property {string|((item: SunEditor.Module.Browser.File) => string)} [thumbnail] - Default thumbnail URL or a function that returns a thumbnail URL per item.
30
34
  * @property {number} [expand=1] - Initial folder expand depth. `1` expands the first level, `Infinity` expands all. Default: `1`.
31
35
  * @property {Array<string>} [props] - Additional tag names
@@ -57,17 +61,26 @@ class FileBrowser extends PluginBrowser {
57
61
  this.onSelectfunction = null;
58
62
 
59
63
  // modules
60
- const thumbnail = { video: this.$.icons.video_thumbnail, audio: this.$.icons.audio_thumbnail, file: this.$.icons.file_thumbnail };
64
+ const thumbnail = {
65
+ video: this.$.icons.video_thumbnail,
66
+ audio: this.$.icons.audio_thumbnail,
67
+ file: this.$.icons.file_thumbnail,
68
+ };
61
69
  const defaultThumbnail = this.$.icons.file_thumbnail;
62
70
  this.browser = new Browser(this, this.$, {
63
71
  title: this.$.lang.fileBrowser,
64
72
  data: pluginOptions.data,
65
73
  url: pluginOptions.url,
66
74
  headers: pluginOptions.headers,
75
+ searchUrl: pluginOptions.searchUrl,
76
+ searchHeaders: pluginOptions.searchHeaders,
67
77
  selectorHandler: this.#SetItem.bind(this),
68
78
  columnSize: 4,
69
79
  className: 'se-file-browser',
70
- thumbnail: typeof pluginOptions.thumbnail === 'function' ? pluginOptions.thumbnail : (item) => thumbnail[item.type] || defaultThumbnail,
80
+ thumbnail:
81
+ typeof pluginOptions.thumbnail === 'function'
82
+ ? pluginOptions.thumbnail
83
+ : (item) => thumbnail[item.type] || defaultThumbnail,
71
84
  props: [...new Set((pluginOptions.props ?? []).concat(['frame']))],
72
85
  expand: pluginOptions.expand,
73
86
  });
@@ -20,6 +20,10 @@ import { Browser } from '../../modules/contract';
20
20
  * }
21
21
  * ```
22
22
  * @property {Object<string, string>} [headers] - Server request headers
23
+ * @property {string} [searchUrl] - Server-side search URL. When set, the keyword is sent to this URL
24
+ * as `?keyword=<value>` and the server response replaces the list. When not set, search filters the
25
+ * already-loaded items locally.
26
+ * @property {Object<string, string>} [searchHeaders] - Server-side search request headers
23
27
  * @property {string|((item: SunEditor.Module.Browser.File) => string)} [thumbnail] - Default thumbnail
24
28
  */
25
29
 
@@ -46,12 +50,15 @@ class FileGallery extends PluginBrowser {
46
50
  this.onSelectfunction = null;
47
51
 
48
52
  // modules
49
- const thumbnail = typeof pluginOptions.thumbnail === 'string' ? pluginOptions.thumbnail : this.$.icons.file_thumbnail;
53
+ const thumbnail =
54
+ typeof pluginOptions.thumbnail === 'string' ? pluginOptions.thumbnail : this.$.icons.file_thumbnail;
50
55
  this.browser = new Browser(this, this.$, {
51
56
  title: this.$.lang.fileGallery,
52
57
  data: pluginOptions.data,
53
58
  url: pluginOptions.url,
54
59
  headers: pluginOptions.headers,
60
+ searchUrl: pluginOptions.searchUrl,
61
+ searchHeaders: pluginOptions.searchHeaders,
55
62
  selectorHandler: this.#SetItem.bind(this),
56
63
  columnSize: 4,
57
64
  className: 'se-file-gallery',
@@ -20,6 +20,10 @@ import { Browser } from '../../modules/contract';
20
20
  * }
21
21
  * ```
22
22
  * @property {Object<string, string>} [headers] - Server request headers
23
+ * @property {string} [searchUrl] - Server-side search URL. When set, the keyword is sent to this URL
24
+ * as `?keyword=<value>` and the server response replaces the list. When not set, search filters the
25
+ * already-loaded items locally.
26
+ * @property {Object<string, string>} [searchHeaders] - Server-side search request headers
23
27
  */
24
28
 
25
29
  /**
@@ -50,14 +54,22 @@ class ImageGallery extends PluginBrowser {
50
54
  data: pluginOptions.data,
51
55
  url: pluginOptions.url,
52
56
  headers: pluginOptions.headers,
57
+ searchUrl: pluginOptions.searchUrl,
58
+ searchHeaders: pluginOptions.searchHeaders,
53
59
  selectorHandler: this.#SetItem.bind(this),
54
60
  columnSize: 4,
55
61
  className: 'se-image-gallery',
56
62
  });
57
63
 
58
64
  // members
59
- this.width = this.$.plugins.image.pluginOptions.defaultWidth === 'auto' ? '' : this.$.plugins.image.pluginOptions.defaultWidth;
60
- this.height = this.$.plugins.image.pluginOptions.defaultHeight === 'auto' ? '' : this.$.plugins.image.pluginOptions.defaultHeight;
65
+ this.width =
66
+ this.$.plugins.image.pluginOptions.defaultWidth === 'auto'
67
+ ? ''
68
+ : this.$.plugins.image.pluginOptions.defaultWidth;
69
+ this.height =
70
+ this.$.plugins.image.pluginOptions.defaultHeight === 'auto'
71
+ ? ''
72
+ : this.$.plugins.image.pluginOptions.defaultHeight;
61
73
  }
62
74
 
63
75
  /**
@@ -88,7 +100,16 @@ class ImageGallery extends PluginBrowser {
88
100
  } else {
89
101
  const file = { name: target.getAttribute('data-name'), size: 0 };
90
102
  this.$.plugins.image.modalInit();
91
- this.$.plugins.image.create(target.getAttribute('data-command'), null, this.width, this.height, 'none', file, target.alt, true);
103
+ this.$.plugins.image.create(
104
+ target.getAttribute('data-command'),
105
+ null,
106
+ this.width,
107
+ this.height,
108
+ 'none',
109
+ file,
110
+ target.alt,
111
+ true,
112
+ );
92
113
  }
93
114
  }
94
115
  }
@@ -20,6 +20,10 @@ import { Browser } from '../../modules/contract';
20
20
  * }
21
21
  * ```
22
22
  * @property {Object<string, string>} [headers] - Server request headers
23
+ * @property {string} [searchUrl] - Server-side search URL. When set, the keyword is sent to this URL
24
+ * as `?keyword=<value>` and the server response replaces the list. When not set, search filters the
25
+ * already-loaded items locally.
26
+ * @property {Object<string, string>} [searchHeaders] - Server-side search request headers
23
27
  * @property {string|((item: SunEditor.Module.Browser.File) => string)} [thumbnail] - Default thumbnail
24
28
  */
25
29
 
@@ -46,12 +50,15 @@ class VideoGallery extends PluginBrowser {
46
50
  this.onSelectfunction = null;
47
51
 
48
52
  // modules
49
- const thumbnail = typeof pluginOptions.thumbnail === 'string' ? pluginOptions.thumbnail : this.$.icons.video_thumbnail;
53
+ const thumbnail =
54
+ typeof pluginOptions.thumbnail === 'string' ? pluginOptions.thumbnail : this.$.icons.video_thumbnail;
50
55
  this.browser = new Browser(this, this.$, {
51
56
  title: this.$.lang.videoGallery,
52
57
  data: pluginOptions.data,
53
58
  url: pluginOptions.url,
54
59
  headers: pluginOptions.headers,
60
+ searchUrl: pluginOptions.searchUrl,
61
+ searchHeaders: pluginOptions.searchHeaders,
55
62
  selectorHandler: this.#SetItem.bind(this),
56
63
  columnSize: 4,
57
64
  className: 'se-video-gallery',
@@ -60,8 +67,14 @@ class VideoGallery extends PluginBrowser {
60
67
  });
61
68
 
62
69
  // members
63
- this.width = this.$.plugins.video.pluginOptions.defaultWidth === 'auto' ? '' : this.$.plugins.video.pluginOptions.defaultWidth;
64
- this.height = this.$.plugins.video.pluginOptions.defaultHeight === 'auto' ? '' : this.$.plugins.video.pluginOptions.defaultHeight;
70
+ this.width =
71
+ this.$.plugins.video.pluginOptions.defaultWidth === 'auto'
72
+ ? ''
73
+ : this.$.plugins.video.pluginOptions.defaultWidth;
74
+ this.height =
75
+ this.$.plugins.video.pluginOptions.defaultHeight === 'auto'
76
+ ? ''
77
+ : this.$.plugins.video.pluginOptions.defaultHeight;
65
78
  }
66
79
 
67
80
  /**
@@ -99,7 +112,9 @@ class VideoGallery extends PluginBrowser {
99
112
  const file = { name: target.getAttribute('data-name'), size: 0 };
100
113
  this.$.plugins.video.modalInit();
101
114
  this.$.plugins.video.create(
102
- this.$.plugins.video[target.getAttribute('data-frame') === 'iframe' ? 'createIframeTag' : 'createVideoTag']({ poster: target.getAttribute('data-thumbnail') }),
115
+ this.$.plugins.video[
116
+ target.getAttribute('data-frame') === 'iframe' ? 'createIframeTag' : 'createVideoTag'
117
+ ]({ poster: target.getAttribute('data-thumbnail') }),
103
118
  url,
104
119
  null,
105
120
  this.width,
@@ -45,7 +45,12 @@ class Blockquote extends PluginCommand {
45
45
  const currentBlockquote = dom.query.getParentElement(this.$.selection.getNode(), 'blockquote');
46
46
 
47
47
  if (currentBlockquote) {
48
- this.$.format.removeBlock(currentBlockquote, { selectedFormats: null, newBlockElement: null, shouldDelete: false, skipHistory: false });
48
+ this.$.format.removeBlock(currentBlockquote, {
49
+ selectedFormats: null,
50
+ newBlockElement: null,
51
+ shouldDelete: false,
52
+ skipHistory: false,
53
+ });
49
54
  } else {
50
55
  this.$.format.applyBlock(this.quoteTag.cloneNode(false));
51
56
  }
@@ -5,7 +5,29 @@ import { SelectMenu } from '../../modules/ui';
5
5
 
6
6
  void PluginDropdown;
7
7
 
8
- const DEFAULT_LANGS = ['javascript', 'typescript', 'html', 'css', 'json', 'python', 'java', 'c', 'cpp', 'csharp', 'go', 'rust', 'ruby', 'php', 'swift', 'kotlin', 'sql', 'bash', 'markdown', 'xml', 'yaml'];
8
+ const DEFAULT_LANGS = [
9
+ 'javascript',
10
+ 'typescript',
11
+ 'html',
12
+ 'css',
13
+ 'json',
14
+ 'python',
15
+ 'java',
16
+ 'c',
17
+ 'cpp',
18
+ 'csharp',
19
+ 'go',
20
+ 'rust',
21
+ 'ruby',
22
+ 'php',
23
+ 'swift',
24
+ 'kotlin',
25
+ 'sql',
26
+ 'bash',
27
+ 'markdown',
28
+ 'xml',
29
+ 'yaml',
30
+ ];
9
31
 
10
32
  /**
11
33
  * @typedef {Object} CodeBlockPluginOptions
@@ -66,7 +88,12 @@ class CodeBlock extends PluginCommand {
66
88
  // ───────────────── [[toolbar dropdown type]] ─────────────────
67
89
  this.afterItem = dom.utils.createElement(
68
90
  'button',
69
- { class: 'se-btn se-tooltip se-sub-arrow-btn', type: 'button', 'data-command': CodeBlock.key, 'data-type': 'dropdown' },
91
+ {
92
+ class: 'se-btn se-tooltip se-sub-arrow-btn',
93
+ type: 'button',
94
+ 'data-command': CodeBlock.key,
95
+ 'data-type': 'dropdown',
96
+ },
70
97
  `${this.$.icons.arrow_down}<span class="se-tooltip-inner"><span class="se-tooltip-text">${this.$.lang.codeLanguage || 'Language'}</span></span>`,
71
98
  );
72
99
 
@@ -242,11 +269,19 @@ class CodeBlock extends PluginCommand {
242
269
  }
243
270
 
244
271
  #addPreLeaveEvent() {
245
- this.#mouseLeaveEvent ??= this.$.eventManager.addEvent(this.#hoverCurrentPre, 'mouseleave', this.#removeEventFunc);
272
+ this.#mouseLeaveEvent ??= this.$.eventManager.addEvent(
273
+ this.#hoverCurrentPre,
274
+ 'mouseleave',
275
+ this.#removeEventFunc,
276
+ );
246
277
  }
247
278
 
248
279
  #addCtrlLeaveEvent() {
249
- this.#mouseLeaveEvent ??= this.$.eventManager.addEvent(this.#hoverController.form, 'mouseleave', this.#removeEventFunc);
280
+ this.#mouseLeaveEvent ??= this.$.eventManager.addEvent(
281
+ this.#hoverController.form,
282
+ 'mouseleave',
283
+ this.#removeEventFunc,
284
+ );
250
285
  }
251
286
 
252
287
  #buildHoverMenu(currentLang) {
@@ -271,7 +306,10 @@ class CodeBlock extends PluginCommand {
271
306
  * @returns {string}
272
307
  */
273
308
  #getPreLang(preOrChild) {
274
- const pre = preOrChild?.nodeName === 'PRE' ? preOrChild : dom.query.getParentElement(preOrChild, (el) => /^PRE$/i.test(el.nodeName));
309
+ const pre =
310
+ preOrChild?.nodeName === 'PRE'
311
+ ? preOrChild
312
+ : dom.query.getParentElement(preOrChild, (el) => /^PRE$/i.test(el.nodeName));
275
313
  if (!pre) return '';
276
314
  return /** @type {HTMLElement} */ (pre).className.match(/language-(\S+)/)?.[1] || '';
277
315
  }
@@ -62,17 +62,29 @@ class ExportPDF extends PluginCommand {
62
62
  let ww = null;
63
63
 
64
64
  try {
65
- const standardWW = this.$.frameContext.get('documentTypePageMirror') || this.$.frameContext.get('wysiwygFrame');
65
+ const standardWW =
66
+ this.$.frameContext.get('documentTypePageMirror') || this.$.frameContext.get('wysiwygFrame');
66
67
 
67
68
  // Strip theme class so getComputedStyle resolves default (light) colors for borders, shadows, etc.
68
69
  const themeClass = (this.$.options.get('_themeClass') || '').trim();
69
70
  const wwClassName = themeClass ? standardWW.className.replace(themeClass, '').trim() : standardWW.className;
70
71
  const editableDiv = dom.utils.createElement('div', { class: wwClassName }, standardWW.innerHTML);
71
- ww = dom.utils.createElement('div', { style: `position: absolute; top: -10000px; left: -10000px; width: 21cm; columns: 21cm; height: auto;` }, editableDiv);
72
+ ww = dom.utils.createElement(
73
+ 'div',
74
+ {
75
+ style: `position: absolute; top: -10000px; left: -10000px; width: 21cm; columns: 21cm; height: auto;`,
76
+ },
77
+ editableDiv,
78
+ );
72
79
 
73
80
  const innerPadding = _w.getComputedStyle(standardWW).padding;
74
81
  const inlineWW = dom.utils.applyInlineStylesAll(editableDiv, true, this.$.options.get('allUsedStyles'));
75
- inlineWW.style.padding = inlineWW.style.paddingTop = inlineWW.style.paddingBottom = inlineWW.style.paddingLeft = inlineWW.style.paddingRight = '0';
82
+ inlineWW.style.padding =
83
+ inlineWW.style.paddingTop =
84
+ inlineWW.style.paddingBottom =
85
+ inlineWW.style.paddingLeft =
86
+ inlineWW.style.paddingRight =
87
+ '0';
76
88
 
77
89
  ww.innerHTML = `
78
90
  <style>
@@ -129,7 +141,11 @@ class ExportPDF extends PluginCommand {
129
141
  const contentDisposition = xhr.getResponseHeader('Content-Disposition');
130
142
  const downloadUrl = URL.createObjectURL(blob);
131
143
  const filename = (contentDisposition.match(/filename="([^"]+)/) || [])[1] || this.fileName + '.pdf';
132
- const a = dom.utils.createElement('A', { href: downloadUrl, download: filename, style: 'display: none;' }, null);
144
+ const a = dom.utils.createElement(
145
+ 'A',
146
+ { href: downloadUrl, download: filename, style: 'display: none;' },
147
+ null,
148
+ );
133
149
 
134
150
  try {
135
151
  _d.body.appendChild(a);
@@ -69,7 +69,8 @@ class FileUpload extends PluginCommand {
69
69
  this.title = this.$.lang.fileUpload;
70
70
  this.icon = 'file_upload';
71
71
 
72
- if (!pluginOptions.uploadUrl) console.warn('[SUNEDITOR.fileUpload.warn] "fileUpload" plugin must be have "uploadUrl" option.');
72
+ if (!pluginOptions.uploadUrl)
73
+ console.warn('[SUNEDITOR.fileUpload.warn] "fileUpload" plugin must be have "uploadUrl" option.');
73
74
 
74
75
  // members
75
76
  this.uploadUrl = pluginOptions.uploadUrl;
@@ -77,7 +78,8 @@ class FileUpload extends PluginCommand {
77
78
  this.uploadSizeLimit = numbers.get(pluginOptions.uploadSizeLimit, 0);
78
79
  this.uploadSingleSizeLimit = numbers.get(pluginOptions.uploadSingleSizeLimit, 0);
79
80
  this.allowMultiple = !!pluginOptions.allowMultiple;
80
- this.acceptedFormats = typeof pluginOptions.acceptedFormats !== 'string' ? '*' : pluginOptions.acceptedFormats.trim() || '*';
81
+ this.acceptedFormats =
82
+ typeof pluginOptions.acceptedFormats !== 'string' ? '*' : pluginOptions.acceptedFormats.trim() || '*';
81
83
  this.as = pluginOptions.as || 'box';
82
84
  this.insertBehavior = pluginOptions.insertBehavior;
83
85
  this.input = dom.utils.createElement('input', { type: 'file', accept: this.acceptedFormats });
@@ -109,7 +111,9 @@ class FileUpload extends PluginCommand {
109
111
  },
110
112
  };
111
113
 
112
- const figureControls = (pluginOptions.controls || [['custom-as', 'align', 'edit', 'custom-download', 'copy', 'remove']]).map((subArray) => subArray.map((item) => (item.startsWith('custom-') ? customItems[item] : item)));
114
+ const figureControls = (
115
+ pluginOptions.controls || [['custom-as', 'align', 'edit', 'custom-download', 'copy', 'remove']]
116
+ ).map((subArray) => subArray.map((item) => (item.startsWith('custom-') ? customItems[item] : item)));
113
117
  this.figure = new Figure(this, this.$, figureControls, {});
114
118
 
115
119
  // file manager
@@ -122,7 +126,13 @@ class FileUpload extends PluginCommand {
122
126
  // controller
123
127
  if (/\bedit\b/.test(JSON.stringify(figureControls))) {
124
128
  const controllerEl = CreateHTML_controller(this.$);
125
- this.controller = new Controller(this, this.$, controllerEl, { position: 'bottom', disabled: true }, FileUpload.key);
129
+ this.controller = new Controller(
130
+ this,
131
+ this.$,
132
+ controllerEl,
133
+ { position: 'bottom', disabled: true },
134
+ FileUpload.key,
135
+ );
126
136
  this.editInput = controllerEl.querySelector('input');
127
137
  }
128
138
 
@@ -188,7 +198,13 @@ class FileUpload extends PluginCommand {
188
198
  if (dom.check.isFigure(target.parentElement)) {
189
199
  asBtn.innerHTML = this.$.icons.reduction + dom.utils.createTooltipInner(this.$.lang.asLink);
190
200
  asBtn.setAttribute('data-value', 'link');
191
- this.figure.open(target, { nonResizing: true, nonSizeInfo: true, nonBorder: true, figureTarget: true, infoOnly: false });
201
+ this.figure.open(target, {
202
+ nonResizing: true,
203
+ nonSizeInfo: true,
204
+ nonBorder: true,
205
+ figureTarget: true,
206
+ infoOnly: false,
207
+ });
192
208
  } else {
193
209
  asBtn.innerHTML = this.$.icons.expansion + dom.utils.createTooltipInner(this.$.lang.asBlock);
194
210
  asBtn.setAttribute('data-value', 'box');
@@ -204,7 +220,11 @@ class FileUpload extends PluginCommand {
204
220
  componentEdit(target) {
205
221
  this.editInput.value = target.textContent;
206
222
  this.figure.controllerHide();
207
- this.controller.open(target, null, { isWWTarget: !dom.check.isFigure(target.parentElement), initMethod: null, addOffset: null });
223
+ this.controller.open(target, null, {
224
+ isWWTarget: !dom.check.isFigure(target.parentElement),
225
+ initMethod: null,
226
+ addOffset: null,
227
+ });
208
228
  this.editInput.focus();
209
229
  }
210
230
 
@@ -218,11 +238,17 @@ class FileUpload extends PluginCommand {
218
238
  const figure = Figure.GetContainer(target);
219
239
  const containerTarget = dom.query.getParentElement(target, '.se-component') || target;
220
240
 
221
- const message = await this.$.eventManager.triggerEvent('onFileDeleteBefore', { element: figure.target, container: figure, url: figure.target.getAttribute('href') });
241
+ const message = await this.$.eventManager.triggerEvent('onFileDeleteBefore', {
242
+ element: figure.target,
243
+ container: figure,
244
+ url: figure.target.getAttribute('href'),
245
+ });
222
246
  if (message === false) return;
223
247
 
224
248
  const isInlineComp = this.$.component.isInline(containerTarget);
225
- const focusEl = isInlineComp ? containerTarget.previousSibling || containerTarget.nextSibling : containerTarget.previousElementSibling || containerTarget.nextElementSibling;
249
+ const focusEl = isInlineComp
250
+ ? containerTarget.previousSibling || containerTarget.nextSibling
251
+ : containerTarget.previousElementSibling || containerTarget.nextElementSibling;
226
252
  dom.utils.removeItem(containerTarget);
227
253
  this.$.ui.offCurrentController();
228
254
 
@@ -245,7 +271,8 @@ class FileUpload extends PluginCommand {
245
271
  f = fileList[i];
246
272
  s = f.size;
247
273
  if (slngleSizeLimit > 0 && s > slngleSizeLimit) {
248
- const err = '[SUNEDITOR.fileUpload.fail] Size of uploadable single file: ' + slngleSizeLimit / 1000 + 'KB';
274
+ const err =
275
+ '[SUNEDITOR.fileUpload.fail] Size of uploadable single file: ' + slngleSizeLimit / 1000 + 'KB';
249
276
  const message = await this.$.eventManager.triggerEvent('onFileUploadError', {
250
277
  error: err,
251
278
  limitSize: slngleSizeLimit,
@@ -369,14 +396,22 @@ class FileUpload extends PluginCommand {
369
396
 
370
397
  if (this.as === 'link') {
371
398
  a.className = 'se-component se-inline-component';
372
- this.$.component.insert(a, { scrollTo: isLast ? true : false, insertBehavior: isLast ? this.insertBehavior : null });
399
+ this.$.component.insert(a, {
400
+ scrollTo: isLast ? true : false,
401
+ insertBehavior: isLast ? this.insertBehavior : null,
402
+ });
373
403
  return;
374
404
  }
375
405
 
376
406
  const figure = Figure.CreateContainer(a);
377
407
  dom.utils.addClass(figure.container, 'se-file-figure|se-flex-component');
378
408
 
379
- if (!this.$.component.insert(figure.container, { scrollTo: isLast ? true : false, insertBehavior: isLast ? this.insertBehavior : null })) {
409
+ if (
410
+ !this.$.component.insert(figure.container, {
411
+ scrollTo: isLast ? true : false,
412
+ insertBehavior: isLast ? this.insertBehavior : null,
413
+ })
414
+ ) {
380
415
  this.$.focusManager.focus();
381
416
  return;
382
417
  }
@@ -27,7 +27,12 @@ class List_bulleted extends PluginCommand {
27
27
  this.icon = 'list_bulleted';
28
28
  this.afterItem = dom.utils.createElement(
29
29
  'button',
30
- { class: 'se-btn se-tooltip se-sub-arrow-btn', type: 'button', 'data-command': List_bulleted.key, 'data-type': 'dropdown' },
30
+ {
31
+ class: 'se-btn se-tooltip se-sub-arrow-btn',
32
+ type: 'button',
33
+ 'data-command': List_bulleted.key,
34
+ 'data-type': 'dropdown',
35
+ },
31
36
  `${this.$.icons.arrow_down}<span class="se-tooltip-inner"><span class="se-tooltip-text">${this.$.lang.bulletedList}</span></span>`,
32
37
  );
33
38
 
@@ -27,7 +27,12 @@ class List_numbered extends PluginCommand {
27
27
  this.icon = 'list_numbered';
28
28
  this.afterItem = dom.utils.createElement(
29
29
  'button',
30
- { class: 'se-btn se-tooltip se-sub-arrow-btn', type: 'button', 'data-command': List_numbered.key, 'data-type': 'dropdown' },
30
+ {
31
+ class: 'se-btn se-tooltip se-sub-arrow-btn',
32
+ type: 'button',
33
+ 'data-command': List_numbered.key,
34
+ 'data-type': 'dropdown',
35
+ },
31
36
  `${this.$.icons.arrow_down}<span class="se-tooltip-inner"><span class="se-tooltip-text">${this.$.lang.numberedList}</span></span>`,
32
37
  );
33
38
 
@@ -23,10 +23,6 @@ class Align extends PluginDropdown {
23
23
  this.title = this.$.lang.align;
24
24
  this.icon = this.$.options.get('_rtl') ? 'align_right' : 'align_left';
25
25
 
26
- // create HTML
27
- const menu = CreateHTML(this.$, pluginOptions.items);
28
- const commandArea = (this._itemMenu = menu.querySelector('ul'));
29
-
30
26
  // members
31
27
  this.defaultDir = '';
32
28
  this.alignIcons = {
@@ -35,10 +31,13 @@ class Align extends PluginDropdown {
35
31
  right: this.$.icons.align_right,
36
32
  center: this.$.icons.align_center,
37
33
  };
38
- this.alignList = commandArea.querySelectorAll('li button');
39
34
 
40
- // init
41
- this.$.menu.initDropdownTarget(Align, menu);
35
+ // create menu from items
36
+ const menu = this.$.menu.initDropdownTarget(Align, CreateItems(this.$, pluginOptions.items), {
37
+ className: 'se-list-align',
38
+ });
39
+ this._itemMenu = menu.querySelector('ul');
40
+ this.alignList = menu.querySelectorAll('li button');
42
41
  }
43
42
 
44
43
  /**
@@ -139,33 +138,22 @@ class Align extends PluginDropdown {
139
138
  /**
140
139
  * @param {SunEditor.Deps} $ - Kernel dependencies
141
140
  * @param {string[]} [items] - Align items list
142
- * @returns {HTMLElement}
141
+ * @returns {Array<import('../../core/logic/panel/menu').DropdownItem>}
143
142
  */
144
- function CreateHTML({ lang, icons, options }, items) {
145
- const alignItems = Array.isArray(items) ? items : options.get('_rtl') ? ['right', 'center', 'left', 'justify'] : ['left', 'center', 'right', 'justify'];
146
-
147
- let html = '';
148
- for (let i = 0, item, text; i < alignItems.length; i++) {
149
- item = alignItems[i];
150
- text = lang['align' + item.charAt(0).toUpperCase() + item.slice(1)];
151
- html += /*html*/ `
152
- <li>
153
- <button type="button" class="se-btn se-btn-list" data-command="${item}" title="${text}" aria-label="${text}">
154
- <span class="se-list-icon">${icons['align_' + item]}</span>${text}
155
- </button>
156
- </li>`;
157
- }
158
-
159
- return dom.utils.createElement(
160
- 'div',
161
- {
162
- class: 'se-dropdown se-list-layer se-list-align',
163
- },
164
- /*html*/ `
165
- <div class="se-list-inner">
166
- <ul class="se-list-basic">${html}</ul>
167
- </div>`,
168
- );
143
+ function CreateItems({ lang, icons, options }, items) {
144
+ const alignItems = Array.isArray(items)
145
+ ? items
146
+ : options.get('_rtl')
147
+ ? ['right', 'center', 'left', 'justify']
148
+ : ['left', 'center', 'right', 'justify'];
149
+ return alignItems.map((item) => {
150
+ const text = lang['align' + item.charAt(0).toUpperCase() + item.slice(1)];
151
+ return {
152
+ command: item,
153
+ title: text,
154
+ innerHTML: `<span class="se-list-icon">${icons['align_' + item]}</span>${text}`,
155
+ };
156
+ });
169
157
  }
170
158
 
171
159
  export default Align;
@@ -92,9 +92,17 @@ class BackgroundColor extends PluginDropdownFree {
92
92
  colorPickerAction(color) {
93
93
  if (color) {
94
94
  const newNode = dom.utils.createElement('SPAN', { style: 'background-color: ' + color + ';' });
95
- this.$.inline.apply(newNode, { stylesToModify: ['background-color'], nodesToRemove: null, strictRemove: null });
95
+ this.$.inline.apply(newNode, {
96
+ stylesToModify: ['background-color'],
97
+ nodesToRemove: null,
98
+ strictRemove: null,
99
+ });
96
100
  } else {
97
- this.$.inline.apply(null, { stylesToModify: ['background-color'], nodesToRemove: ['span'], strictRemove: true });
101
+ this.$.inline.apply(null, {
102
+ stylesToModify: ['background-color'],
103
+ nodesToRemove: ['span'],
104
+ strictRemove: true,
105
+ });
98
106
  }
99
107
 
100
108
  this.$.menu.dropdownOff();