suneditor 3.0.0-alpha.9 → 3.0.0-beta.2

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 (315) hide show
  1. package/CONTRIBUTING.md +170 -22
  2. package/{LICENSE.txt → LICENSE} +9 -9
  3. package/README.md +168 -30
  4. package/dist/suneditor.min.css +1 -1
  5. package/dist/suneditor.min.js +1 -1
  6. package/package.json +47 -21
  7. package/src/assets/design/color.css +121 -0
  8. package/src/assets/design/index.css +3 -0
  9. package/src/assets/design/size.css +35 -0
  10. package/src/assets/design/typography.css +37 -0
  11. package/src/assets/icons/defaultIcons.js +232 -0
  12. package/src/assets/suneditor-contents.css +181 -46
  13. package/src/assets/suneditor.css +1403 -650
  14. package/src/core/base/eventHandlers/handler_toolbar.js +35 -14
  15. package/src/core/base/eventHandlers/handler_ww_clipboard.js +23 -4
  16. package/src/core/base/eventHandlers/handler_ww_dragDrop.js +49 -10
  17. package/src/core/base/eventHandlers/handler_ww_key_input.js +422 -224
  18. package/src/core/base/eventHandlers/handler_ww_mouse.js +83 -36
  19. package/src/core/base/eventManager.js +520 -179
  20. package/src/core/base/history.js +95 -41
  21. package/src/core/class/char.js +26 -11
  22. package/src/core/class/component.js +345 -137
  23. package/src/core/class/format.js +683 -519
  24. package/src/core/class/html.js +485 -305
  25. package/src/core/class/menu.js +133 -47
  26. package/src/core/class/nodeTransform.js +90 -71
  27. package/src/core/class/offset.js +408 -92
  28. package/src/core/class/selection.js +216 -106
  29. package/src/core/class/shortcuts.js +68 -8
  30. package/src/core/class/toolbar.js +106 -116
  31. package/src/core/class/ui.js +422 -0
  32. package/src/core/class/viewer.js +178 -74
  33. package/src/core/editor.js +496 -389
  34. package/src/core/section/actives.js +123 -27
  35. package/src/core/section/constructor.js +615 -206
  36. package/src/core/section/context.js +28 -23
  37. package/src/core/section/documentType.js +561 -0
  38. package/src/editorInjector/_classes.js +19 -5
  39. package/src/editorInjector/_core.js +71 -7
  40. package/src/editorInjector/index.js +63 -1
  41. package/src/events.js +622 -0
  42. package/src/helper/clipboard.js +59 -0
  43. package/src/helper/converter.js +202 -26
  44. package/src/helper/dom/domCheck.js +304 -0
  45. package/src/helper/dom/domQuery.js +669 -0
  46. package/src/helper/dom/domUtils.js +557 -0
  47. package/src/helper/dom/index.js +12 -0
  48. package/src/helper/env.js +46 -56
  49. package/src/helper/index.js +10 -4
  50. package/src/helper/keyCodeMap.js +183 -0
  51. package/src/helper/numbers.js +12 -8
  52. package/src/helper/unicode.js +9 -5
  53. package/src/langs/ckb.js +74 -4
  54. package/src/langs/cs.js +72 -2
  55. package/src/langs/da.js +73 -3
  56. package/src/langs/de.js +73 -4
  57. package/src/langs/en.js +23 -3
  58. package/src/langs/es.js +73 -4
  59. package/src/langs/fa.js +75 -3
  60. package/src/langs/fr.js +73 -3
  61. package/src/langs/he.js +73 -4
  62. package/src/langs/hu.js +230 -0
  63. package/src/langs/index.js +7 -3
  64. package/src/langs/it.js +70 -1
  65. package/src/langs/ja.js +72 -4
  66. package/src/langs/km.js +230 -0
  67. package/src/langs/ko.js +22 -2
  68. package/src/langs/lv.js +74 -5
  69. package/src/langs/nl.js +73 -4
  70. package/src/langs/pl.js +73 -4
  71. package/src/langs/pt_br.js +70 -1
  72. package/src/langs/ro.js +74 -5
  73. package/src/langs/ru.js +73 -4
  74. package/src/langs/se.js +73 -4
  75. package/src/langs/tr.js +73 -1
  76. package/src/langs/{ua.js → uk.js} +75 -6
  77. package/src/langs/ur.js +77 -8
  78. package/src/langs/zh_cn.js +74 -5
  79. package/src/modules/ApiManager.js +77 -54
  80. package/src/modules/Browser.js +667 -0
  81. package/src/modules/ColorPicker.js +162 -102
  82. package/src/modules/Controller.js +273 -142
  83. package/src/modules/Figure.js +925 -484
  84. package/src/modules/FileManager.js +121 -69
  85. package/src/modules/HueSlider.js +113 -61
  86. package/src/modules/Modal.js +291 -122
  87. package/src/modules/ModalAnchorEditor.js +383 -234
  88. package/src/modules/SelectMenu.js +270 -168
  89. package/src/modules/_DragHandle.js +2 -1
  90. package/src/modules/index.js +3 -3
  91. package/src/plugins/browser/audioGallery.js +83 -0
  92. package/src/plugins/browser/fileBrowser.js +103 -0
  93. package/src/plugins/browser/fileGallery.js +83 -0
  94. package/src/plugins/browser/imageGallery.js +81 -0
  95. package/src/plugins/browser/videoGallery.js +103 -0
  96. package/src/plugins/command/blockquote.js +40 -27
  97. package/src/plugins/command/exportPDF.js +134 -0
  98. package/src/plugins/command/fileUpload.js +229 -162
  99. package/src/plugins/command/list_bulleted.js +83 -47
  100. package/src/plugins/command/list_numbered.js +83 -47
  101. package/src/plugins/dropdown/align.js +66 -54
  102. package/src/plugins/dropdown/backgroundColor.js +63 -49
  103. package/src/plugins/dropdown/font.js +71 -47
  104. package/src/plugins/dropdown/fontColor.js +63 -48
  105. package/src/plugins/dropdown/formatBlock.js +70 -33
  106. package/src/plugins/dropdown/hr.js +92 -51
  107. package/src/plugins/dropdown/layout.js +37 -26
  108. package/src/plugins/dropdown/lineHeight.js +54 -38
  109. package/src/plugins/dropdown/list.js +60 -45
  110. package/src/plugins/dropdown/paragraphStyle.js +51 -30
  111. package/src/plugins/dropdown/table.js +2003 -813
  112. package/src/plugins/dropdown/template.js +38 -26
  113. package/src/plugins/dropdown/textStyle.js +43 -31
  114. package/src/plugins/field/mention.js +147 -86
  115. package/src/plugins/index.js +32 -6
  116. package/src/plugins/input/fontSize.js +161 -108
  117. package/src/plugins/input/pageNavigator.js +70 -0
  118. package/src/plugins/modal/audio.js +358 -173
  119. package/src/plugins/modal/drawing.js +531 -0
  120. package/src/plugins/modal/embed.js +886 -0
  121. package/src/plugins/modal/image.js +674 -362
  122. package/src/plugins/modal/link.js +100 -71
  123. package/src/plugins/modal/math.js +367 -167
  124. package/src/plugins/modal/video.js +691 -335
  125. package/src/plugins/popup/anchor.js +222 -0
  126. package/src/suneditor.js +50 -13
  127. package/src/themes/dark.css +122 -0
  128. package/src/typedef.js +130 -0
  129. package/types/assets/icons/defaultIcons.d.ts +153 -0
  130. package/types/core/base/eventHandlers/handler_toolbar.d.ts +41 -0
  131. package/types/core/base/eventHandlers/handler_ww_clipboard.d.ts +40 -0
  132. package/types/core/base/eventHandlers/handler_ww_dragDrop.d.ts +35 -0
  133. package/types/core/base/eventHandlers/handler_ww_key_input.d.ts +45 -0
  134. package/types/core/base/eventHandlers/handler_ww_mouse.d.ts +39 -0
  135. package/types/core/base/eventManager.d.ts +385 -0
  136. package/types/core/base/history.d.ts +81 -0
  137. package/types/core/class/char.d.ts +60 -0
  138. package/types/core/class/component.d.ts +212 -0
  139. package/types/core/class/format.d.ts +616 -0
  140. package/types/core/class/html.d.ts +422 -0
  141. package/types/core/class/menu.d.ts +126 -0
  142. package/types/core/class/nodeTransform.d.ts +93 -0
  143. package/types/core/class/offset.d.ts +522 -0
  144. package/types/core/class/selection.d.ts +188 -0
  145. package/types/core/class/shortcuts.d.ts +142 -0
  146. package/types/core/class/toolbar.d.ts +189 -0
  147. package/types/core/class/ui.d.ts +164 -0
  148. package/types/core/class/viewer.d.ts +140 -0
  149. package/types/core/editor.d.ts +610 -0
  150. package/types/core/section/actives.d.ts +46 -0
  151. package/types/core/section/constructor.d.ts +777 -0
  152. package/types/core/section/context.d.ts +45 -0
  153. package/types/core/section/documentType.d.ts +178 -0
  154. package/types/editorInjector/_classes.d.ts +41 -0
  155. package/types/editorInjector/_core.d.ts +92 -0
  156. package/types/editorInjector/index.d.ts +71 -0
  157. package/types/events.d.ts +273 -0
  158. package/types/helper/clipboard.d.ts +12 -0
  159. package/types/helper/converter.d.ts +197 -0
  160. package/types/helper/dom/domCheck.d.ts +189 -0
  161. package/types/helper/dom/domQuery.d.ts +223 -0
  162. package/types/helper/dom/domUtils.d.ts +226 -0
  163. package/types/helper/dom/index.d.ts +9 -0
  164. package/types/helper/env.d.ts +132 -0
  165. package/types/helper/index.d.ts +174 -0
  166. package/types/helper/keyCodeMap.d.ts +110 -0
  167. package/types/helper/numbers.d.ts +46 -0
  168. package/types/helper/unicode.d.ts +28 -0
  169. package/types/index.d.ts +120 -0
  170. package/{typings/Lang.d.ts → types/langs/_Lang.d.ts} +173 -103
  171. package/types/langs/ckb.d.ts +3 -0
  172. package/types/langs/cs.d.ts +3 -0
  173. package/types/langs/da.d.ts +3 -0
  174. package/types/langs/de.d.ts +3 -0
  175. package/types/langs/en.d.ts +3 -0
  176. package/types/langs/es.d.ts +3 -0
  177. package/types/langs/fa.d.ts +3 -0
  178. package/types/langs/fr.d.ts +3 -0
  179. package/types/langs/he.d.ts +3 -0
  180. package/types/langs/hu.d.ts +3 -0
  181. package/types/langs/index.d.ts +54 -0
  182. package/types/langs/it.d.ts +3 -0
  183. package/types/langs/ja.d.ts +3 -0
  184. package/types/langs/km.d.ts +3 -0
  185. package/types/langs/ko.d.ts +3 -0
  186. package/types/langs/lv.d.ts +3 -0
  187. package/types/langs/nl.d.ts +3 -0
  188. package/types/langs/pl.d.ts +3 -0
  189. package/types/langs/pt_br.d.ts +3 -0
  190. package/types/langs/ro.d.ts +3 -0
  191. package/types/langs/ru.d.ts +3 -0
  192. package/types/langs/se.d.ts +3 -0
  193. package/types/langs/tr.d.ts +3 -0
  194. package/types/langs/uk.d.ts +3 -0
  195. package/types/langs/ur.d.ts +3 -0
  196. package/types/langs/zh_cn.d.ts +3 -0
  197. package/types/modules/ApiManager.d.ts +125 -0
  198. package/types/modules/Browser.d.ts +326 -0
  199. package/types/modules/ColorPicker.d.ts +131 -0
  200. package/types/modules/Controller.d.ts +251 -0
  201. package/types/modules/Figure.d.ts +517 -0
  202. package/types/modules/FileManager.d.ts +202 -0
  203. package/types/modules/HueSlider.d.ts +136 -0
  204. package/types/modules/Modal.d.ts +111 -0
  205. package/types/modules/ModalAnchorEditor.d.ts +236 -0
  206. package/types/modules/SelectMenu.d.ts +194 -0
  207. package/types/modules/_DragHandle.d.ts +7 -0
  208. package/types/modules/index.d.ts +26 -0
  209. package/types/plugins/browser/audioGallery.d.ts +55 -0
  210. package/types/plugins/browser/fileBrowser.d.ts +64 -0
  211. package/types/plugins/browser/fileGallery.d.ts +55 -0
  212. package/types/plugins/browser/imageGallery.d.ts +51 -0
  213. package/types/plugins/browser/videoGallery.d.ts +57 -0
  214. package/types/plugins/command/blockquote.d.ts +28 -0
  215. package/types/plugins/command/exportPDF.d.ts +46 -0
  216. package/types/plugins/command/fileUpload.d.ts +156 -0
  217. package/types/plugins/command/list_bulleted.d.ts +46 -0
  218. package/types/plugins/command/list_numbered.d.ts +46 -0
  219. package/types/plugins/dropdown/align.d.ts +60 -0
  220. package/types/plugins/dropdown/backgroundColor.d.ts +63 -0
  221. package/types/plugins/dropdown/font.d.ts +54 -0
  222. package/types/plugins/dropdown/fontColor.d.ts +63 -0
  223. package/types/plugins/dropdown/formatBlock.d.ts +54 -0
  224. package/types/plugins/dropdown/hr.d.ts +71 -0
  225. package/types/plugins/dropdown/layout.d.ts +40 -0
  226. package/types/plugins/dropdown/lineHeight.d.ts +50 -0
  227. package/types/plugins/dropdown/list.d.ts +39 -0
  228. package/types/plugins/dropdown/paragraphStyle.d.ts +54 -0
  229. package/types/plugins/dropdown/table.d.ts +627 -0
  230. package/types/plugins/dropdown/template.d.ts +40 -0
  231. package/types/plugins/dropdown/textStyle.d.ts +41 -0
  232. package/types/plugins/field/mention.d.ts +102 -0
  233. package/types/plugins/index.d.ts +107 -0
  234. package/types/plugins/input/fontSize.d.ts +170 -0
  235. package/types/plugins/input/pageNavigator.d.ts +28 -0
  236. package/types/plugins/modal/audio.d.ts +269 -0
  237. package/types/plugins/modal/drawing.d.ts +246 -0
  238. package/types/plugins/modal/embed.d.ts +387 -0
  239. package/types/plugins/modal/image.d.ts +451 -0
  240. package/types/plugins/modal/link.d.ts +128 -0
  241. package/types/plugins/modal/math.d.ts +193 -0
  242. package/types/plugins/modal/video.d.ts +485 -0
  243. package/types/plugins/popup/anchor.d.ts +56 -0
  244. package/types/suneditor.d.ts +51 -0
  245. package/types/typedef.d.ts +233 -0
  246. package/.eslintignore +0 -7
  247. package/.eslintrc.json +0 -64
  248. package/src/assets/icons/_default.js +0 -194
  249. package/src/core/base/events.js +0 -320
  250. package/src/core/class/notice.js +0 -42
  251. package/src/helper/domUtils.js +0 -1177
  252. package/src/modules/FileBrowser.js +0 -271
  253. package/src/plugins/command/exportPdf.js +0 -168
  254. package/src/plugins/fileBrowser/imageGallery.js +0 -81
  255. package/src/themes/test.css +0 -61
  256. package/typings/CommandPlugin.d.ts +0 -8
  257. package/typings/DialogPlugin.d.ts +0 -20
  258. package/typings/FileBrowserPlugin.d.ts +0 -30
  259. package/typings/Module.d.ts +0 -15
  260. package/typings/Plugin.d.ts +0 -42
  261. package/typings/SubmenuPlugin.d.ts +0 -8
  262. package/typings/_classes.d.ts +0 -17
  263. package/typings/_colorPicker.d.ts +0 -60
  264. package/typings/_core.d.ts +0 -55
  265. package/typings/align.d.ts +0 -5
  266. package/typings/audio.d.ts +0 -5
  267. package/typings/backgroundColor.d.ts +0 -5
  268. package/typings/blockquote.d.ts +0 -5
  269. package/typings/char.d.ts +0 -39
  270. package/typings/component.d.ts +0 -38
  271. package/typings/context.d.ts +0 -39
  272. package/typings/converter.d.ts +0 -33
  273. package/typings/dialog.d.ts +0 -28
  274. package/typings/domUtils.d.ts +0 -361
  275. package/typings/editor.d.ts +0 -7
  276. package/typings/editor.ts +0 -542
  277. package/typings/env.d.ts +0 -70
  278. package/typings/eventManager.d.ts +0 -37
  279. package/typings/events.d.ts +0 -262
  280. package/typings/fileBrowser.d.ts +0 -42
  281. package/typings/fileManager.d.ts +0 -67
  282. package/typings/font.d.ts +0 -5
  283. package/typings/fontColor.d.ts +0 -5
  284. package/typings/fontSize.d.ts +0 -5
  285. package/typings/format.d.ts +0 -191
  286. package/typings/formatBlock.d.ts +0 -5
  287. package/typings/history.d.ts +0 -48
  288. package/typings/horizontalRule.d.ts +0 -5
  289. package/typings/image.d.ts +0 -5
  290. package/typings/imageGallery.d.ts +0 -5
  291. package/typings/index.d.ts +0 -21
  292. package/typings/index.modules.d.ts +0 -11
  293. package/typings/index.plugins.d.ts +0 -58
  294. package/typings/lineHeight.d.ts +0 -5
  295. package/typings/link.d.ts +0 -5
  296. package/typings/list.d.ts +0 -5
  297. package/typings/math.d.ts +0 -5
  298. package/typings/mediaContainer.d.ts +0 -25
  299. package/typings/mention.d.ts +0 -5
  300. package/typings/node.d.ts +0 -57
  301. package/typings/notice.d.ts +0 -16
  302. package/typings/numbers.d.ts +0 -29
  303. package/typings/offset.d.ts +0 -24
  304. package/typings/options.d.ts +0 -589
  305. package/typings/paragraphStyle.d.ts +0 -5
  306. package/typings/resizing.d.ts +0 -141
  307. package/typings/selection.d.ts +0 -94
  308. package/typings/shortcuts.d.ts +0 -13
  309. package/typings/suneditor.d.ts +0 -9
  310. package/typings/table.d.ts +0 -5
  311. package/typings/template.d.ts +0 -5
  312. package/typings/textStyle.d.ts +0 -5
  313. package/typings/toolbar.d.ts +0 -32
  314. package/typings/unicode.d.ts +0 -25
  315. package/typings/video.d.ts +0 -5
@@ -1,122 +1,163 @@
1
1
  import EditorInjector from '../editorInjector';
2
2
  import SelectMenu from './SelectMenu';
3
3
  import FileManager from './FileManager';
4
- import { domUtils, numbers, env, unicode } from '../helper';
5
- import { CreateTooltipInner } from '../core/section/constructor';
4
+ import { dom, numbers, env, unicode } from '../helper';
6
5
  const { NO_EVENT } = env;
7
6
 
8
7
  /**
9
- * @param {*} inst
10
- * @param {Element} modalForm
11
- * @param {object} params
12
- * @param {boolean} params.textToDisplay - Create Text to display input.
13
- * @param {string} params.title - Modal title
14
- * @param {boolean} params.openNewWindow - Default checked value of the "Open in new window" checkbox.
15
- * @param {boolean} params.relList - The "rel" attribute list of anchor tag.
16
- * @param {object} params.defaultRel - Default "rel" attributes of anchor tag.
17
- * @param {boolean} params.noAutoPrefix - If true, disables the automatic prefixing of the host URL to the value of the link.
18
- Example:
8
+ * @typedef {{default?: string, check_new_window?: string, check_bookmark?: string}} RELAttr
9
+ */
10
+
11
+ /**
12
+ * @typedef {Object} ModalAnchorEditorParams
13
+ * @property {boolean} [title=false] - Modal title display.
14
+ * @property {boolean} [textToDisplay=''] - Create Text to display input.
15
+ * @property {boolean} [openNewWindow=false] - Default checked value of the "Open in new window" checkbox.
16
+ * @property {boolean} [noAutoPrefix=false] - If true, disables the automatic prefixing of the host URL to the value of the link.
17
+ * @property {Array<string>} [relList=[]] - The "rel" attribute list of anchor tag.
18
+ * @property {RELAttr} [defaultRel={}] - Default "rel" attributes of anchor tag.
19
+ * @property {string=} uploadUrl - File upload URL.
20
+ * @property {Object<string, string>=} uploadHeaders - File upload headers.
21
+ * @property {number=} uploadSizeLimit - File upload size limit.
22
+ * @property {number=} uploadSingleSizeLimit - File upload single size limit.
23
+ * @property {string=} acceptedFormats - File upload accepted formats.
24
+ * @property {boolean=} enableFileUpload - If true, enables file upload.
25
+ * @example "REL" structure
19
26
  {
20
27
  default: 'nofollow', // Default rel
21
28
  check_new_window: 'noreferrer noopener', // When "open new window" is checked
22
29
  check_bookmark: 'bookmark' // When "bookmark" is checked
23
30
  }
24
- * @param {boolean} params.noAutoPrefix - If true, disables the automatic prefixing of the host URL to the value of the link.
31
+ If true, disables the automatic prefixing of the host URL to the value of the link.
25
32
  */
26
- const ModalAnchorEditor = function (inst, modalForm, params) {
27
- // plugin bisic properties
28
- EditorInjector.call(this, inst.editor);
29
-
30
- // params
31
- this.openNewWindow = !!params.openNewWindow;
32
- this.relList = Array.isArray(params.relList) ? params.relList : [];
33
- this.defaultRel = params.defaultRel || {};
34
- this.noAutoPrefix = !!params.noAutoPrefix;
35
- // file upload
36
- if (params.enableFileUpload) {
37
- this.uploadUrl = typeof params.uploadUrl === 'string' ? params.uploadUrl : null;
38
- this.uploadHeaders = params.uploadHeaders || null;
39
- this.uploadSizeLimit = /\d+/.test(params.uploadSizeLimit) ? numbers.get(params.uploadSizeLimit, 0) : null;
40
- this.uploadSingleSizeLimit = /\d+/.test(params.uploadSingleSizeLimit) ? numbers.get(params.uploadSingleSizeLimit, 0) : null;
41
- this.input = domUtils.createElement('input', { type: 'file', accept: params.acceptedFormats || '*' });
42
- this.eventManager.addEvent(this.input, 'change', OnChangeFile.bind(this));
43
- // file manager
44
- this.fileManager = new FileManager(this, {
45
- query: 'a[download]:not([data-se-file-download])',
46
- loadHandler: this.events.onFileLoad,
47
- eventHandler: this.events.onFileAction
48
- });
49
- }
50
33
 
51
- // create HTML
52
- const forms = CreatetModalForm(inst.editor, params, this.relList);
53
-
54
- // members
55
- this.kink = inst.constructor.key || inst.constructor.name;
56
- this.inst = inst;
57
- this.modalForm = modalForm;
58
- this.host = (this._w.location.origin + this._w.location.pathname).replace(/\/$/, '');
59
- this.urlInput = forms.querySelector('.se-input-url');
60
- this.displayInput = forms.querySelector('._se_display_text');
61
- this.titleInput = forms.querySelector('._se_title');
62
- this.newWindowCheck = forms.querySelector('._se_anchor_check');
63
- this.downloadCheck = forms.querySelector('._se_anchor_download');
64
- this.download = forms.querySelector('._se_anchor_download_icon');
65
- this.preview = forms.querySelector('.se-link-preview');
66
- this.bookmark = forms.querySelector('._se_anchor_bookmark_icon');
67
- this.bookmarkButton = forms.querySelector('._se_bookmark_button');
68
- this.currentRel = [];
69
- this.currentTarget = null;
70
- this.linkValue = '';
71
- this._change = false;
72
- this._isRel = this.relList.length > 0;
73
- // members - rel
74
- if (this._isRel) {
75
- this.relButton = forms.querySelector('.se-anchor-rel-btn');
76
- this.relPreview = forms.querySelector('.se-anchor-rel-preview');
77
- const relList = this.relList;
78
- const defaultRel = (this.defaultRel.default || '').split(' ');
79
- const list = [];
80
- for (let i = 0, len = relList.length, rel; i < len; i++) {
81
- rel = relList[i];
82
- list.push(
83
- domUtils.createElement(
84
- 'BUTTON',
85
- {
86
- type: 'button',
87
- class: 'se-btn-list' + (defaultRel.includes(rel) ? ' se-checked' : ''),
88
- 'data-command': rel,
89
- title: rel,
90
- 'aria-label': rel
91
- },
92
- rel + '<span class="se-svg">' + this.icons.checked + '</span>'
93
- )
94
- );
34
+ /**
35
+ * @class
36
+ * @description Modal form Anchor tag editor
37
+ * - Use it by inserting it into Modal in a plugin that uses Modal.
38
+ */
39
+ class ModalAnchorEditor extends EditorInjector {
40
+ /**
41
+ * @constructor
42
+ * @param {*} inst The instance object that called the constructor.
43
+ * @param {Node} modalForm The modal form element
44
+ * @param {ModalAnchorEditorParams} params ModalAnchorEditor options
45
+ */
46
+ constructor(inst, modalForm, params) {
47
+ // plugin bisic properties
48
+ super(inst.editor);
49
+
50
+ // params
51
+ this.openNewWindow = !!params.openNewWindow;
52
+ this.relList = Array.isArray(params.relList) ? params.relList : [];
53
+ this.defaultRel = params.defaultRel || {};
54
+ this.noAutoPrefix = !!params.noAutoPrefix;
55
+ // file upload
56
+ if (params.enableFileUpload) {
57
+ this.uploadUrl = typeof params.uploadUrl === 'string' ? params.uploadUrl : null;
58
+ this.uploadHeaders = params.uploadHeaders || null;
59
+ this.uploadSizeLimit = numbers.get(params.uploadSizeLimit, 0) || null;
60
+ this.uploadSingleSizeLimit = numbers.get(params.uploadSingleSizeLimit, 0) || null;
61
+ this.input = dom.utils.createElement('input', { type: 'file', accept: params.acceptedFormats || '*' });
62
+ this.eventManager.addEvent(this.input, 'change', this.#OnChangeFile.bind(this));
63
+ // file manager
64
+ this.fileManager = new FileManager(this, {
65
+ query: 'a[download]:not([data-se-file-download])',
66
+ loadHandler: this.events.onFileLoad,
67
+ eventHandler: this.events.onFileAction
68
+ });
95
69
  }
96
- this.selectMenu_rel = new SelectMenu(this, { checkList: true, position: 'right-middle', dir: 'ltr' });
97
- this.selectMenu_rel.on(this.relButton, SetRelItem.bind(this));
98
- this.selectMenu_rel.create(list);
99
- this.eventManager.addEvent(this.relButton, 'click', OnClick_relbutton.bind(this));
100
- }
101
70
 
102
- // init
103
- modalForm.querySelector('.se-anchor-editor').appendChild(forms);
104
- this.selectMenu_bookmark = new SelectMenu(this, { checkList: false, position: 'bottom-left', dir: 'ltr' });
105
- this.selectMenu_bookmark.on(this.urlInput, SetHeaderBookmark.bind(this));
106
- this.eventManager.addEvent(this.newWindowCheck, 'change', OnChange_newWindowCheck.bind(this));
107
- this.eventManager.addEvent(this.downloadCheck, 'change', OnChange_downloadCheck.bind(this));
108
- this.eventManager.addEvent(this.displayInput, 'input', OnChange_displayInput.bind(this));
109
- this.eventManager.addEvent(this.urlInput, 'input', OnChange_urlInput.bind(this));
110
- this.eventManager.addEvent(this.urlInput, 'focus', OnFocus_urlInput.bind(this));
111
- this.eventManager.addEvent(this.bookmarkButton, 'click', OnClick_bookmarkButton.bind(this));
112
- this.eventManager.addEvent(forms.querySelector('._se_upload_button'), 'click', () => this.input.click());
113
- };
114
-
115
- ModalAnchorEditor.prototype = {
71
+ // create HTML
72
+ const forms = CreatetModalForm(inst.editor, params, this.relList);
73
+
74
+ // members
75
+ this.kink = inst.constructor.key || inst.constructor.name;
76
+ this.inst = inst;
77
+ this.modalForm = /** @type {HTMLElement} */ (modalForm);
78
+ this.host = (this._w.location.origin + this._w.location.pathname).replace(/\/$/, '');
79
+
80
+ /** @type {HTMLInputElement} */
81
+ this.urlInput = forms.querySelector('.se-input-url');
82
+ /** @type {HTMLInputElement} */
83
+ this.displayInput = forms.querySelector('._se_display_text');
84
+ /** @type {HTMLInputElement} */
85
+ this.titleInput = forms.querySelector('._se_title');
86
+ /** @type {HTMLInputElement} */
87
+ this.newWindowCheck = forms.querySelector('._se_anchor_check');
88
+ /** @type {HTMLInputElement} */
89
+ this.downloadCheck = forms.querySelector('._se_anchor_download');
90
+ /** @type {HTMLElement} */
91
+ this.download = forms.querySelector('._se_anchor_download_icon');
92
+ /** @type {HTMLElement} */
93
+ this.preview = forms.querySelector('.se-link-preview');
94
+ /** @type {HTMLElement} */
95
+ this.bookmark = forms.querySelector('._se_anchor_bookmark_icon');
96
+ /** @type {HTMLButtonElement} */
97
+ this.bookmarkButton = forms.querySelector('._se_bookmark_button');
98
+
99
+ this.currentRel = [];
100
+ this.currentTarget = null;
101
+ this.linkValue = '';
102
+ this._change = false;
103
+ this._isRel = this.relList.length > 0;
104
+ // members - rel
105
+ if (this._isRel) {
106
+ /** @type {HTMLButtonElement} */
107
+ this.relButton = forms.querySelector('.se-anchor-rel-btn');
108
+ /** @type {HTMLElement} */
109
+ this.relPreview = forms.querySelector('.se-anchor-rel-preview');
110
+
111
+ const relList = this.relList;
112
+ const defaultRel = (this.defaultRel.default || '').split(' ');
113
+ const list = [];
114
+ for (let i = 0, len = relList.length, rel; i < len; i++) {
115
+ rel = relList[i];
116
+ list.push(
117
+ dom.utils.createElement(
118
+ 'BUTTON',
119
+ {
120
+ type: 'button',
121
+ class: 'se-btn-list' + (defaultRel.includes(rel) ? ' se-checked' : ''),
122
+ 'data-command': rel,
123
+ title: rel,
124
+ 'aria-label': rel
125
+ },
126
+ rel + '<span class="se-svg">' + this.icons.checked + '</span>'
127
+ )
128
+ );
129
+ }
130
+ this.selectMenu_rel = new SelectMenu(this, { checkList: true, position: 'right-middle', dir: 'ltr' });
131
+ this.selectMenu_rel.on(this.relButton, this.#SetRelItem.bind(this));
132
+ this.selectMenu_rel.create(list);
133
+ this.eventManager.addEvent(this.relButton, 'click', this.#OnClick_relbutton.bind(this));
134
+ }
135
+
136
+ // init
137
+ this.modalForm.querySelector('.se-anchor-editor').appendChild(forms);
138
+ this.selectMenu_bookmark = new SelectMenu(this, { checkList: false, position: 'bottom-left', dir: 'ltr' });
139
+ this.selectMenu_bookmark.on(this.urlInput, this.#SetHeaderBookmark.bind(this));
140
+ this.eventManager.addEvent(this.newWindowCheck, 'change', this.#OnChange_newWindowCheck.bind(this));
141
+ this.eventManager.addEvent(this.downloadCheck, 'change', this.#OnChange_downloadCheck.bind(this));
142
+ this.eventManager.addEvent(this.displayInput, 'input', this.#OnChange_displayInput.bind(this));
143
+ this.eventManager.addEvent(this.urlInput, 'input', this.#OnChange_urlInput.bind(this));
144
+ this.eventManager.addEvent(this.urlInput, 'focus', this.#OnFocus_urlInput.bind(this));
145
+ this.eventManager.addEvent(this.bookmarkButton, 'click', this.#OnClick_bookmarkButton.bind(this));
146
+ this.eventManager.addEvent(forms.querySelector('._se_upload_button'), 'click', () => this.input.click());
147
+ }
148
+ /**
149
+ * @description Initialize.
150
+ * - Sets the current anchor element to be edited.
151
+ * @param {Node} element Modal target element
152
+ */
116
153
  set(element) {
117
- this.currentTarget = element;
118
- },
154
+ this.currentTarget = /** @type {HTMLAnchorElement} */ (element);
155
+ }
119
156
 
157
+ /**
158
+ * @description Opens the anchor editor modal and populates it with data.
159
+ * @param {boolean} isUpdate - Indicates whether an existing anchor is being updated (`true`) or a new one is being created (`false`).
160
+ */
120
161
  on(isUpdate) {
121
162
  if (!isUpdate) {
122
163
  this.init();
@@ -124,31 +165,39 @@ ModalAnchorEditor.prototype = {
124
165
  this.newWindowCheck.checked = this.openNewWindow;
125
166
  this.titleInput.value = '';
126
167
  } else if (this.currentTarget) {
127
- const href = this.currentTarget.getAttribute('href');
128
- this.linkValue = this.preview.textContent = this.urlInput.value = this._selfPathBookmark(href) ? href.substr(href.lastIndexOf('#')) : href;
168
+ const href = this.currentTarget.href;
169
+ this.linkValue = this.preview.textContent = this.urlInput.value = this._selfPathBookmark(href) ? href.substring(href.lastIndexOf('#')) : href;
129
170
  this.displayInput.value = this.currentTarget.textContent;
130
171
  this.titleInput.value = this.currentTarget.title;
131
172
  this.newWindowCheck.checked = /_blank/i.test(this.currentTarget.target) ? true : false;
132
- this.downloadCheck.checked = this.currentTarget.download;
173
+ this.downloadCheck.checked = !!this.currentTarget.download;
133
174
  }
134
175
 
135
176
  this._setRel(isUpdate && this.currentTarget ? this.currentTarget.rel : this.defaultRel.default || '');
136
177
  this._setLinkPreview(this.linkValue);
137
- },
178
+ }
138
179
 
180
+ /**
181
+ * @description Creates an anchor (`<a>`) element with the specified attributes.
182
+ * @param {boolean} notText - If `true`, the anchor will not contain text content.
183
+ * @returns {HTMLElement|null} - The newly created anchor element, or `null` if the URL is empty.
184
+ */
139
185
  create(notText) {
140
186
  if (this.linkValue.length === 0) return null;
141
187
 
142
188
  const url = this.linkValue;
143
189
  const displayText = this.displayInput.value.length === 0 ? url : this.displayInput.value;
144
190
 
145
- const oA = this.currentTarget || domUtils.createElement('A');
191
+ const oA = /** @type {HTMLAnchorElement} */ (this.currentTarget || dom.utils.createElement('A'));
146
192
  this._updateAnchor(oA, url, displayText, this.titleInput.value, notText);
147
193
  this.linkValue = this.preview.textContent = this.urlInput.value = this.displayInput.value = '';
148
194
 
149
195
  return oA;
150
- },
196
+ }
151
197
 
198
+ /**
199
+ * @description Resets the ModalAnchorEditor to its initial state.
200
+ */
152
201
  init() {
153
202
  this.currentTarget = null;
154
203
  this.linkValue = this.preview.textContent = this.urlInput.value = '';
@@ -157,8 +206,17 @@ ModalAnchorEditor.prototype = {
157
206
  this.downloadCheck.checked = false;
158
207
  this._change = false;
159
208
  this._setRel(this.defaultRel.default || '');
160
- },
209
+ }
161
210
 
211
+ /**
212
+ * @private
213
+ * @description Updates the anchor element with new attributes.
214
+ * @param {HTMLAnchorElement} anchor - The anchor (`<a>`) element to update.
215
+ * @param {string} url - The URL for the anchor's `href` attribute.
216
+ * @param {string} displayText - The text to be displayed inside the anchor.
217
+ * @param {string} title - The tooltip text (title attribute).
218
+ * @param {boolean} notText - If `true`, the anchor will not contain text content.
219
+ */
162
220
  _updateAnchor(anchor, url, displayText, title, notText) {
163
221
  // download
164
222
  if (!this._selfPathBookmark(url) && this.downloadCheck.checked) {
@@ -186,13 +244,24 @@ ModalAnchorEditor.prototype = {
186
244
  } else {
187
245
  anchor.textContent = displayText;
188
246
  }
189
- },
247
+ }
190
248
 
249
+ /**
250
+ * @private
251
+ * @description Checks if the given path is an internal bookmark.
252
+ * @param {string} path - The URL or anchor link.
253
+ * @returns {boolean} - `true` if the path is an internal bookmark, otherwise `false`.
254
+ */
191
255
  _selfPathBookmark(path) {
192
256
  const href = this._w.location.href.replace(/\/$/, '');
193
- return path.indexOf('#') === 0 || (path.indexOf(href) === 0 && path.indexOf('#') === (!href.includes('#') ? href.length : href.substr(0, href.indexOf('#')).length));
194
- },
257
+ return path.indexOf('#') === 0 || (path.indexOf(href) === 0 && path.indexOf('#') === (!href.includes('#') ? href.length : href.substring(0, href.indexOf('#')).length));
258
+ }
195
259
 
260
+ /**
261
+ * @private
262
+ * @description Updates the `rel` attribute list in the modal and preview.
263
+ * @param {string} relAttr - The `rel` attribute string to set.
264
+ */
196
265
  _setRel(relAttr) {
197
266
  if (!this._isRel) return;
198
267
 
@@ -201,22 +270,27 @@ ModalAnchorEditor.prototype = {
201
270
  for (let i = 0, len = checkedRel.length, cmd; i < len; i++) {
202
271
  cmd = checkedRel[i].getAttribute('data-command');
203
272
  if (rels.includes(cmd)) {
204
- domUtils.addClass(checkedRel[i], 'se-checked');
273
+ dom.utils.addClass(checkedRel[i], 'se-checked');
205
274
  } else {
206
- domUtils.removeClass(checkedRel[i], 'se-checked');
275
+ dom.utils.removeClass(checkedRel[i], 'se-checked');
207
276
  }
208
277
  }
209
278
 
210
279
  this.relPreview.title = this.relPreview.textContent = rels.join(' ');
211
280
  if (rels.length > 0) {
212
- domUtils.addClass(this.relButton, 'on');
281
+ dom.utils.addClass(this.relButton, 'on');
213
282
  } else {
214
- domUtils.removeClass(this.relButton, 'on');
283
+ dom.utils.removeClass(this.relButton, 'on');
215
284
  }
216
- },
285
+ }
217
286
 
218
- _createHeaderList(urlValue) {
219
- const headers = domUtils.getListChildren(this.editor.frameContext.get('wysiwyg'), (current) => /h[1-6]/i.test(current.nodeName));
287
+ /**
288
+ * @private
289
+ * @description Generates a list of bookmark headers within the editor.
290
+ * @param {string} urlValue - The current URL input value.
291
+ */
292
+ _createBookmarkList(urlValue) {
293
+ const headers = dom.query.getListChildren(this.editor.frameContext.get('wysiwyg'), (current) => /h[1-6]/i.test(current.nodeName) || (dom.check.isAnchor(current) && !!current.id));
220
294
  if (headers.length === 0) return;
221
295
 
222
296
  const valueRegExp = new RegExp(`^${urlValue.replace(/^#/, '')}`, 'i');
@@ -226,7 +300,7 @@ ModalAnchorEditor.prototype = {
226
300
  v = headers[i];
227
301
  if (!valueRegExp.test(v.textContent)) continue;
228
302
  list.push(v);
229
- menus.push('<div style="' + v.style.cssText + '">' + v.textContent + '</div>');
303
+ menus.push(dom.check.isAnchor(v) ? `<div><span class="se-text-prefix-icon">${this.icons.bookmark_anchor}</span>${v.id}</div>` : `<div style="${v.style.cssText}">${v.textContent}</div>`);
230
304
  }
231
305
 
232
306
  if (list.length === 0) {
@@ -235,14 +309,19 @@ ModalAnchorEditor.prototype = {
235
309
  this.selectMenu_bookmark.create(list, menus);
236
310
  this.selectMenu_bookmark.open(this.options.get('_rtl') ? 'bottom-right' : '');
237
311
  }
238
- },
312
+ }
239
313
 
314
+ /**
315
+ * @private
316
+ * @description Updates the preview of the anchor link.
317
+ * @param {string} value - The current URL value.
318
+ */
240
319
  _setLinkPreview(value) {
241
320
  const preview = this.preview;
242
321
  const protocol = this.options.get('defaultUrlProtocol');
243
322
  const noPrefix = this.noAutoPrefix;
244
323
  const reservedProtocol = /^(mailto:|tel:|sms:|https*:\/\/|#)/.test(value) || value.indexOf(protocol) === 0;
245
- const sameProtocol = !protocol ? false : RegExp('^' + unicode.escapeStringRegexp(value.substr(0, protocol.length))).test(protocol);
324
+ const sameProtocol = !protocol ? false : RegExp('^' + unicode.escapeStringRegexp(value.substring(0, protocol.length))).test(protocol);
246
325
 
247
326
  value =
248
327
  this.linkValue =
@@ -251,10 +330,10 @@ ModalAnchorEditor.prototype = {
251
330
 
252
331
  if (this._selfPathBookmark(value)) {
253
332
  this.bookmark.style.display = 'block';
254
- domUtils.addClass(this.bookmarkButton, 'active');
333
+ dom.utils.addClass(this.bookmarkButton, 'active');
255
334
  } else {
256
335
  this.bookmark.style.display = 'none';
257
- domUtils.removeClass(this.bookmarkButton, 'active');
336
+ dom.utils.removeClass(this.bookmarkButton, 'active');
258
337
  }
259
338
 
260
339
  if (!this._selfPathBookmark(value) && this.downloadCheck.checked) {
@@ -262,8 +341,14 @@ ModalAnchorEditor.prototype = {
262
341
  } else {
263
342
  this.download.style.display = 'none';
264
343
  }
265
- },
344
+ }
266
345
 
346
+ /**
347
+ * @private
348
+ * @description Merges the given `rel` attribute value with the current list.
349
+ * @param {string} relAttr - The `rel` attribute to merge.
350
+ * @returns {string} - The updated `rel` attribute string.
351
+ */
267
352
  _relMerge(relAttr) {
268
353
  const current = this.currentRel;
269
354
  if (!relAttr) return current.join(' ');
@@ -280,8 +365,14 @@ ModalAnchorEditor.prototype = {
280
365
  }
281
366
 
282
367
  return current.join(' ');
283
- },
368
+ }
284
369
 
370
+ /**
371
+ * @private
372
+ * @description Removes the specified `rel` attribute from the current list.
373
+ * @param {string} relAttr - The `rel` attribute to remove.
374
+ * @returns {string} - The updated `rel` attribute string.
375
+ */
285
376
  _relDelete(relAttr) {
286
377
  if (!relAttr) return this.currentRel.join(' ');
287
378
  if (/^only:/.test(relAttr)) relAttr = relAttr.replace(/^only:/, '').trim();
@@ -289,24 +380,39 @@ ModalAnchorEditor.prototype = {
289
380
  const rels = this.currentRel.join(' ').replace(RegExp(relAttr + '\\s*'), '');
290
381
  this.currentRel = rels.split(' ');
291
382
  return rels;
292
- },
383
+ }
293
384
 
385
+ /**
386
+ * @private
387
+ * @description Registers a newly uploaded file and sets its URL in the modal form.
388
+ * @param {Object<string, *>} response - The response object from the file upload request.
389
+ */
294
390
  _register(response) {
295
391
  const file = response.result[0];
296
392
  this.linkValue = this.preview.textContent = this.urlInput.value = file.url;
297
393
  this.displayInput.value = file.name;
298
394
  this.downloadCheck.checked = true;
299
395
  this.download.style.display = 'block';
300
- },
396
+ }
301
397
 
398
+ /**
399
+ * @private
400
+ * @description Handles file upload errors.
401
+ * @param {Object<string, *>} response - The error response object.
402
+ * @returns {Promise<void>}
403
+ */
302
404
  async _error(response) {
303
405
  const message = await this.triggerEvent('onFileUploadError', { error: response });
304
406
  if (message === false) return;
305
407
  const err = message === NO_EVENT ? response.errorMessage : message || response.errorMessage;
306
- this.notice.open(err);
408
+ this.ui.alertOpen(err, 'error');
307
409
  console.error('[SUNEDITOR.plugin.fileUpload.error]', err);
308
- },
410
+ }
309
411
 
412
+ /**
413
+ * @description Handles the callback after a file upload completes.
414
+ * @param {XMLHttpRequest} xmlHttp - The XMLHttpRequest object containing the response.
415
+ */
310
416
  _uploadCallBack(xmlHttp) {
311
417
  const response = JSON.parse(xmlHttp.responseText);
312
418
  if (response.errorMessage) {
@@ -314,127 +420,170 @@ ModalAnchorEditor.prototype = {
314
420
  } else {
315
421
  this._register(response);
316
422
  }
317
- },
318
-
319
- constructor: ModalAnchorEditor
320
- };
321
-
322
- async function OnChangeFile(e) {
323
- const files = e.target.files;
324
- if (!files[0]) return;
325
-
326
- const fileInfo = {
327
- url: this.uploadUrl,
328
- uploadHeaders: this.uploadHeaders,
329
- files
330
- };
331
-
332
- const handler = async function (infos, newInfos) {
333
- infos = newInfos || infos;
334
- const xmlHttp = await this.fileManager.asyncUpload(infos.url, infos.uploadHeaders, infos.files);
335
- this._uploadCallBack(xmlHttp);
336
- }.bind(this, fileInfo);
337
-
338
- const result = await this.triggerEvent('onFileUploadBefore', {
339
- ...fileInfo,
340
- handler
341
- });
342
-
343
- if (result === undefined) return true;
344
- if (result === false) return false;
345
- if (result !== null && typeof result === 'object') handler(result);
423
+ }
346
424
 
347
- if (result === true || result === NO_EVENT) handler(null);
348
- }
425
+ /**
426
+ * @description Handles file input change events.
427
+ * @param {InputEvent} e - The change event object.
428
+ */
429
+ async #OnChangeFile(e) {
430
+ /** @type {HTMLInputElement} */
431
+ const eventTarget = dom.query.getEventTarget(e);
432
+ const files = eventTarget.files;
433
+ if (!files[0]) return;
434
+
435
+ const fileInfo = {
436
+ url: this.uploadUrl,
437
+ uploadHeaders: this.uploadHeaders,
438
+ files
439
+ };
440
+
441
+ const handler = async function (infos, newInfos) {
442
+ infos = newInfos || infos;
443
+ const xmlHttp = await this.fileManager.asyncUpload(infos.url, infos.uploadHeaders, infos.files);
444
+ this._uploadCallBack(xmlHttp);
445
+ }.bind(this, fileInfo);
446
+ // se-ts-ignore
447
+ void this._uploadCallBack;
448
+
449
+ const result = await this.triggerEvent('onFileUploadBefore', {
450
+ info: fileInfo,
451
+ handler
452
+ });
349
453
 
350
- function OnClick_relbutton() {
351
- this.selectMenu_rel.open(this.options.get('_rtl') ? 'left-middle' : '');
352
- }
454
+ if (result === undefined) return true;
455
+ if (result === false) return false;
456
+ if (result !== null && typeof result === 'object') handler(result);
353
457
 
354
- function SetHeaderBookmark(item) {
355
- const id = item.id || 'h_' + Math.random().toString().replace(/.+\./, '');
356
- item.id = id;
357
- this.urlInput.value = '#' + id;
458
+ if (result === true || result === NO_EVENT) handler(null);
459
+ }
358
460
 
359
- this._setLinkPreview(this.urlInput.value);
360
- this.selectMenu_bookmark.close();
361
- this.urlInput.focus();
362
- }
461
+ /**
462
+ * @description Opens the `rel` attribute selection menu.
463
+ */
464
+ #OnClick_relbutton() {
465
+ this.selectMenu_rel.open(this.options.get('_rtl') ? 'left-middle' : '');
466
+ }
363
467
 
364
- function SetRelItem(item) {
365
- const cmd = item.getAttribute('data-command');
366
- if (!cmd) return;
468
+ /**
469
+ * @description Sets the selected bookmark as the URL.
470
+ * @param {HTMLElement} item - The selected bookmark element.
471
+ */
472
+ #SetHeaderBookmark(item) {
473
+ const id = item.id || 'h_' + Math.random().toString().replace(/.+\./, '');
474
+ item.id = id;
475
+ this.urlInput.value = '#' + id;
476
+
477
+ this._setLinkPreview(this.urlInput.value);
478
+ this.selectMenu_bookmark.close();
479
+ this.urlInput.focus();
480
+ }
367
481
 
368
- const current = this.currentRel;
369
- const index = current.indexOf(cmd);
370
- if (index === -1) current.push(cmd);
371
- else current.splice(index, 1);
482
+ /**
483
+ * @param {HTMLElement} item - The selected `rel` attribute element.
484
+ */
485
+ #SetRelItem(item) {
486
+ const cmd = item.getAttribute('data-command');
487
+ if (!cmd) return;
372
488
 
373
- this.relPreview.title = this.relPreview.textContent = current.join(', ');
374
- }
489
+ const current = this.currentRel;
490
+ const index = current.indexOf(cmd);
491
+ if (index === -1) current.push(cmd);
492
+ else current.splice(index, 1);
375
493
 
376
- function OnChange_displayInput(e) {
377
- this._change = !!e.target.value.trim();
378
- }
494
+ this.relPreview.title = this.relPreview.textContent = current.join(', ');
495
+ }
379
496
 
380
- function OnChange_urlInput(e) {
381
- const value = e.target.value.trim();
382
- this._setLinkPreview(value);
383
- if (this._selfPathBookmark(value)) this._createHeaderList(value);
384
- else this.selectMenu_bookmark.close();
385
- }
497
+ /**
498
+ * @param {InputEvent} e - Event object
499
+ */
500
+ #OnChange_displayInput(e) {
501
+ /** @type {HTMLInputElement} */
502
+ const eventTarget = dom.query.getEventTarget(e);
503
+ this._change = !!eventTarget.value.trim();
504
+ }
386
505
 
387
- function OnFocus_urlInput() {
388
- const value = this.urlInput.value;
389
- if (this._selfPathBookmark(value)) this._createHeaderList(value);
390
- }
506
+ /**
507
+ * @param {InputEvent} e - Event object
508
+ */
509
+ #OnChange_urlInput(e) {
510
+ /** @type {HTMLInputElement} */
511
+ const eventTarget = dom.query.getEventTarget(e);
512
+ const value = eventTarget.value.trim();
513
+ this._setLinkPreview(value);
514
+ if (this._selfPathBookmark(value)) this._createBookmarkList(value);
515
+ else this.selectMenu_bookmark.close();
516
+ }
391
517
 
392
- function OnClick_bookmarkButton() {
393
- let url = this.urlInput.value;
394
- if (this._selfPathBookmark(url)) {
395
- url = url.substr(1);
396
- this.bookmark.style.display = 'none';
397
- domUtils.removeClass(this.bookmarkButton, 'active');
398
- } else {
399
- url = '#' + url;
400
- this.bookmark.style.display = 'block';
401
- domUtils.addClass(this.bookmarkButton, 'active');
402
- this.downloadCheck.checked = false;
403
- this.download.style.display = 'none';
404
- this._createHeaderList(url);
518
+ #OnFocus_urlInput() {
519
+ const value = this.urlInput.value;
520
+ if (this._selfPathBookmark(value)) this._createBookmarkList(value);
405
521
  }
406
522
 
407
- this.urlInput.value = url;
408
- this._setLinkPreview(url);
409
- this.urlInput.focus();
410
- }
523
+ #OnClick_bookmarkButton() {
524
+ let url = this.urlInput.value;
525
+ if (this._selfPathBookmark(url)) {
526
+ url = url.substring(1);
527
+ this.bookmark.style.display = 'none';
528
+ dom.utils.removeClass(this.bookmarkButton, 'active');
529
+ } else {
530
+ url = '#' + url;
531
+ this.bookmark.style.display = 'block';
532
+ dom.utils.addClass(this.bookmarkButton, 'active');
533
+ this.downloadCheck.checked = false;
534
+ this.download.style.display = 'none';
535
+ this._createBookmarkList(url);
536
+ }
411
537
 
412
- function OnChange_newWindowCheck(e) {
413
- if (typeof this.defaultRel.check_new_window !== 'string') return;
414
- if (e.target.checked) {
415
- this._setRel(this._relMerge(this.defaultRel.check_new_window));
416
- } else {
417
- this._setRel(this._relDelete(this.defaultRel.check_new_window));
538
+ this.urlInput.value = url;
539
+ this._setLinkPreview(url);
540
+ this.urlInput.focus();
418
541
  }
419
- }
420
542
 
421
- function OnChange_downloadCheck(e) {
422
- if (e.target.checked) {
423
- this.download.style.display = 'block';
424
- this.bookmark.style.display = 'none';
425
- domUtils.removeClass(this.bookmarkButton, 'active');
426
- this.linkValue = this.preview.textContent = this.urlInput.value = this.urlInput.value.replace(/^#+/, '');
427
- if (typeof this.defaultRel.check_bookmark === 'string') {
428
- this._setRel(this._relMerge(this.defaultRel.check_bookmark));
543
+ /**
544
+ * @param {InputEvent} e - Event object
545
+ */
546
+ #OnChange_newWindowCheck(e) {
547
+ if (typeof this.defaultRel.check_new_window !== 'string') return;
548
+ /** @type {HTMLInputElement} */
549
+ const eventTarget = dom.query.getEventTarget(e);
550
+ if (eventTarget.checked) {
551
+ this._setRel(this._relMerge(this.defaultRel.check_new_window));
552
+ } else {
553
+ this._setRel(this._relDelete(this.defaultRel.check_new_window));
429
554
  }
430
- } else {
431
- this.download.style.display = 'none';
432
- if (typeof this.defaultRel.check_bookmark === 'string') {
433
- this._setRel(this._relDelete(this.defaultRel.check_bookmark));
555
+ }
556
+
557
+ /**
558
+ * @param {InputEvent} e - Event object
559
+ */
560
+ #OnChange_downloadCheck(e) {
561
+ /** @type {HTMLInputElement} */
562
+ const eventTarget = dom.query.getEventTarget(e);
563
+ if (eventTarget.checked) {
564
+ this.download.style.display = 'block';
565
+ this.bookmark.style.display = 'none';
566
+ dom.utils.removeClass(this.bookmarkButton, 'active');
567
+ this.linkValue = this.preview.textContent = this.urlInput.value = this.urlInput.value.replace(/^#+/, '');
568
+ if (typeof this.defaultRel.check_bookmark === 'string') {
569
+ this._setRel(this._relMerge(this.defaultRel.check_bookmark));
570
+ }
571
+ } else {
572
+ this.download.style.display = 'none';
573
+ if (typeof this.defaultRel.check_bookmark === 'string') {
574
+ this._setRel(this._relDelete(this.defaultRel.check_bookmark));
575
+ }
434
576
  }
435
577
  }
436
578
  }
437
579
 
580
+ /**
581
+ * @private
582
+ * @param {__se__EditorCore} editor - Editor instance
583
+ * @param {ModalAnchorEditorParams} params - ModalAnchorEditor options
584
+ * @param {Array<string>} relList - REL attribute list
585
+ * @returns {HTMLElement} - Modal form element
586
+ */
438
587
  function CreatetModalForm(editor, params, relList) {
439
588
  const lang = editor.lang;
440
589
  const icons = editor.icons;
@@ -451,13 +600,13 @@ function CreatetModalForm(editor, params, relList) {
451
600
  params.enableFileUpload
452
601
  ? `<button type="button" class="se-btn se-tooltip se-modal-files-edge-button _se_upload_button" aria-label="${lang.fileUpload}">
453
602
  ${icons.file_upload}
454
- ${CreateTooltipInner(lang.fileUpload)}
603
+ ${dom.utils.createTooltipInner(lang.fileUpload)}
455
604
  </button>`
456
605
  : ''
457
606
  }
458
607
  <button type="button" class="se-btn se-tooltip se-modal-files-edge-button _se_bookmark_button" aria-label="${lang.link_modal_bookmark}">
459
608
  ${icons.bookmark}
460
- ${CreateTooltipInner(lang.link_modal_bookmark)}
609
+ ${dom.utils.createTooltipInner(lang.link_modal_bookmark)}
461
610
  </button>
462
611
  </div>
463
612
  <div class="se-anchor-preview-form">
@@ -479,7 +628,7 @@ function CreatetModalForm(editor, params, relList) {
479
628
  <div class="se-anchor-rel">
480
629
  <button type="button" class="se-btn se-tooltip se-anchor-rel-btn" title="${lang.link_modal_relAttribute}" aria-label="${lang.link_modal_relAttribute}">
481
630
  ${icons.link_rel}
482
- ${CreateTooltipInner(lang.link_modal_relAttribute)}
631
+ ${dom.utils.createTooltipInner(lang.link_modal_relAttribute)}
483
632
  </button>
484
633
  <div class="se-anchor-rel-wrapper"><pre class="se-link-preview se-anchor-rel-preview"></pre></div>
485
634
  </div>
@@ -488,7 +637,7 @@ function CreatetModalForm(editor, params, relList) {
488
637
 
489
638
  html += '</div></div>';
490
639
 
491
- return domUtils.createElement('DIV', null, html);
640
+ return dom.utils.createElement('DIV', null, html);
492
641
  }
493
642
 
494
643
  export default ModalAnchorEditor;