suneditor 3.0.0-beta.9 → 3.0.0-rc.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 (380) hide show
  1. package/README.md +65 -57
  2. package/dist/suneditor-contents.min.css +1 -0
  3. package/dist/suneditor.min.css +1 -1
  4. package/dist/suneditor.min.js +1 -1
  5. package/package.json +110 -61
  6. package/src/assets/design/color.css +36 -17
  7. package/src/assets/design/size.css +2 -0
  8. package/src/assets/icons/defaultIcons.js +17 -2
  9. package/src/assets/suneditor-contents.css +51 -16
  10. package/src/assets/suneditor.css +116 -43
  11. package/src/core/config/contextProvider.js +288 -0
  12. package/src/core/config/eventManager.js +188 -0
  13. package/src/core/config/instanceCheck.js +59 -0
  14. package/src/core/config/optionProvider.js +452 -0
  15. package/src/core/editor.js +166 -1637
  16. package/src/core/event/actions/index.js +229 -0
  17. package/src/core/event/effects/common.registry.js +74 -0
  18. package/src/core/event/effects/keydown.registry.js +573 -0
  19. package/src/core/event/effects/ruleHelpers.js +148 -0
  20. package/src/core/event/eventOrchestrator.js +944 -0
  21. package/src/core/event/executor.js +27 -0
  22. package/src/core/{base/eventHandlers → event/handlers}/handler_toolbar.js +27 -28
  23. package/src/core/{base/eventHandlers → event/handlers}/handler_ww_clipboard.js +10 -8
  24. package/src/core/{base/eventHandlers → event/handlers}/handler_ww_dragDrop.js +22 -23
  25. package/src/core/event/handlers/handler_ww_input.js +75 -0
  26. package/src/core/event/handlers/handler_ww_key.js +228 -0
  27. package/src/core/event/handlers/handler_ww_mouse.js +166 -0
  28. package/src/core/event/ports.js +211 -0
  29. package/src/core/event/reducers/keydown.reducer.js +97 -0
  30. package/src/core/event/rules/keydown.rule.arrow.js +63 -0
  31. package/src/core/event/rules/keydown.rule.backspace.js +208 -0
  32. package/src/core/event/rules/keydown.rule.delete.js +132 -0
  33. package/src/core/event/rules/keydown.rule.enter.js +150 -0
  34. package/src/core/event/rules/keydown.rule.tab.js +35 -0
  35. package/src/core/event/support/defaultLineManager.js +136 -0
  36. package/src/core/event/support/selectionState.js +204 -0
  37. package/src/core/kernel/coreKernel.js +320 -0
  38. package/src/core/kernel/kernelInjector.js +19 -0
  39. package/src/core/kernel/store.js +173 -0
  40. package/src/core/{class → logic/dom}/char.js +42 -45
  41. package/src/core/logic/dom/format.js +1075 -0
  42. package/src/core/{class → logic/dom}/html.js +743 -624
  43. package/src/core/logic/dom/inline.js +1847 -0
  44. package/src/core/logic/dom/listFormat.js +601 -0
  45. package/src/core/{class → logic/dom}/nodeTransform.js +92 -72
  46. package/src/core/{class → logic/dom}/offset.js +254 -317
  47. package/src/core/logic/dom/selection.js +754 -0
  48. package/src/core/logic/panel/menu.js +389 -0
  49. package/src/core/logic/panel/toolbar.js +449 -0
  50. package/src/core/logic/panel/viewer.js +761 -0
  51. package/src/core/logic/shell/_commandExecutor.js +380 -0
  52. package/src/core/logic/shell/commandDispatcher.js +241 -0
  53. package/src/core/logic/shell/component.js +970 -0
  54. package/src/core/logic/shell/focusManager.js +110 -0
  55. package/src/core/{base → logic/shell}/history.js +110 -60
  56. package/src/core/logic/shell/pluginManager.js +363 -0
  57. package/src/core/logic/shell/shortcuts.js +130 -0
  58. package/src/core/logic/shell/ui.js +904 -0
  59. package/src/core/schema/context.js +66 -0
  60. package/src/core/schema/frameContext.js +160 -0
  61. package/src/core/schema/options.js +628 -0
  62. package/src/core/section/constructor.js +194 -500
  63. package/src/core/section/documentType.js +297 -222
  64. package/src/events.js +808 -543
  65. package/src/helper/clipboard.js +27 -16
  66. package/src/helper/converter.js +100 -78
  67. package/src/helper/dom/domCheck.js +56 -30
  68. package/src/helper/dom/domQuery.js +159 -89
  69. package/src/helper/dom/domUtils.js +114 -49
  70. package/src/helper/dom/index.js +5 -1
  71. package/src/helper/env.js +26 -26
  72. package/src/helper/index.js +1 -1
  73. package/src/helper/keyCodeMap.js +25 -28
  74. package/src/helper/numbers.js +4 -8
  75. package/src/helper/unicode.js +4 -8
  76. package/src/hooks/base.js +307 -0
  77. package/src/hooks/params.js +130 -0
  78. package/src/interfaces/contracts.js +227 -0
  79. package/src/interfaces/index.js +7 -0
  80. package/src/interfaces/plugins.js +239 -0
  81. package/src/langs/ckb.js +4 -4
  82. package/src/langs/cs.js +4 -4
  83. package/src/langs/da.js +4 -4
  84. package/src/langs/de.js +4 -4
  85. package/src/langs/en.js +4 -4
  86. package/src/langs/es.js +4 -4
  87. package/src/langs/fa.js +4 -4
  88. package/src/langs/fr.js +4 -4
  89. package/src/langs/he.js +4 -4
  90. package/src/langs/hu.js +4 -4
  91. package/src/langs/it.js +4 -4
  92. package/src/langs/ja.js +4 -4
  93. package/src/langs/km.js +4 -4
  94. package/src/langs/ko.js +4 -4
  95. package/src/langs/lv.js +4 -4
  96. package/src/langs/nl.js +4 -4
  97. package/src/langs/pl.js +4 -4
  98. package/src/langs/pt_br.js +13 -13
  99. package/src/langs/ro.js +4 -4
  100. package/src/langs/ru.js +4 -4
  101. package/src/langs/se.js +4 -4
  102. package/src/langs/tr.js +4 -4
  103. package/src/langs/uk.js +4 -4
  104. package/src/langs/ur.js +4 -4
  105. package/src/langs/zh_cn.js +4 -4
  106. package/src/modules/{Browser.js → contract/Browser.js} +119 -128
  107. package/src/modules/{ColorPicker.js → contract/ColorPicker.js} +132 -142
  108. package/src/modules/contract/Controller.js +589 -0
  109. package/src/modules/{Figure.js → contract/Figure.js} +591 -411
  110. package/src/modules/{HueSlider.js → contract/HueSlider.js} +125 -86
  111. package/src/modules/contract/Modal.js +357 -0
  112. package/src/modules/contract/index.js +9 -0
  113. package/src/modules/manager/ApiManager.js +197 -0
  114. package/src/modules/{FileManager.js → manager/FileManager.js} +128 -160
  115. package/src/modules/manager/index.js +5 -0
  116. package/src/modules/{ModalAnchorEditor.js → ui/ModalAnchorEditor.js} +108 -138
  117. package/src/modules/{SelectMenu.js → ui/SelectMenu.js} +119 -120
  118. package/src/modules/{_DragHandle.js → ui/_DragHandle.js} +1 -1
  119. package/src/modules/ui/index.js +6 -0
  120. package/src/plugins/browser/audioGallery.js +23 -26
  121. package/src/plugins/browser/fileBrowser.js +25 -28
  122. package/src/plugins/browser/fileGallery.js +20 -23
  123. package/src/plugins/browser/imageGallery.js +24 -23
  124. package/src/plugins/browser/videoGallery.js +27 -29
  125. package/src/plugins/command/blockquote.js +11 -17
  126. package/src/plugins/command/exportPDF.js +26 -26
  127. package/src/plugins/command/fileUpload.js +138 -133
  128. package/src/plugins/command/list_bulleted.js +48 -44
  129. package/src/plugins/command/list_numbered.js +48 -44
  130. package/src/plugins/dropdown/align.js +64 -50
  131. package/src/plugins/dropdown/backgroundColor.js +34 -35
  132. package/src/plugins/dropdown/{formatBlock.js → blockStyle.js} +43 -37
  133. package/src/plugins/dropdown/font.js +50 -36
  134. package/src/plugins/dropdown/fontColor.js +34 -35
  135. package/src/plugins/dropdown/hr.js +55 -50
  136. package/src/plugins/dropdown/layout.js +20 -15
  137. package/src/plugins/dropdown/lineHeight.js +46 -30
  138. package/src/plugins/dropdown/list.js +32 -33
  139. package/src/plugins/dropdown/paragraphStyle.js +40 -34
  140. package/src/plugins/dropdown/table/index.js +915 -0
  141. package/src/plugins/dropdown/table/render/table.html.js +308 -0
  142. package/src/plugins/dropdown/table/render/table.menu.js +121 -0
  143. package/src/plugins/dropdown/table/services/table.cell.js +465 -0
  144. package/src/plugins/dropdown/table/services/table.clipboard.js +414 -0
  145. package/src/plugins/dropdown/table/services/table.grid.js +504 -0
  146. package/src/plugins/dropdown/table/services/table.resize.js +463 -0
  147. package/src/plugins/dropdown/table/services/table.selection.js +466 -0
  148. package/src/plugins/dropdown/table/services/table.style.js +844 -0
  149. package/src/plugins/dropdown/table/shared/table.constants.js +109 -0
  150. package/src/plugins/dropdown/table/shared/table.utils.js +219 -0
  151. package/src/plugins/dropdown/template.js +20 -15
  152. package/src/plugins/dropdown/textStyle.js +28 -22
  153. package/src/plugins/field/mention.js +54 -49
  154. package/src/plugins/index.js +5 -5
  155. package/src/plugins/input/fontSize.js +100 -97
  156. package/src/plugins/input/pageNavigator.js +13 -10
  157. package/src/plugins/modal/audio.js +208 -219
  158. package/src/plugins/modal/drawing.js +99 -104
  159. package/src/plugins/modal/embed.js +323 -312
  160. package/src/plugins/modal/image/index.js +942 -0
  161. package/src/plugins/modal/image/render/image.html.js +150 -0
  162. package/src/plugins/modal/image/services/image.size.js +198 -0
  163. package/src/plugins/modal/image/services/image.upload.js +216 -0
  164. package/src/plugins/modal/image/shared/image.constants.js +20 -0
  165. package/src/plugins/modal/link.js +74 -54
  166. package/src/plugins/modal/math.js +126 -119
  167. package/src/plugins/modal/video/index.js +858 -0
  168. package/src/plugins/modal/video/render/video.html.js +131 -0
  169. package/src/plugins/modal/video/services/video.size.js +281 -0
  170. package/src/plugins/modal/video/services/video.upload.js +92 -0
  171. package/src/plugins/popup/anchor.js +57 -49
  172. package/src/suneditor.js +73 -61
  173. package/src/themes/cobalt.css +155 -0
  174. package/src/themes/dark.css +143 -120
  175. package/src/typedef.js +214 -63
  176. package/types/assets/icons/defaultIcons.d.ts +8 -0
  177. package/types/assets/suneditor-contents.css.d.ts +1 -0
  178. package/types/assets/suneditor.css.d.ts +1 -0
  179. package/types/core/config/contextProvider.d.ts +148 -0
  180. package/types/core/config/eventManager.d.ts +68 -0
  181. package/types/core/config/instanceCheck.d.ts +33 -0
  182. package/types/core/config/optionProvider.d.ts +147 -0
  183. package/types/core/editor.d.ts +27 -586
  184. package/types/core/event/actions/index.d.ts +50 -0
  185. package/types/core/event/effects/common.registry.d.ts +56 -0
  186. package/types/core/event/effects/keydown.registry.d.ts +80 -0
  187. package/types/core/event/effects/ruleHelpers.d.ts +36 -0
  188. package/types/core/event/eventOrchestrator.d.ts +191 -0
  189. package/types/core/event/executor.d.ts +13 -0
  190. package/types/core/event/handlers/handler_toolbar.d.ts +38 -0
  191. package/types/core/event/handlers/handler_ww_clipboard.d.ts +36 -0
  192. package/types/core/event/handlers/handler_ww_dragDrop.d.ts +26 -0
  193. package/types/core/event/handlers/handler_ww_input.d.ts +38 -0
  194. package/types/core/event/handlers/handler_ww_key.d.ts +40 -0
  195. package/types/core/event/handlers/handler_ww_mouse.d.ts +47 -0
  196. package/types/core/event/ports.d.ts +256 -0
  197. package/types/core/event/reducers/keydown.reducer.d.ts +84 -0
  198. package/types/core/event/rules/keydown.rule.arrow.d.ts +19 -0
  199. package/types/core/event/rules/keydown.rule.backspace.d.ts +18 -0
  200. package/types/core/event/rules/keydown.rule.delete.d.ts +18 -0
  201. package/types/core/event/rules/keydown.rule.enter.d.ts +18 -0
  202. package/types/core/event/rules/keydown.rule.tab.d.ts +18 -0
  203. package/types/core/event/support/defaultLineManager.d.ts +22 -0
  204. package/types/core/event/support/selectionState.d.ts +29 -0
  205. package/types/core/kernel/coreKernel.d.ts +219 -0
  206. package/types/core/kernel/kernelInjector.d.ts +16 -0
  207. package/types/core/kernel/store.d.ts +170 -0
  208. package/types/core/logic/dom/char.d.ts +46 -0
  209. package/types/core/logic/dom/format.d.ts +234 -0
  210. package/types/core/logic/dom/html.d.ts +290 -0
  211. package/types/core/logic/dom/inline.d.ts +93 -0
  212. package/types/core/logic/dom/listFormat.d.ts +101 -0
  213. package/types/core/logic/dom/nodeTransform.d.ts +110 -0
  214. package/types/core/logic/dom/offset.d.ts +335 -0
  215. package/types/core/logic/dom/selection.d.ts +165 -0
  216. package/types/core/logic/panel/menu.d.ts +93 -0
  217. package/types/core/logic/panel/toolbar.d.ts +128 -0
  218. package/types/core/logic/panel/viewer.d.ts +89 -0
  219. package/types/core/logic/shell/_commandExecutor.d.ts +18 -0
  220. package/types/core/logic/shell/commandDispatcher.d.ts +65 -0
  221. package/types/core/logic/shell/component.d.ts +182 -0
  222. package/types/core/logic/shell/focusManager.d.ts +31 -0
  223. package/types/core/{base → logic/shell}/history.d.ts +13 -12
  224. package/types/core/logic/shell/pluginManager.d.ts +115 -0
  225. package/types/core/logic/shell/shortcuts.d.ts +131 -0
  226. package/types/core/logic/shell/ui.d.ts +261 -0
  227. package/types/core/schema/context.d.ts +104 -0
  228. package/types/core/schema/frameContext.d.ts +320 -0
  229. package/types/core/schema/options.d.ts +1241 -0
  230. package/types/core/section/constructor.d.ts +117 -652
  231. package/types/core/section/documentType.d.ts +43 -61
  232. package/types/events.d.ts +796 -65
  233. package/types/helper/clipboard.d.ts +5 -4
  234. package/types/helper/converter.d.ts +55 -43
  235. package/types/helper/dom/domCheck.d.ts +27 -19
  236. package/types/helper/dom/domQuery.d.ts +76 -57
  237. package/types/helper/dom/domUtils.d.ts +62 -39
  238. package/types/helper/dom/index.d.ts +87 -1
  239. package/types/helper/env.d.ts +16 -13
  240. package/types/helper/index.d.ts +8 -2
  241. package/types/helper/keyCodeMap.d.ts +24 -23
  242. package/types/helper/numbers.d.ts +4 -6
  243. package/types/helper/unicode.d.ts +4 -3
  244. package/types/hooks/base.d.ts +239 -0
  245. package/types/hooks/params.d.ts +65 -0
  246. package/types/index.d.ts +20 -117
  247. package/types/interfaces/contracts.d.ts +183 -0
  248. package/types/interfaces/index.d.ts +3 -0
  249. package/types/interfaces/plugins.d.ts +168 -0
  250. package/types/langs/_Lang.d.ts +2 -2
  251. package/types/langs/index.d.ts +2 -2
  252. package/types/modules/contract/Browser.d.ts +262 -0
  253. package/types/modules/contract/ColorPicker.d.ts +99 -0
  254. package/types/modules/contract/Controller.d.ts +204 -0
  255. package/types/modules/contract/Figure.d.ts +529 -0
  256. package/types/modules/{HueSlider.d.ts → contract/HueSlider.d.ts} +39 -28
  257. package/types/modules/contract/Modal.d.ts +62 -0
  258. package/types/modules/contract/index.d.ts +7 -0
  259. package/types/modules/manager/ApiManager.d.ts +106 -0
  260. package/types/modules/manager/FileManager.d.ts +124 -0
  261. package/types/modules/manager/index.d.ts +3 -0
  262. package/types/modules/ui/ModalAnchorEditor.d.ts +152 -0
  263. package/types/modules/ui/SelectMenu.d.ts +107 -0
  264. package/types/modules/{_DragHandle.d.ts → ui/_DragHandle.d.ts} +1 -0
  265. package/types/modules/ui/index.d.ts +4 -0
  266. package/types/plugins/browser/audioGallery.d.ts +33 -41
  267. package/types/plugins/browser/fileBrowser.d.ts +42 -50
  268. package/types/plugins/browser/fileGallery.d.ts +33 -41
  269. package/types/plugins/browser/imageGallery.d.ts +30 -37
  270. package/types/plugins/browser/videoGallery.d.ts +33 -41
  271. package/types/plugins/command/blockquote.d.ts +4 -21
  272. package/types/plugins/command/exportPDF.d.ts +23 -33
  273. package/types/plugins/command/fileUpload.d.ts +80 -100
  274. package/types/plugins/command/list_bulleted.d.ts +9 -35
  275. package/types/plugins/command/list_numbered.d.ts +9 -35
  276. package/types/plugins/dropdown/align.d.ts +23 -46
  277. package/types/plugins/dropdown/backgroundColor.d.ts +35 -53
  278. package/types/plugins/dropdown/blockStyle.d.ts +45 -0
  279. package/types/plugins/dropdown/font.d.ts +18 -41
  280. package/types/plugins/dropdown/fontColor.d.ts +35 -53
  281. package/types/plugins/dropdown/hr.d.ts +26 -52
  282. package/types/plugins/dropdown/layout.d.ts +19 -25
  283. package/types/plugins/dropdown/lineHeight.d.ts +21 -39
  284. package/types/plugins/dropdown/list.d.ts +6 -34
  285. package/types/plugins/dropdown/paragraphStyle.d.ts +34 -45
  286. package/types/plugins/dropdown/table/index.d.ts +158 -0
  287. package/types/plugins/dropdown/table/render/table.html.d.ts +71 -0
  288. package/types/plugins/dropdown/table/render/table.menu.d.ts +59 -0
  289. package/types/plugins/dropdown/table/services/table.cell.d.ts +76 -0
  290. package/types/plugins/dropdown/table/services/table.clipboard.d.ts +26 -0
  291. package/types/plugins/dropdown/table/services/table.grid.d.ts +77 -0
  292. package/types/plugins/dropdown/table/services/table.resize.d.ts +72 -0
  293. package/types/plugins/dropdown/table/services/table.selection.d.ts +59 -0
  294. package/types/plugins/dropdown/table/services/table.style.d.ts +162 -0
  295. package/types/plugins/dropdown/table/shared/table.constants.d.ts +134 -0
  296. package/types/plugins/dropdown/table/shared/table.utils.d.ts +91 -0
  297. package/types/plugins/dropdown/template.d.ts +19 -25
  298. package/types/plugins/dropdown/textStyle.d.ts +23 -30
  299. package/types/plugins/field/mention.d.ts +66 -72
  300. package/types/plugins/index.d.ts +41 -40
  301. package/types/plugins/input/fontSize.d.ts +57 -96
  302. package/types/plugins/input/pageNavigator.d.ts +5 -8
  303. package/types/plugins/modal/audio.d.ts +60 -153
  304. package/types/plugins/modal/drawing.d.ts +16 -118
  305. package/types/plugins/modal/embed.d.ts +46 -166
  306. package/types/plugins/modal/image/index.d.ts +281 -0
  307. package/types/plugins/modal/image/render/image.html.d.ts +45 -0
  308. package/types/plugins/modal/image/services/image.size.d.ts +55 -0
  309. package/types/plugins/modal/image/services/image.upload.d.ts +24 -0
  310. package/types/plugins/modal/image/shared/image.constants.d.ts +17 -0
  311. package/types/plugins/modal/link.d.ts +46 -66
  312. package/types/plugins/modal/math.d.ts +17 -86
  313. package/types/plugins/modal/{video.d.ts → video/index.d.ts} +89 -221
  314. package/types/plugins/modal/video/render/video.html.d.ts +37 -0
  315. package/types/plugins/modal/video/services/video.size.d.ts +74 -0
  316. package/types/plugins/modal/video/services/video.upload.d.ts +19 -0
  317. package/types/plugins/popup/anchor.d.ts +8 -38
  318. package/types/suneditor.d.ts +55 -24
  319. package/types/typedef.d.ts +344 -228
  320. package/CONTRIBUTING.md +0 -186
  321. package/src/core/base/eventHandlers/handler_ww_key_input.js +0 -1200
  322. package/src/core/base/eventHandlers/handler_ww_mouse.js +0 -194
  323. package/src/core/base/eventManager.js +0 -1523
  324. package/src/core/class/component.js +0 -856
  325. package/src/core/class/format.js +0 -3433
  326. package/src/core/class/menu.js +0 -346
  327. package/src/core/class/selection.js +0 -610
  328. package/src/core/class/shortcuts.js +0 -98
  329. package/src/core/class/toolbar.js +0 -431
  330. package/src/core/class/ui.js +0 -424
  331. package/src/core/class/viewer.js +0 -750
  332. package/src/core/section/actives.js +0 -266
  333. package/src/core/section/context.js +0 -102
  334. package/src/editorInjector/_classes.js +0 -36
  335. package/src/editorInjector/_core.js +0 -87
  336. package/src/editorInjector/index.js +0 -73
  337. package/src/modules/ApiManager.js +0 -191
  338. package/src/modules/Controller.js +0 -474
  339. package/src/modules/Modal.js +0 -346
  340. package/src/modules/index.js +0 -14
  341. package/src/plugins/dropdown/table.js +0 -4034
  342. package/src/plugins/modal/image.js +0 -1376
  343. package/src/plugins/modal/video.js +0 -1226
  344. package/types/core/base/eventHandlers/handler_toolbar.d.ts +0 -41
  345. package/types/core/base/eventHandlers/handler_ww_clipboard.d.ts +0 -40
  346. package/types/core/base/eventHandlers/handler_ww_dragDrop.d.ts +0 -35
  347. package/types/core/base/eventHandlers/handler_ww_key_input.d.ts +0 -45
  348. package/types/core/base/eventHandlers/handler_ww_mouse.d.ts +0 -39
  349. package/types/core/base/eventManager.d.ts +0 -401
  350. package/types/core/class/char.d.ts +0 -61
  351. package/types/core/class/component.d.ts +0 -213
  352. package/types/core/class/format.d.ts +0 -623
  353. package/types/core/class/html.d.ts +0 -430
  354. package/types/core/class/menu.d.ts +0 -126
  355. package/types/core/class/nodeTransform.d.ts +0 -93
  356. package/types/core/class/offset.d.ts +0 -522
  357. package/types/core/class/selection.d.ts +0 -188
  358. package/types/core/class/shortcuts.d.ts +0 -142
  359. package/types/core/class/toolbar.d.ts +0 -189
  360. package/types/core/class/ui.d.ts +0 -164
  361. package/types/core/class/viewer.d.ts +0 -140
  362. package/types/core/section/actives.d.ts +0 -46
  363. package/types/core/section/context.d.ts +0 -45
  364. package/types/editorInjector/_classes.d.ts +0 -41
  365. package/types/editorInjector/_core.d.ts +0 -87
  366. package/types/editorInjector/index.d.ts +0 -69
  367. package/types/modules/ApiManager.d.ts +0 -125
  368. package/types/modules/Browser.d.ts +0 -326
  369. package/types/modules/ColorPicker.d.ts +0 -135
  370. package/types/modules/Controller.d.ts +0 -251
  371. package/types/modules/Figure.d.ts +0 -517
  372. package/types/modules/FileManager.d.ts +0 -202
  373. package/types/modules/Modal.d.ts +0 -111
  374. package/types/modules/ModalAnchorEditor.d.ts +0 -236
  375. package/types/modules/SelectMenu.d.ts +0 -194
  376. package/types/modules/index.d.ts +0 -26
  377. package/types/plugins/dropdown/formatBlock.d.ts +0 -55
  378. package/types/plugins/dropdown/table.d.ts +0 -627
  379. package/types/plugins/modal/image.d.ts +0 -451
  380. /package/{LICENSE → LICENSE.txt} +0 -0
@@ -1,4034 +0,0 @@
1
- import EditorInjector from '../../editorInjector';
2
- import { dom, numbers, converter, env, keyCodeMap } from '../../helper';
3
- import { Controller, SelectMenu, ColorPicker, Figure, _DragHandle } from '../../modules';
4
-
5
- const { _w, ON_OVER_COMPONENT } = env;
6
-
7
- const ROW_SELECT_MARGIN = 5;
8
- const CELL_SELECT_MARGIN = 2;
9
- const CELL_DECIMAL_END = 0;
10
-
11
- const RESIZE_CELL_CLASS = '.se-table-resize-line';
12
- const RESIZE_CELL_PREV_CLASS = '.se-table-resize-line-prev';
13
- const RESIZE_ROW_CLASS = '.se-table-resize-row';
14
- const RESIZE_ROW_PREV_CLASS = '.se-table-resize-row-prev';
15
-
16
- const BORDER_LIST = ['none', 'solid', 'dotted', 'dashed', 'double', 'groove', 'ridge', 'inset', 'outset'];
17
- const BORDER_FORMATS = {
18
- all: 'border_all',
19
- inside: 'border_inside',
20
- horizon: 'border_horizontal',
21
- vertical: 'border_vertical',
22
- outside: 'border_outside',
23
- left: 'border_left',
24
- top: 'border_top',
25
- right: 'border_right',
26
- bottom: 'border_bottom',
27
- none: 'border_none'
28
- };
29
- const BORDER_FORMAT_INSIDE = ['all', 'inside', 'horizon', 'vertical'];
30
- const BORDER_NS = {
31
- l: 'borderLeft',
32
- t: 'borderTop',
33
- r: 'borderRight',
34
- b: 'borderBottom'
35
- };
36
- const DEFAULT_BORDER_UNIT = 'px';
37
- const DEFAULT_COLOR_LIST = [
38
- // row-1
39
- '#b0dbb0',
40
- '#efef7e',
41
- '#f2acac',
42
- '#dcb0f6',
43
- '#99bdff',
44
- // row-2
45
- '#5dbd5d',
46
- '#e7c301',
47
- '#f64444',
48
- '#e57ff4',
49
- '#4387f1',
50
- // row-3
51
- '#27836a',
52
- '#f69915',
53
- '#ba0808',
54
- '#a90bed',
55
- '#134299',
56
- // row-4
57
- '#e4e4e4',
58
- '#B3B3B3',
59
- '#808080',
60
- '#4D4D4D',
61
- '#000000'
62
- ];
63
-
64
- /**
65
- * @class
66
- * @description Table Plugin
67
- */
68
- class Table extends EditorInjector {
69
- static key = 'table';
70
- static type = 'dropdown-free';
71
- static className = '';
72
- static options = { isInputComponent: true };
73
- /**
74
- * @this {Table}
75
- * @param {HTMLElement} node - The node to check.
76
- * @returns {HTMLElement|null} Returns a node if the node is a valid component.
77
- */
78
- static component(node) {
79
- return dom.check.isTable(node) ? node : null;
80
- }
81
-
82
- /**
83
- * @constructor
84
- * @param {__se__EditorCore} editor - The root editor instance
85
- * @param {Object} pluginOptions
86
- * @param {"x"|"y"|"xy"} [pluginOptions.scrollType='x'] - Scroll type ('x', 'y', 'xy')
87
- * @param {"top"|"bottom"} [pluginOptions.captionPosition='bottom'] - Caption position ('top', 'bottom')
88
- * @param {"cell"|"table"} [pluginOptions.cellControllerPosition='cell'] - Cell controller position ('cell', 'table')
89
- * @param {Array} [pluginOptions.colorList] - Color list, used in cell color picker
90
- */
91
- constructor(editor, pluginOptions) {
92
- // plugin bisic properties
93
- super(editor);
94
- this.title = this.lang.table;
95
- this.icon = 'table';
96
-
97
- // pluginOptions options
98
- this.figureScrollList = ['se-scroll-figure-xy', 'se-scroll-figure-x', 'se-scroll-figure-y'];
99
- this.figureScroll = typeof pluginOptions.scrollType === 'string' ? pluginOptions.scrollType.toLowerCase() : 'x';
100
- this.captionPosition = pluginOptions.captionPosition !== 'bottom' ? 'top' : 'bottom';
101
- this.cellControllerTop = (pluginOptions.cellControllerPosition !== 'cell' ? 'table' : 'cell') === 'table';
102
-
103
- // create HTML
104
- const menu = CreateHTML();
105
- const commandArea = menu.querySelector('.se-controller-table-picker');
106
- const controller_table = CreateHTML_controller_table(editor);
107
- const controller_cell = CreateHTML_controller_cell(editor, this.cellControllerTop);
108
- const controller_props = CreateHTML_controller_properties(editor);
109
-
110
- editor.applyFrameRoots((e) => {
111
- e.get('wrapper').appendChild(dom.utils.createElement('DIV', { class: RESIZE_CELL_CLASS.replace(/^\./, '') }));
112
- e.get('wrapper').appendChild(dom.utils.createElement('DIV', { class: RESIZE_CELL_PREV_CLASS.replace(/^\./, '') }));
113
- e.get('wrapper').appendChild(dom.utils.createElement('DIV', { class: RESIZE_ROW_CLASS.replace(/^\./, '') }));
114
- e.get('wrapper').appendChild(dom.utils.createElement('DIV', { class: RESIZE_ROW_PREV_CLASS.replace(/^\./, '') }));
115
- });
116
-
117
- // members - Controller
118
- this.controller_cell = new Controller(this, controller_cell.html, { position: this.cellControllerTop ? 'top' : 'bottom' });
119
- this.controller_table = new Controller(this, controller_table, { position: 'top' });
120
- if (this.cellControllerTop) {
121
- this.controller_cell.sibling = this.controller_table.form;
122
- this.controller_cell.siblingPosition = 'top';
123
- }
124
- // props
125
- const propsTargetForms = [this.controller_table.form, this.controller_cell.form];
126
- this.controller_props = new Controller(this, controller_props.html, { position: 'bottom', parents: propsTargetForms, isInsideForm: true });
127
- this.controller_props_title = controller_props.controller_props_title;
128
- // color picker
129
- const colorForm = dom.utils.createElement('DIV', { class: 'se-controller se-list-layer' }, null);
130
- this.colorPicker = new ColorPicker(this, '', {
131
- colorList: pluginOptions.colorList || DEFAULT_COLOR_LIST,
132
- splitNum: 5,
133
- disableRemove: true,
134
- hueSliderOptions: { controllerOptions: { parents: [colorForm], isOutsideForm: true } }
135
- });
136
-
137
- colorForm.appendChild(this.colorPicker.target);
138
- this.controller_colorPicker = new Controller(this, colorForm, {
139
- position: 'bottom',
140
- parents: [this.controller_props.form].concat(propsTargetForms),
141
- isInsideForm: true,
142
- isWWTarget: false,
143
- initMethod: () => {
144
- this.colorPicker.hueSlider.close();
145
- dom.utils.removeClass(this.controller_colorPicker.currentTarget, 'on');
146
- }
147
- });
148
-
149
- this.figure = new Figure(this, null, {});
150
-
151
- this.sliderType = '';
152
-
153
- // members - SelectMenu [cells]
154
- const openCellMenuFunc = _CellFormZIndex.bind(this, true);
155
- const closeCellMenuFunc = _CellFormZIndex.bind(this, false);
156
- // members - SelectMenu - split
157
- const splitMenu = CreateSplitMenu(this.lang);
158
- this.splitButton = controller_cell.splitButton;
159
- this.selectMenu_split = new SelectMenu(this, { checkList: false, position: 'bottom-center', openMethod: openCellMenuFunc, closeMethod: closeCellMenuFunc });
160
- this.selectMenu_split.on(this.splitButton, this.#OnSplitCells.bind(this));
161
- this.selectMenu_split.create(splitMenu.items, splitMenu.menus);
162
-
163
- // members - SelectMenu - column
164
- const columnMenu = CreateColumnMenu(this.lang, this.icons);
165
- const columnButton = controller_cell.columnButton;
166
- this.selectMenu_column = new SelectMenu(this, { checkList: false, position: 'bottom-center', openMethod: openCellMenuFunc, closeMethod: closeCellMenuFunc });
167
- this.selectMenu_column.on(columnButton, this.#OnColumnEdit.bind(this));
168
- this.selectMenu_column.create(columnMenu.items, columnMenu.menus);
169
-
170
- // members - SelectMenu - row
171
- const rownMenu = CreateRowMenu(this.lang, this.icons);
172
- const rowButton = controller_cell.rowButton;
173
- this.selectMenu_row = new SelectMenu(this, { checkList: false, position: 'bottom-center', openMethod: openCellMenuFunc, closeMethod: closeCellMenuFunc });
174
- this.selectMenu_row.on(rowButton, this.#OnRowEdit.bind(this));
175
- this.selectMenu_row.create(rownMenu.items, rownMenu.menus);
176
-
177
- // members - SelectMenu - properties - border style
178
- const borderMenu = CreateBorderMenu();
179
- const borderButton = controller_props.borderButton;
180
- this.selectMenu_props_border = new SelectMenu(this, { checkList: false, position: 'bottom-center' });
181
- this.selectMenu_props_border.on(borderButton, OnPropsBorderEdit.bind(this));
182
- this.selectMenu_props_border.create(borderMenu.items, borderMenu.menus);
183
-
184
- // members - SelectMenu - properties - border format
185
- const borderFormatMenu = CreateBorderFormatMenu(this.lang, this.icons, []);
186
- const borderFormatButton = controller_props.borderFormatButton;
187
- this.selectMenu_props_border_format = new SelectMenu(this, { checkList: false, position: 'bottom-left', dir: 'ltr', splitNum: 5 });
188
- this.selectMenu_props_border_format.on(borderFormatButton, OnPropsBorderFormatEdit.bind(this, 'all'));
189
- this.selectMenu_props_border_format.create(borderFormatMenu.items, borderFormatMenu.menus);
190
-
191
- const borderFormatMenu_oneCell = CreateBorderFormatMenu(this.lang, this.icons, BORDER_FORMAT_INSIDE);
192
- this.selectMenu_props_border_format_oneCell = new SelectMenu(this, { checkList: false, position: 'bottom-left', dir: 'ltr', splitNum: 6 });
193
- this.selectMenu_props_border_format_oneCell.on(borderFormatButton, OnPropsBorderFormatEdit.bind(this, 'outside'));
194
- this.selectMenu_props_border_format_oneCell.create(borderFormatMenu_oneCell.items, borderFormatMenu_oneCell.menus);
195
-
196
- // memberts - elements..
197
- this.maxText = this.lang.maxSize;
198
- this.minText = this.lang.minSize;
199
- this.propTargets = {
200
- cell_alignment: controller_props.cell_alignment,
201
- cell_alignment_vertical: controller_props.cell_alignment_vertical,
202
- cell_alignment_table_text: controller_props.cell_alignment_table_text,
203
- border_format: borderFormatButton,
204
- border_style: controller_props.border_style,
205
- border_color: controller_props.border_color,
206
- border_width: controller_props.border_width,
207
- back_color: controller_props.back_color,
208
- font_color: controller_props.font_color,
209
- palette_border_button: controller_props.palette_border_button,
210
- font_bold: controller_props.font_bold,
211
- font_underline: controller_props.font_underline,
212
- font_italic: controller_props.font_italic,
213
- font_strike: controller_props.font_strike
214
- };
215
- this._propsCache = [];
216
- this._currentFontStyles = [];
217
- this._propsAlignCache = '';
218
- this._propsVerticalAlignCache = '';
219
- this._typeCache = '';
220
-
221
- /** @type {HTMLElement} */
222
- this.tableHighlight = menu.querySelector('.se-table-size-highlighted');
223
- /** @type {HTMLElement} */
224
- this.tableUnHighlight = menu.querySelector('.se-table-size-unhighlighted');
225
- /** @type {HTMLElement} */
226
- this.tableDisplay = menu.querySelector('.se-table-size-display');
227
- /** @type {HTMLButtonElement} */
228
- this.resizeButton = controller_table.querySelector('._se_table_resize');
229
- /** @type {HTMLSpanElement} */
230
- this.resizeText = controller_table.querySelector('._se_table_resize > span > span');
231
- /** @type {HTMLButtonElement} */
232
- this.columnFixedButton = controller_table.querySelector('._se_table_fixed_column');
233
- /** @type {HTMLButtonElement} */
234
- this.headerButton = controller_table.querySelector('._se_table_header');
235
- /** @type {HTMLButtonElement} */
236
- this.captionButton = controller_table.querySelector('._se_table_caption');
237
- /** @type {HTMLButtonElement} */
238
- this.mergeButton = controller_cell.mergeButton;
239
- /** @type {HTMLButtonElement} */
240
- this.unmergeButton = controller_cell.unmergeButton;
241
-
242
- // members - private
243
- this._resizing = false;
244
- this._resizeLine = null;
245
- this._resizeLinePrev = null;
246
-
247
- /** @type {HTMLElement} */
248
- this._figure = null;
249
- /**
250
- * @description Same value a "this._selectedTable", but it maintain prev table element
251
- * @type {HTMLTableElement}
252
- */
253
- this._element = null;
254
- /** @type {HTMLTableCellElement} */
255
- this._tdElement = null;
256
- /** @type {HTMLTableRowElement} */
257
- this._trElement = null;
258
- /** @type {HTMLTableRowElement[]|HTMLCollectionOf<HTMLTableRowElement>} */
259
- this._trElements = null;
260
-
261
- this._tableXY = [];
262
- this._maxWidth = true;
263
- this._fixedColumn = false;
264
- this._physical_cellCnt = 0;
265
- this._logical_cellCnt = 0;
266
- this._cellCnt = 0;
267
- this._rowCnt = 0;
268
- this._rowIndex = 0;
269
- this._physical_cellIndex = 0;
270
- this._logical_cellIndex = 0;
271
- this._current_colSpan = 0;
272
- this._current_rowSpan = 0;
273
-
274
- // member - multi selecte
275
- /** @type {HTMLTableElement} */
276
- this._selectedTable = null;
277
- /** @type {HTMLTableCellElement} */
278
- this._fixedCell = null;
279
- /** @type {HTMLTableCellElement} */
280
- this._selectedCell = null;
281
- /** @type {HTMLTableCellElement[]} */
282
- this._selectedCells = null;
283
-
284
- this._shift = false;
285
- this.__s = false;
286
- this._fixedCellName = null;
287
- this._ref = null;
288
-
289
- // member - global events
290
- this._bindMultiOn = this.#OnCellMultiSelect.bind(this);
291
- this._bindMultiOff = this.#OffCellMultiSelect.bind(this);
292
- this._bindShiftOff = this.#OffCellShift.bind(this);
293
- this._bindTouchOff = this.#OffCellTouch.bind(this);
294
- this.__globalEvents = {
295
- on: null,
296
- off: null,
297
- shiftOff: null,
298
- touchOff: null,
299
- resize: null,
300
- resizeStop: null,
301
- resizeKeyDown: null
302
- };
303
-
304
- // init
305
- this.menu.initDropdownTarget(Table, menu);
306
- this.eventManager.addEvent(commandArea, 'mousemove', this.#OnMouseMoveTablePicker.bind(this));
307
- this.eventManager.addEvent(commandArea, 'click', this.#OnClickTablePicker.bind(this));
308
- }
309
-
310
- /**
311
- * @editorMethod Editor.core
312
- * @description Executes the main execution method of the plugin.
313
- * - Called when an item in the "dropdown" menu is clicked.
314
- */
315
- action() {
316
- const oTable = dom.utils.createElement('TABLE');
317
- const x = this._tableXY[0];
318
- const y = this._tableXY[1];
319
-
320
- const body = `<tbody>${`<tr>${CreateCellsString('td', x)}</tr>`.repeat(y)}</tbody>`;
321
- const colGroup = `<colgroup>${`<col style="width: ${numbers.get(100 / x, CELL_DECIMAL_END)}%;">`.repeat(x)}</colgroup>`;
322
- oTable.innerHTML = colGroup + body;
323
-
324
- // scroll
325
- let scrollTypeClass = '';
326
- if (this.figureScroll) {
327
- scrollTypeClass = ` se-scroll-figure-${this.figureScroll}`;
328
- }
329
-
330
- const figure = dom.utils.createElement('FIGURE', { class: 'se-flex-component se-input-component' + scrollTypeClass });
331
- figure.appendChild(oTable);
332
-
333
- if (this.component.insert(figure, { skipCharCount: false, skipSelection: false, skipHistory: false })) {
334
- this._resetTablePicker();
335
- const target = oTable.querySelector('td div');
336
- this.selection.setRange(target, 0, target, 0);
337
- }
338
- }
339
-
340
- /**
341
- * @editorMethod Editor.component
342
- * @description Executes the method that is called when a component of a plugin is selected.
343
- * @param {HTMLElement} target Target component element
344
- */
345
- select(target) {
346
- this._figureOpen(target);
347
- if (!this._figure) this.setTableInfo(target);
348
-
349
- const targetWidth = this._figure?.style.width || '100%';
350
- this._maxWidth = targetWidth === '100%';
351
- this._fixedColumn = dom.utils.hasClass(target, 'se-table-layout-fixed') || target.style.tableLayout === 'fixed';
352
- this._setTableStyle(this._maxWidth ? 'width|column' : 'width', true);
353
-
354
- if (_DragHandle.get('__overInfo') === ON_OVER_COMPONENT) return;
355
-
356
- if (!this._tdElement) return;
357
- this.setCellInfo(this._tdElement, true);
358
-
359
- // controller open
360
- const btnDisabled = this._selectedCells?.length > 1;
361
- const figureEl = dom.query.getParentElement(target, dom.check.isFigure);
362
- this.controller_table.open(figureEl, null, { isWWTarget: false, initMethod: null, addOffset: null, disabled: btnDisabled });
363
-
364
- if (!this._fixedCell) return;
365
-
366
- this._setUnMergeButton();
367
- this.controller_cell.open(this._tdElement, this.cellControllerTop ? figureEl : null, { isWWTarget: false, initMethod: null, addOffset: null, disabled: btnDisabled });
368
- }
369
-
370
- /**
371
- * @editorMethod Editor.component
372
- * @description Executes the method that is called when a component copy is requested.
373
- * @param {__se__PluginCopyComponentParams} params
374
- * @returns {boolean|void}
375
- */
376
- onCopyComponent({ event, cloneContainer }) {
377
- /** @type {NodeListOf<HTMLTableCellElement>} */
378
- const selectedCells = cloneContainer.querySelectorAll('.se-selected-table-cell');
379
- dom.utils.removeClass(selectedCells, 'se-selected-table-cell|se-selected-cell-focus');
380
-
381
- if (selectedCells.length > 0) {
382
- SetClipboardSelectedTableCells(event, cloneContainer, selectedCells);
383
- this.editor.ui.showToast(this.lang.message_copy_success, 550);
384
- }
385
- }
386
-
387
- /**
388
- * @editorMethod Editor.EventManager
389
- * @description Executes the event function of "copy".
390
- * @param {__se__PluginPasteParams} params
391
- * @returns {boolean|void}
392
- */
393
- onPaste({ event, doc }) {
394
- /** @type {HTMLTableCellElement} */
395
- const targetCell = dom.query.getParentElement(dom.query.getEventTarget(event), dom.check.isTableCell);
396
- if (!targetCell) return;
397
-
398
- const domParserBody = doc.body;
399
- if (domParserBody.childElementCount !== 1) return;
400
-
401
- const componentInfo = this.component.get(domParserBody.firstElementChild);
402
- if (componentInfo.pluginName !== Table.key) return;
403
-
404
- const copyTable = /** @type {HTMLTableElement} */ (componentInfo.target);
405
- this.pasteTableCellMatrix(copyTable, targetCell);
406
-
407
- return true;
408
- }
409
-
410
- /**
411
- * @editorMethod Editor.core
412
- * @description This method is used to validate and preserve the format of the component within the editor.
413
- * - It ensures that the structure and attributes of the element are maintained and secure.
414
- * - The method checks if the element is already wrapped in a valid container and updates its attributes if necessary.
415
- * - If the element isn't properly contained, a new container is created to retain the format.
416
- * @returns {{query: string, method: (element: HTMLTableElement) => void}} The format retention object containing the query and method to process the element.
417
- * - query: The selector query to identify the relevant elements (in this case, 'audio').
418
- * - method:The function to execute on the element to validate and preserve its format.
419
- * - The function takes the element as an argument, checks if it is contained correctly, and applies necessary adjustments.
420
- */
421
- retainFormat() {
422
- return {
423
- query: 'table',
424
- method: (element) => {
425
- const ColgroupEl = element.querySelector('colgroup');
426
- let FigureEl = /** @type {HTMLElement} */ (dom.check.isFigure(element.parentNode) ? element.parentNode : null);
427
-
428
- // create colgroup
429
- if (!ColgroupEl) {
430
- const rows = element.rows;
431
- const firstRow = rows[0];
432
- const maxCount = GetMaxColumns(element);
433
- const colHTML = [];
434
-
435
- for (let i = 0; i < maxCount; i++) {
436
- let colStyle = '';
437
- if (firstRow && firstRow.cells[i]) {
438
- const styleWidth = firstRow.cells[i].style.width;
439
- if (styleWidth) {
440
- colStyle = ` style="width: ${styleWidth};"`;
441
- dom.utils.setStyle(firstRow.cells[i], 'width', '');
442
- }
443
- }
444
- colHTML.push(`<col${colStyle}>`);
445
- }
446
-
447
- const colGroup = dom.utils.createElement('colgroup', null, colHTML.join(''));
448
- element.insertBefore(colGroup, element.firstElementChild);
449
- }
450
-
451
- // figure
452
- if (!FigureEl) {
453
- FigureEl = dom.utils.createElement('FIGURE', { class: 'se-flex-component se-input-component' });
454
- element.parentNode.insertBefore(FigureEl, element);
455
- FigureEl.appendChild(element);
456
- } else {
457
- dom.utils.addClass(FigureEl, 'se-flex-component|se-input-component');
458
- }
459
-
460
- // table width
461
- if (element.style.width) {
462
- FigureEl.style.width = element.style.width;
463
- dom.utils.setStyle(element, 'width', '');
464
- }
465
-
466
- // scroll
467
- if (!this.figureScroll) {
468
- dom.utils.removeClass(FigureEl, this.figureScrollList.join('|'));
469
- } else {
470
- const scrollTypeClass = `se-scroll-figure-${this.figureScroll}`;
471
- dom.utils.addClass(FigureEl, scrollTypeClass);
472
- dom.utils.removeClass(FigureEl, this.figureScrollList.filter((v) => v !== scrollTypeClass).join('|'));
473
- }
474
- }
475
- };
476
- }
477
-
478
- /**
479
- * @editorMethod Editor.core
480
- * @description Executes the method called when the rtl, ltr mode changes. ("editor.setDir")
481
- * @param {string} dir Direction ("rtl" or "ltr")
482
- */
483
- setDir(dir) {
484
- this.tableHighlight.style.left = dir === 'rtl' ? 10 * 18 - 13 + 'px' : '';
485
- this._resetTablePicker();
486
- this._resetPropsAlign();
487
- }
488
-
489
- /**
490
- * @editorMethod Editor.EventManager
491
- * @description Executes the event function of "mousemove".
492
- * @param {__se__PluginMouseEventInfo} params
493
- */
494
- onMouseMove({ event }) {
495
- if (this._resizing) return;
496
-
497
- const eventTarget = dom.query.getEventTarget(event);
498
- const target = dom.query.getParentElement(eventTarget, IsResizeEls);
499
- if (!target) {
500
- this.__hideResizeLine();
501
- return;
502
- }
503
-
504
- const cellEdge = CheckCellEdge(event, target);
505
- if (cellEdge.is) {
506
- if (this._element) this._element.style.cursor = '';
507
- this.__removeGlobalEvents();
508
- if (this._resizeLine?.style.display === 'block') this._resizeLine.style.display = 'none';
509
- this._resizeLine = this.editor.frameContext.get('wrapper').querySelector(RESIZE_CELL_CLASS);
510
- this._setResizeLinePosition(dom.query.getParentElement(target, dom.check.isTable), target, this._resizeLine, cellEdge.isLeft);
511
- this._resizeLine.style.display = 'block';
512
- return;
513
- }
514
-
515
- const rowEdge = CheckRowEdge(event, target);
516
- if (rowEdge.is) {
517
- this.__removeGlobalEvents();
518
- this._element = dom.query.getParentElement(target, dom.check.isTable);
519
- this._element.style.cursor = 'ns-resize';
520
- if (this._resizeLine?.style.display === 'block') this._resizeLine.style.display = 'none';
521
- this._resizeLine = this.editor.frameContext.get('wrapper').querySelector(RESIZE_ROW_CLASS);
522
- this._setResizeRowPosition(dom.query.getParentElement(target, dom.check.isTable), target, this._resizeLine);
523
- this._resizeLine.style.display = 'block';
524
- return;
525
- }
526
-
527
- if (this._element) this._element.style.cursor = '';
528
- this.__hideResizeLine();
529
- }
530
-
531
- /**
532
- * @editorMethod Editor.EventManager
533
- * @description Executes the event function of "scroll".
534
- */
535
- onScroll() {
536
- if (this._resizeLine?.style.display !== 'block') return;
537
- // delete resize line position
538
- if (this._element) this._element.style.cursor = '';
539
- this._resizeLine.style.display = 'none';
540
- }
541
-
542
- /**
543
- * @editorMethod Editor.EventManager
544
- * @description Executes the event function of "mousedown".
545
- * @param {__se__PluginMouseEventInfo} params
546
- */
547
- onMouseDown({ event }) {
548
- this._ref = this._selectedCell = null;
549
- const eventTarget = dom.query.getEventTarget(event);
550
- const target = /** @type {HTMLTableCellElement} */ (dom.query.getParentElement(eventTarget, IsResizeEls));
551
- if (!target) return;
552
-
553
- if (!this.cellControllerTop) {
554
- this.controller_cell.hide();
555
- }
556
-
557
- const cellEdge = CheckCellEdge(event, target);
558
- if (cellEdge.is) {
559
- try {
560
- this._deleteStyleSelectedCells();
561
- this.setCellInfo(target, true);
562
- const colIndex = this._logical_cellIndex - (cellEdge.isLeft ? 1 : 0);
563
-
564
- // ready
565
- this.ui.enableBackWrapper('ew-resize');
566
- if (!this._resizeLine) this._resizeLine = this.editor.frameContext.get('wrapper').querySelector(RESIZE_CELL_CLASS);
567
- this._resizeLinePrev = this.editor.frameContext.get('wrapper').querySelector(RESIZE_CELL_PREV_CLASS);
568
-
569
- // select figure
570
- if (colIndex < 0 || colIndex === this._logical_cellCnt - 1) {
571
- this._startFigureResizing(cellEdge.startX, colIndex < 0);
572
- return;
573
- }
574
-
575
- const col = this._element.querySelector('colgroup').querySelectorAll('col')[colIndex < 0 ? 0 : colIndex];
576
- this._startCellResizing(col, cellEdge.startX, numbers.get(_w.getComputedStyle(col).width, CELL_DECIMAL_END), cellEdge.isLeft);
577
- this._toggleEditor(false);
578
- } catch (err) {
579
- console.warn('[SUNEDITOR.plugins.table.error]', err);
580
- this.__removeGlobalEvents();
581
- } finally {
582
- this._fixedCell = this._selectedCell = null;
583
- }
584
-
585
- return;
586
- }
587
-
588
- const rowEdge = CheckRowEdge(event, target);
589
- if (rowEdge.is) {
590
- try {
591
- /** @type {HTMLTableRowElement} */
592
- let row = dom.query.getParentElement(target, dom.check.isTableRow);
593
- let rowSpan = target.rowSpan;
594
- if (rowSpan > 1) {
595
- while (dom.check.isTableRow(row) && rowSpan > 1) {
596
- row = /** @type {HTMLTableRowElement} */ (row.nextElementSibling);
597
- --rowSpan;
598
- }
599
- }
600
-
601
- this._deleteStyleSelectedCells();
602
- this.setRowInfo(row);
603
-
604
- // ready
605
- this.ui.enableBackWrapper('ns-resize');
606
- if (!this._resizeLine) this._resizeLine = this.editor.frameContext.get('wrapper').querySelector(RESIZE_ROW_CLASS);
607
- this._resizeLinePrev = this.editor.frameContext.get('wrapper').querySelector(RESIZE_ROW_PREV_CLASS);
608
-
609
- this._startRowResizing(row, rowEdge.startY, numbers.get(_w.getComputedStyle(row).height, CELL_DECIMAL_END));
610
- this._toggleEditor(false);
611
- } catch (err) {
612
- console.warn('[SUNEDITOR.plugins.table.error]', err);
613
- this.__removeGlobalEvents();
614
- } finally {
615
- this._fixedCell = this._selectedCell = null;
616
- }
617
-
618
- return;
619
- }
620
-
621
- if (this._shift && target !== this._fixedCell) return;
622
-
623
- this._deleteStyleSelectedCells();
624
- if (/^TR$/i.test(target.nodeName)) return;
625
-
626
- this.#StyleSelectCells(target, false);
627
- }
628
-
629
- /**
630
- * @editorMethod Editor.EventManager
631
- * @description Executes the event function of "mouseup".
632
- */
633
- onMouseUp() {
634
- this._shift = false;
635
- if (!this.cellControllerTop) {
636
- this.controller_cell.resetPosition(this._fixedCell);
637
- }
638
- }
639
-
640
- /**
641
- * @editorMethod Editor.EventManager
642
- * @description Executes the event function of "mouseleave".
643
- */
644
- onMouseLeave() {
645
- this.__hideResizeLine();
646
- }
647
-
648
- /**
649
- * @editorMethod Editor.EventManager
650
- * @description Executes the event function of "keydown".
651
- * @param {__se__PluginKeyEventInfo} params
652
- */
653
- onKeyDown({ event, range, line }) {
654
- this._ref = null;
655
-
656
- const keyCode = event.code;
657
- const isTab = keyCodeMap.isTab(keyCode);
658
- if (this.editor.selectMenuOn || this._resizing || (!isTab && this.__s) || keyCodeMap.isCtrl(event)) return;
659
-
660
- if (!this.cellControllerTop) {
661
- this.controller_cell.hide();
662
- }
663
-
664
- this.__s = keyCodeMap.isShift(event);
665
-
666
- // table tabkey
667
- if (isTab) {
668
- this._deleteStyleSelectedCells();
669
- const tableCell = dom.query.getParentElement(line, dom.check.isTableCell);
670
- if (tableCell && range.collapsed && dom.check.isEdgePoint(range.startContainer, range.startOffset)) {
671
- this._closeController();
672
-
673
- const shift = this.__s;
674
- this._shift = this.__s = false;
675
-
676
- /** @type {HTMLTableElement} */
677
- const table = dom.query.getParentElement(tableCell, 'table');
678
- /** @type {HTMLTableCellElement[]} */
679
- const cells = dom.query.getListChildren(table, dom.check.isTableCell);
680
- const idx = shift ? dom.utils.prevIndex(cells, tableCell) : dom.utils.nextIndex(cells, tableCell);
681
-
682
- if (idx === cells.length && !shift) {
683
- if (!dom.query.getParentElement(tableCell, 'thead')) {
684
- const rows = table.rows;
685
- const newRow = this.insertBodyRow(table, rows.length, this._cellCnt);
686
- const firstTd = newRow.querySelector('td div');
687
- this.selection.setRange(firstTd, 0, firstTd, 0);
688
- }
689
-
690
- event.preventDefault();
691
- event.stopPropagation();
692
-
693
- return false;
694
- }
695
-
696
- if (idx === -1 && shift) return false;
697
-
698
- const moveCell = cells[idx];
699
- if (!moveCell) return;
700
-
701
- const rangeCell = moveCell.firstElementChild || moveCell;
702
- this.selection.setRange(rangeCell, 0, rangeCell, 0);
703
-
704
- event.preventDefault();
705
- event.stopPropagation();
706
-
707
- return false;
708
- }
709
- }
710
-
711
- let cell = null;
712
- if (!keyCodeMap.isShift(event)) {
713
- cell = dom.query.getParentElement(line, dom.check.isTableCell);
714
- if (!dom.utils.hasClass(cell, 'se-selected-cell-focus')) return;
715
-
716
- this._deleteStyleSelectedCells();
717
- this._toggleEditor(true);
718
- this.__removeGlobalEvents();
719
- this._closeController();
720
-
721
- return;
722
- }
723
-
724
- if (this._shift || this._ref) return;
725
-
726
- cell = /** @type {HTMLTableCellElement} */ (cell || dom.query.getParentElement(line, dom.check.isTableCell));
727
- if (cell) {
728
- this.__s = false;
729
- this._fixedCell = cell;
730
- this._closeController();
731
- this.#StyleSelectCells(cell, event.shiftKey);
732
- return false;
733
- }
734
- }
735
-
736
- /**
737
- * @editorMethod Editor.EventManager
738
- * @description Executes the event function of "keyup".
739
- * @param {__se__PluginKeyEventInfo} params
740
- */
741
- onKeyUp({ line }) {
742
- this.__s = false;
743
- if (this._shift && dom.query.getParentElement(line, dom.check.isTableCell) === this._fixedCell) {
744
- this._deleteStyleSelectedCells();
745
- this._toggleEditor(true);
746
- this.__removeGlobalEvents();
747
- }
748
- this._shift = false;
749
- }
750
-
751
- /**
752
- * @editorMethod Modules.ColorPicker
753
- * @description Executes the method called when a button of "ColorPicker" module is clicked.
754
- * @param {string} color - Color code (hex)
755
- */
756
- colorPickerAction(color) {
757
- const target = this.propTargets[`${this.sliderType}_color`];
758
- target.style.borderColor = target.value = color;
759
- this.controller_colorPicker.close();
760
- }
761
-
762
- /**
763
- * @editorMethod Modules.Controller
764
- * @description Executes the method that is called when a button is clicked in the "controller".
765
- * @param {HTMLButtonElement} target Target button element
766
- */
767
- controllerAction(target) {
768
- const command = target.getAttribute('data-command');
769
- if (!command) return;
770
-
771
- const { back_color, font_color, border_color } = this.propTargets;
772
- const value = target.getAttribute('data-value');
773
-
774
- switch (command) {
775
- case 'header':
776
- this.toggleHeader();
777
- this._historyPush();
778
- break;
779
- case 'caption':
780
- this.toggleCaption();
781
- this._historyPush();
782
- break;
783
- case 'onsplit':
784
- this.selectMenu_split.open();
785
- break;
786
- case 'oncolumn':
787
- this.selectMenu_column.open();
788
- break;
789
- case 'onrow':
790
- this.selectMenu_row.menus[0].style.display = this.selectMenu_row.menus[1].style.display = /^TH$/i.test(this._tdElement?.nodeName) ? 'none' : '';
791
- this.selectMenu_row.open();
792
- break;
793
- case 'openTableProperties':
794
- if (this.controller_props.currentTarget === target && this.controller_props.form?.style.display === 'block') {
795
- this.controller_props.close();
796
- } else {
797
- this.controller_props_title.textContent = this.lang.tableProperties;
798
- this._setCtrlProps('table');
799
- this.controller_props.open(target, this.controller_table.form, { isWWTarget: false, initMethod: null, addOffset: null });
800
- }
801
- break;
802
- case 'openCellProperties':
803
- if (this.controller_props.currentTarget === target && this.controller_props.form?.style.display === 'block') {
804
- this.controller_props.close();
805
- } else {
806
- this.controller_props_title.textContent = this.lang.cellProperties;
807
- this._setCtrlProps('cell');
808
- this.controller_props.open(target, this.controller_cell.form, { isWWTarget: false, initMethod: null, addOffset: null });
809
- }
810
- break;
811
- case 'props_onborder_format':
812
- if (this._propsCache.length === 1) {
813
- this.selectMenu_props_border_format_oneCell.open();
814
- } else {
815
- this.selectMenu_props_border_format.open();
816
- }
817
- break;
818
- case 'props_onborder_style':
819
- this.selectMenu_props_border.open();
820
- break;
821
- case 'props_onpalette':
822
- this._onColorPalette(target, value, value === 'border' ? border_color : value === 'back' ? back_color : font_color);
823
- break;
824
- case 'props_font_style':
825
- dom.utils.toggleClass(this.propTargets[`font_${value}`], 'on');
826
- break;
827
- case 'props_submit':
828
- this._submitProps(target);
829
- break;
830
- case 'revert': {
831
- const propsCache = this._propsCache;
832
- for (let i = 0, len = propsCache.length; i < len; i++) {
833
- propsCache[i][0].style.cssText = propsCache[i][1];
834
- }
835
- // alignment
836
- this._setAlignProps(this.propTargets.cell_alignment, this._propsAlignCache, true);
837
- this._setAlignProps(this.propTargets.cell_alignment_vertical, this._propsVerticalAlignCache, true);
838
- if (dom.check.isTable(propsCache[0][0]) && this._figure) {
839
- this._figure.style.float = this._propsAlignCache;
840
- }
841
- break;
842
- }
843
- case 'close_props':
844
- this.controller_props.close();
845
- break;
846
- case 'props_align':
847
- this._setAlignProps(this.propTargets.cell_alignment, target.getAttribute('data-value'), false);
848
- break;
849
- case 'props_align_vertical':
850
- this._setAlignProps(this.propTargets.cell_alignment_vertical, target.getAttribute('data-value'), false);
851
- break;
852
- case 'merge':
853
- this.mergeCells(this._selectedCells);
854
- break;
855
- case 'unmerge':
856
- this.unmergeCells(this._selectedCells);
857
- break;
858
- case 'resize':
859
- this._maxWidth = !this._maxWidth;
860
- this._setTableStyle('width', false);
861
- this._historyPush();
862
- this.component.select(this._element, Table.key, { isInput: true });
863
- break;
864
- case 'layout':
865
- this._fixedColumn = !this._fixedColumn;
866
- this._setTableStyle('column', false);
867
- this._historyPush();
868
- this.component.select(this._element, Table.key, { isInput: true });
869
- break;
870
- case 'copy':
871
- this.component.copy(this._figure);
872
- break;
873
- case 'remove': {
874
- const emptyDiv = this._figure?.parentNode;
875
- dom.utils.removeItem(this._figure);
876
-
877
- this._closeTableSelectInfo();
878
-
879
- if (emptyDiv !== this.editor.frameContext.get('wysiwyg'))
880
- this.nodeTransform.removeAllParents(
881
- emptyDiv,
882
- function (current) {
883
- return current.childNodes.length === 0;
884
- },
885
- null
886
- );
887
- this.editor.focus();
888
- this.history.push(false);
889
- }
890
- }
891
-
892
- if (!/(^props_|^revert|Properties$)/.test(command)) {
893
- this.controller_props.close();
894
- this.controller_colorPicker.close();
895
- }
896
-
897
- if (!/^(remove|props_|on|open|merge)/.test(command)) {
898
- this._setCellControllerPosition(this._tdElement, this._shift);
899
- }
900
- }
901
-
902
- /**
903
- * @editorMethod Modules.Controller
904
- * @description Executes the method called when the "controller" is closed.
905
- */
906
- close() {
907
- this.__removeGlobalEvents();
908
- this._deleteStyleSelectedCells();
909
- this._toggleEditor(true);
910
-
911
- this._figure = null;
912
- this._element = null;
913
- this._trElement = null;
914
- this._trElements = null;
915
- this._tableXY = [];
916
- this._maxWidth = false;
917
- this._fixedColumn = false;
918
- this._physical_cellCnt = 0;
919
- this._logical_cellCnt = 0;
920
- this._rowCnt = 0;
921
- this._rowIndex = 0;
922
- this._physical_cellIndex = 0;
923
- this._logical_cellIndex = 0;
924
- this._current_colSpan = 0;
925
- this._current_rowSpan = 0;
926
-
927
- this._shift = false;
928
- this._selectedCells = null;
929
- this._selectedTable = null;
930
- this._ref = null;
931
-
932
- this._fixedCell = null;
933
- this._selectedCell = null;
934
- this._fixedCellName = null;
935
-
936
- const { border_format, border_color, border_style, border_width, back_color, font_color, cell_alignment, cell_alignment_vertical, font_bold, font_underline, font_italic, font_strike } = this.propTargets;
937
- dom.utils.removeClass([border_format, border_color, border_style, border_width, back_color, font_color, cell_alignment, cell_alignment_vertical, font_bold, font_underline, font_italic, font_strike], 'on');
938
- }
939
-
940
- /**
941
- * @description Selects a group of table cells and sets internal state related to multi-cell selection.
942
- * @param {HTMLTableCellElement[]} cells - An array of table cell elements to be selected.
943
- */
944
- selectCells(cells) {
945
- const firstCell = cells[0];
946
- const lastCell = dom.query.findVisualLastCell(cells);
947
-
948
- this._selectedCells = cells;
949
- this._fixedCell = firstCell;
950
- this._selectedCell = lastCell;
951
- this._fixedCellName = firstCell.nodeName;
952
- this._selectedTable = dom.query.getParentElement(firstCell, 'TABLE');
953
-
954
- this._setMultiCells(firstCell, lastCell);
955
- }
956
-
957
- /**
958
- * @description Sets the table and figure elements based on the provided cell element, and stores references to them for later use.
959
- * @param {Node} element The target table cell (`<td>`) element from which the table info will be extracted.
960
- * @returns {HTMLTableElement} The `<table>` element that is the parent of the provided `element`.
961
- */
962
- setTableInfo(element) {
963
- const table = (this._element = this._selectedTable = dom.query.getParentElement(element, 'TABLE'));
964
- this._figure = dom.query.getParentElement(table, dom.check.isFigure) || table;
965
- return /** @type {HTMLTableElement} */ (table);
966
- }
967
-
968
- /**
969
- * @description Sets various table-related information based on the provided table cell element (`<td>`). This includes updating cell, row, and table attributes, handling spanning cells, and adjusting the UI for elements like headers and captions.
970
- * @param {HTMLTableCellElement} tdElement The target table cell (`<td>`) element from which table information will be extracted.
971
- * @param {boolean} reset A flag indicating whether to reset the cell information. If `true`, the cell information will be reset and recalculated.
972
- */
973
- setCellInfo(tdElement, reset) {
974
- const table = this.setTableInfo(tdElement);
975
- if (!table) return;
976
- this._fixedCell = tdElement;
977
- this._trElement = /** @type {HTMLTableRowElement} */ (tdElement.parentNode);
978
-
979
- // hedaer
980
- if (table.querySelector('thead')) dom.utils.addClass(this.headerButton, 'active');
981
- else dom.utils.removeClass(this.headerButton, 'active');
982
-
983
- // caption
984
- if (table.querySelector('caption')) dom.utils.addClass(this.captionButton, 'active');
985
- else dom.utils.removeClass(this.captionButton, 'active');
986
-
987
- if (reset || this._physical_cellCnt === 0) {
988
- if (this._tdElement !== tdElement) {
989
- this._tdElement = tdElement;
990
- this._trElement = /** @type {HTMLTableRowElement} */ (tdElement.parentNode);
991
- }
992
-
993
- if (!this._selectedCells?.length) this._selectedCells = [tdElement];
994
-
995
- const rows = (this._trElements = table.rows);
996
- const cellIndex = tdElement.cellIndex;
997
-
998
- let cellCnt = 0;
999
- for (let i = 0, cells = rows[0].cells, len = rows[0].cells.length; i < len; i++) {
1000
- cellCnt += cells[i].colSpan;
1001
- }
1002
-
1003
- // row cnt, row index
1004
- const rowIndex = (this._rowIndex = this._trElement.rowIndex);
1005
- this._rowCnt = rows.length;
1006
-
1007
- // cell cnt, physical cell index
1008
- this._physical_cellCnt = this._trElement.cells.length;
1009
- this._logical_cellCnt = this._cellCnt = cellCnt;
1010
- this._physical_cellIndex = cellIndex;
1011
-
1012
- // span
1013
- this._current_colSpan = this._tdElement.colSpan - 1;
1014
- this._current_rowSpan = this._trElement.cells[cellIndex].rowSpan - 1;
1015
-
1016
- // find logcal cell index
1017
- let rowSpanArr = [];
1018
- let spanIndex = [];
1019
- for (let i = 0, cells, colSpan; i <= rowIndex; i++) {
1020
- cells = rows[i].cells;
1021
- colSpan = 0;
1022
- for (let c = 0, cLen = cells.length, cell, cs, rs, logcalIndex; c < cLen; c++) {
1023
- cell = cells[c];
1024
- cs = cell.colSpan - 1;
1025
- rs = cell.rowSpan - 1;
1026
- logcalIndex = c + colSpan;
1027
-
1028
- if (spanIndex.length > 0) {
1029
- for (let r = 0, arr; r < spanIndex.length; r++) {
1030
- arr = spanIndex[r];
1031
- if (arr.row > i) continue;
1032
- if (logcalIndex >= arr.index) {
1033
- colSpan += arr.cs;
1034
- logcalIndex += arr.cs;
1035
- arr.rs -= 1;
1036
- arr.row = i + 1;
1037
- if (arr.rs < 1) {
1038
- spanIndex.splice(r, 1);
1039
- r--;
1040
- }
1041
- } else if (c === cLen - 1) {
1042
- arr.rs -= 1;
1043
- arr.row = i + 1;
1044
- if (arr.rs < 1) {
1045
- spanIndex.splice(r, 1);
1046
- r--;
1047
- }
1048
- }
1049
- }
1050
- }
1051
-
1052
- // logcal cell index
1053
- if (i === rowIndex && c === cellIndex) {
1054
- this._logical_cellIndex = logcalIndex;
1055
- break;
1056
- }
1057
-
1058
- if (rs > 0) {
1059
- rowSpanArr.push({
1060
- index: logcalIndex,
1061
- cs: cs + 1,
1062
- rs: rs,
1063
- row: -1
1064
- });
1065
- }
1066
-
1067
- colSpan += cs;
1068
- }
1069
-
1070
- spanIndex = spanIndex.concat(rowSpanArr).sort(function (a, b) {
1071
- return a.index - b.index;
1072
- });
1073
- rowSpanArr = [];
1074
- }
1075
-
1076
- rowSpanArr = null;
1077
- spanIndex = null;
1078
- }
1079
- }
1080
-
1081
- /**
1082
- * @description Sets row-related information based on the provided table row element (`<tr>`). This includes updating the row count and the index of the selected row.
1083
- * @param {HTMLTableRowElement} trElement The target table row (`<tr>`) element from which row information will be extracted.
1084
- */
1085
- setRowInfo(trElement) {
1086
- const table = this.setTableInfo(trElement);
1087
- const rows = (this._trElements = table.rows);
1088
- this._rowCnt = rows.length;
1089
- this._rowIndex = trElement.rowIndex;
1090
- }
1091
-
1092
- /**
1093
- * @description Edits the table by adding, removing, or modifying rows and cells, based on the provided options. Supports both single and multi-cell/row editing.
1094
- * @param {"row"|"cell"} type The type of element to edit ('row' or 'cell').
1095
- * @param {?"up"|"down"|"left"|"right"} option The action to perform: 'up', 'down', 'left', 'right', or `null` for removing.
1096
- */
1097
- editTable(type, option) {
1098
- const table = this._element;
1099
- const isRow = type === 'row';
1100
-
1101
- if (isRow) {
1102
- const tableAttr = this._trElement.parentElement;
1103
- if (/^THEAD$/i.test(tableAttr.nodeName)) {
1104
- if (option === 'up') {
1105
- return;
1106
- } else if (!tableAttr.nextElementSibling || !/^TBODY$/i.test(tableAttr.nextElementSibling.nodeName)) {
1107
- if (!option) {
1108
- dom.utils.removeItem(this._figure);
1109
- this._closeTableSelectInfo();
1110
- } else {
1111
- table.innerHTML += '<tbody><tr>' + CreateCellsString('td', this._logical_cellCnt) + '</tr></tbody>';
1112
- }
1113
- return;
1114
- }
1115
- }
1116
- }
1117
-
1118
- // multi
1119
- if (this._ref) {
1120
- const positionCell = this._tdElement;
1121
- const selectedCells = this._selectedCells;
1122
- // multi - row
1123
- if (isRow) {
1124
- // remove row
1125
- if (!option) {
1126
- let row = selectedCells[0].parentNode;
1127
- const removeCells = [selectedCells[0]];
1128
-
1129
- for (let i = 1, len = selectedCells.length, cell; i < len; i++) {
1130
- cell = selectedCells[i];
1131
- if (row !== cell.parentNode) {
1132
- removeCells.push(cell);
1133
- row = cell.parentNode;
1134
- }
1135
- }
1136
-
1137
- for (let i = 0, len = removeCells.length; i < len; i++) {
1138
- this.setCellInfo(removeCells[i], true);
1139
- this.editRow(option);
1140
- }
1141
- } else {
1142
- // edit row
1143
- this.setCellInfo(option === 'up' ? selectedCells[0] : selectedCells[selectedCells.length - 1], true);
1144
- this.editRow(option, null, positionCell);
1145
- }
1146
- } else {
1147
- // multi - cell
1148
- const firstRow = selectedCells[0].parentNode;
1149
- // remove cell
1150
- if (!option) {
1151
- const removeCells = [selectedCells[0]];
1152
-
1153
- for (let i = 1, len = selectedCells.length, cell; i < len; i++) {
1154
- cell = selectedCells[i];
1155
- if (firstRow === cell.parentNode) {
1156
- removeCells.push(cell);
1157
- } else {
1158
- break;
1159
- }
1160
- }
1161
-
1162
- for (let i = 0, len = removeCells.length; i < len; i++) {
1163
- this.setCellInfo(removeCells[i], true);
1164
- this.editCell(option);
1165
- }
1166
- } else {
1167
- // edit cell
1168
- let rightCell = null;
1169
-
1170
- for (let i = 0, len = selectedCells.length - 1; i < len; i++) {
1171
- if (firstRow !== selectedCells[i + 1].parentNode) {
1172
- rightCell = selectedCells[i];
1173
- break;
1174
- }
1175
- }
1176
-
1177
- this.setCellInfo(option === 'left' ? selectedCells[0] : rightCell || selectedCells[0], true);
1178
- this.editCell(option, null, positionCell);
1179
- }
1180
- }
1181
-
1182
- if (!option) this.close();
1183
- } // one
1184
- else {
1185
- this[isRow ? 'editRow' : 'editCell'](option);
1186
- }
1187
-
1188
- // after remove
1189
- if (!option) {
1190
- const children = table.children;
1191
- for (let i = 0; i < children.length; i++) {
1192
- if (children[i].children.length === 0) {
1193
- dom.utils.removeItem(children[i]);
1194
- i--;
1195
- }
1196
- }
1197
-
1198
- if (table.children.length === 0) dom.utils.removeItem(table);
1199
- }
1200
- }
1201
-
1202
- /**
1203
- * @description Edits a table row, either adding, removing, the row
1204
- * @param {?string} option The action to perform on the row ("up"|"down"|null)
1205
- * - null: to remove the row
1206
- * - 'up': to insert the row up
1207
- * - 'down': to insert the row down, or null to remove.
1208
- * @param {?HTMLTableCellElement=} targetCell Target cell, (default: current selected cell)
1209
- * @param {?HTMLTableCellElement=} [positionResetElement] The element to reset the position of (optional). This can be the cell that triggered the row edit.
1210
- */
1211
- editRow(option, targetCell, positionResetElement) {
1212
- this._deleteStyleSelectedCells();
1213
- if (targetCell) this.setCellInfo(targetCell, true);
1214
-
1215
- const remove = !option;
1216
- const up = option === 'up';
1217
- const originRowIndex = this._rowIndex;
1218
- const rowIndex = remove || up ? originRowIndex : originRowIndex + this._current_rowSpan + 1;
1219
- const sign = remove ? -1 : 1;
1220
-
1221
- const rows = this._trElements;
1222
- let cellCnt = this._logical_cellCnt;
1223
-
1224
- for (let i = 0, len = originRowIndex + (remove ? -1 : 0), cell; i <= len; i++) {
1225
- cell = rows[i].cells;
1226
- if (cell.length === 0) return;
1227
-
1228
- for (let c = 0, cLen = cell.length, rs, cs; c < cLen; c++) {
1229
- rs = cell[c].rowSpan;
1230
- cs = cell[c].colSpan;
1231
- if (rs < 2 && cs < 2) continue;
1232
-
1233
- if (rs + i > rowIndex && rowIndex > i) {
1234
- cell[c].rowSpan = rs + sign;
1235
- cellCnt -= cs;
1236
- }
1237
- }
1238
- }
1239
-
1240
- if (remove) {
1241
- const next = rows[originRowIndex + 1];
1242
- if (next) {
1243
- const spanCells = [];
1244
- let cells = rows[originRowIndex].cells;
1245
- let colSpan = 0;
1246
-
1247
- for (let i = 0, len = cells.length, cell, logcalIndex; i < len; i++) {
1248
- cell = cells[i];
1249
- logcalIndex = i + colSpan;
1250
- colSpan += cell.colSpan - 1;
1251
-
1252
- if (cell.rowSpan > 1) {
1253
- cell.rowSpan -= 1;
1254
- spanCells.push({ cell: /** @type {HTMLTableCellElement} */ (cell.cloneNode(false)), index: logcalIndex });
1255
- }
1256
- }
1257
-
1258
- if (spanCells.length > 0) {
1259
- let spanCell = spanCells.shift();
1260
- cells = next.cells;
1261
- colSpan = 0;
1262
-
1263
- for (let i = 0, len = cells.length, cell, logcalIndex; i < len; i++) {
1264
- cell = cells[i];
1265
- logcalIndex = i + colSpan;
1266
- colSpan += cell.colSpan - 1;
1267
-
1268
- if (logcalIndex >= spanCell.index) {
1269
- i--;
1270
- colSpan--;
1271
- colSpan += spanCell.cell.colSpan - 1;
1272
- next.insertBefore(spanCell.cell, cell);
1273
- spanCell = spanCells.shift();
1274
- if (!spanCell) break;
1275
- }
1276
- }
1277
-
1278
- if (spanCell) {
1279
- next.appendChild(spanCell.cell);
1280
- for (let i = 0, len = spanCells.length; i < len; i++) {
1281
- next.appendChild(spanCells[i].cell);
1282
- }
1283
- }
1284
- }
1285
- }
1286
-
1287
- this._element.deleteRow(rowIndex);
1288
- } else {
1289
- this.insertBodyRow(this._element, rowIndex, cellCnt);
1290
- }
1291
-
1292
- if (!remove) {
1293
- this._setCellControllerPosition(positionResetElement || this._tdElement, true);
1294
- } else {
1295
- this._closeController();
1296
- }
1297
- }
1298
-
1299
- /**
1300
- * @description Edits a table cell(column), either adding, removing, or modifying the cell based on the provided option.
1301
- * @param {?string} option The action to perform on the cell ("left"|"right"|null)
1302
- * - null: to remove the cell
1303
- * - left: to insert a new cell to the left
1304
- * - right: to insert a new cell to the right
1305
- * @param {?HTMLTableCellElement=} targetCell Target cell, (default: current selected cell)
1306
- * @param {?HTMLTableCellElement=} positionResetElement The element to reset the position of (optional). This can be the cell that triggered the column edit.
1307
- * @returns {HTMLTableCellElement} Target table cell
1308
- */
1309
- editCell(option, targetCell, positionResetElement) {
1310
- if (targetCell) this.setCellInfo(targetCell, true);
1311
-
1312
- const remove = !option;
1313
- const left = option === 'left';
1314
- const colSpan = this._current_colSpan;
1315
- const cellIndex = remove || left ? this._logical_cellIndex : this._logical_cellIndex + colSpan + 1;
1316
-
1317
- const rows = this._trElements;
1318
- let rowSpanArr = [];
1319
- let spanIndex = [];
1320
- let passCell = 0;
1321
- let insertIndex;
1322
- const removeCell = [];
1323
- const removeSpanArr = [];
1324
-
1325
- for (let i = 0, len = this._rowCnt, row, cells, newCell, applySpan, cellColSpan; i < len; i++) {
1326
- row = rows[i];
1327
- insertIndex = cellIndex;
1328
- applySpan = false;
1329
- cells = row.cells;
1330
- cellColSpan = 0;
1331
-
1332
- for (let c = 0, cell, cLen = cells.length, rs, cs, removeIndex; c < cLen; c++) {
1333
- cell = cells[c];
1334
- if (!cell) break;
1335
-
1336
- rs = cell.rowSpan - 1;
1337
- cs = cell.colSpan - 1;
1338
-
1339
- if (!remove) {
1340
- if (c >= insertIndex) break;
1341
- if (cs > 0) {
1342
- if (passCell < 1 && cs + c >= insertIndex) {
1343
- cell.colSpan += 1;
1344
- insertIndex = null;
1345
- passCell = rs + 1;
1346
- break;
1347
- }
1348
-
1349
- insertIndex -= cs;
1350
- }
1351
-
1352
- if (!applySpan) {
1353
- for (let r = 0, arr; r < spanIndex.length; r++) {
1354
- arr = spanIndex[r];
1355
- insertIndex -= arr.cs;
1356
- arr.rs -= 1;
1357
- if (arr.rs < 1) {
1358
- spanIndex.splice(r, 1);
1359
- r--;
1360
- }
1361
- }
1362
- applySpan = true;
1363
- }
1364
- } else {
1365
- removeIndex = c + cellColSpan;
1366
-
1367
- if (spanIndex.length > 0) {
1368
- const lastCell = !cells[c + 1];
1369
- for (let r = 0, arr; r < spanIndex.length; r++) {
1370
- arr = spanIndex[r];
1371
- if (arr.row > i) continue;
1372
-
1373
- if (removeIndex >= arr.index) {
1374
- cellColSpan += arr.cs;
1375
- removeIndex = c + cellColSpan;
1376
- arr.rs -= 1;
1377
- arr.row = i + 1;
1378
- if (arr.rs < 1) {
1379
- spanIndex.splice(r, 1);
1380
- r--;
1381
- }
1382
- } else if (lastCell) {
1383
- arr.rs -= 1;
1384
- arr.row = i + 1;
1385
- if (arr.rs < 1) {
1386
- spanIndex.splice(r, 1);
1387
- r--;
1388
- }
1389
- }
1390
- }
1391
- }
1392
-
1393
- if (rs > 0) {
1394
- rowSpanArr.push({
1395
- rs: rs,
1396
- cs: cs + 1,
1397
- index: removeIndex,
1398
- row: -1
1399
- });
1400
- }
1401
-
1402
- if (removeIndex >= insertIndex && removeIndex + cs <= insertIndex + colSpan) {
1403
- removeCell.push(cell);
1404
- } else if (removeIndex <= insertIndex + colSpan && removeIndex + cs >= insertIndex) {
1405
- cell.colSpan -= numbers.getOverlapRangeAtIndex(cellIndex, cellIndex + colSpan, removeIndex, removeIndex + cs);
1406
- } else if (rs > 0 && (removeIndex < insertIndex || removeIndex + cs > insertIndex + colSpan)) {
1407
- removeSpanArr.push({
1408
- cell: cell,
1409
- i: i,
1410
- rs: i + rs
1411
- });
1412
- }
1413
-
1414
- cellColSpan += cs;
1415
- }
1416
- }
1417
-
1418
- spanIndex = spanIndex.concat(rowSpanArr).sort(function (a, b) {
1419
- return a.index - b.index;
1420
- });
1421
- rowSpanArr = [];
1422
-
1423
- if (!remove) {
1424
- if (passCell > 0) {
1425
- passCell -= 1;
1426
- continue;
1427
- }
1428
-
1429
- if (insertIndex !== null && cells.length > 0) {
1430
- newCell = CreateCellsHTML(cells[0].nodeName);
1431
- newCell = row.insertBefore(newCell, cells[insertIndex]);
1432
- }
1433
- }
1434
- }
1435
-
1436
- const colgroup = this._element.querySelector('colgroup');
1437
- if (colgroup) {
1438
- const cols = colgroup.querySelectorAll('col');
1439
- if (remove) {
1440
- dom.utils.removeItem(cols[insertIndex]);
1441
- } else {
1442
- let totalW = 0;
1443
- for (let i = 0, len = cols.length, w; i < len; i++) {
1444
- w = numbers.get(cols[i].style.width);
1445
- w -= Math.round((w * len * 0.1) / 2);
1446
- totalW += w;
1447
- cols[i].style.width = `${w}%`;
1448
- }
1449
- const newCol = dom.utils.createElement('col', { style: `width:${100 - totalW}%` });
1450
- colgroup.insertBefore(newCol, cols[insertIndex]);
1451
- }
1452
- }
1453
-
1454
- if (remove) {
1455
- let removeFirst, removeEnd;
1456
- for (let r = 0, rLen = removeCell.length, row; r < rLen; r++) {
1457
- row = /** @type {HTMLTableRowElement} */ (removeCell[r].parentNode);
1458
- dom.utils.removeItem(removeCell[r]);
1459
- if (row.cells.length === 0) {
1460
- if (!removeFirst) removeFirst = dom.utils.getArrayIndex(rows, row);
1461
- removeEnd = dom.utils.getArrayIndex(rows, row);
1462
- dom.utils.removeItem(row);
1463
- }
1464
- }
1465
-
1466
- for (let c = 0, cLen = removeSpanArr.length, rowSpanCell; c < cLen; c++) {
1467
- rowSpanCell = removeSpanArr[c];
1468
- rowSpanCell.cell.rowSpan = numbers.getOverlapRangeAtIndex(removeFirst, removeEnd, rowSpanCell.i, rowSpanCell.rs);
1469
- }
1470
-
1471
- this._closeController();
1472
- } else {
1473
- this._setCellControllerPosition(positionResetElement || this._tdElement, true);
1474
- }
1475
-
1476
- return positionResetElement || this._tdElement;
1477
- }
1478
-
1479
- /**
1480
- * @description Updates the target table's cells with the data from the copied table.
1481
- * @param {HTMLTableElement} copyTable The table containing the copied data.
1482
- * @param {HTMLTableCellElement} targetTD The starting cell in the target table where data will be pasted.
1483
- */
1484
- pasteTableCellMatrix(copyTable, targetTD) {
1485
- if (!copyTable || !targetTD) return;
1486
-
1487
- // --- copy info ---
1488
- const copyRows = copyTable.rows;
1489
- let rowCnt = 0;
1490
- const colIndexMap = [];
1491
- for (let row = 0; row < copyRows.length; row++) {
1492
- const cells = copyRows[row].cells;
1493
- let logicalCol = 0;
1494
-
1495
- for (let i = 0; i < cells.length; i++) {
1496
- const cell = cells[i];
1497
-
1498
- while (colIndexMap[row]?.[logicalCol]) {
1499
- logicalCol++;
1500
- }
1501
-
1502
- const rowspan = cell.rowSpan || 1;
1503
- const colspan = cell.colSpan || 1;
1504
-
1505
- if (logicalCol === 0) {
1506
- rowCnt += rowspan;
1507
- }
1508
-
1509
- // rowspan map
1510
- for (let r = 0; r < rowspan; r++) {
1511
- for (let c = 0; c < colspan; c++) {
1512
- if (!colIndexMap[row + r]) colIndexMap[row + r] = [];
1513
- colIndexMap[row + r][logicalCol + c] = true;
1514
- }
1515
- }
1516
-
1517
- logicalCol += colspan;
1518
- }
1519
- }
1520
-
1521
- let logicalColCount = 0;
1522
- for (let i = 0, cells = copyRows[0].cells, len = cells.length; i < len; i++) {
1523
- const cell = cells[i];
1524
- logicalColCount += cell.colSpan || 1;
1525
- }
1526
-
1527
- const copyInfo = {
1528
- rowCnt: rowCnt,
1529
- logicalCellCnt: logicalColCount
1530
- };
1531
-
1532
- // --- target info ---
1533
- this._deleteStyleSelectedCells();
1534
- const originTable = targetTD.closest('table');
1535
- const { cloneTable, clonedSelectedCells } = this.#cloneTable(originTable, [targetTD]);
1536
-
1537
- const targetTable = cloneTable;
1538
- targetTD = clonedSelectedCells[0];
1539
- let targetRows = targetTable.rows;
1540
- this.setTableInfo(targetTable);
1541
- this.setCellInfo(targetTD, true);
1542
-
1543
- const targetInfo = {
1544
- physicalCellCnt: this._physical_cellCnt,
1545
- logicalCellCnt: this._logical_cellCnt,
1546
- rowCnt: this._rowCnt,
1547
- rowInex: this._rowIndex,
1548
- physicalCellIndex: this._physical_cellIndex,
1549
- logicalCellIndex: this._logical_cellIndex,
1550
- currentColSpan: this._current_colSpan,
1551
- currentRowSpan: this._current_rowSpan
1552
- };
1553
-
1554
- // --- [expand] target table ---
1555
- const addRowCnt = copyInfo.rowCnt - (targetInfo.rowCnt - (targetInfo.rowInex + 1)) - 1;
1556
- const addColCnt = copyInfo.logicalCellCnt - (targetInfo.logicalCellCnt - (targetInfo.logicalCellIndex + 1)) - 1;
1557
- targetInfo.rowCnt += addRowCnt;
1558
- targetInfo.logicalCellCnt += addColCnt;
1559
- targetInfo.physicalCellCnt += addColCnt;
1560
-
1561
- if (addRowCnt > 0 || addColCnt > 0) {
1562
- const lastRow = targetRows[targetRows.length - 1];
1563
- const lastCell = lastRow.cells[lastRow.cells.length - 1];
1564
- for (let i = 0; i < addRowCnt; i++) {
1565
- this.editRow('down', lastCell);
1566
- }
1567
- for (let i = 0; i < addColCnt; i++) {
1568
- this.editCell('right', lastCell);
1569
- }
1570
- targetRows = this._trElements = targetTable.rows;
1571
- }
1572
-
1573
- // --- [Un_merge] cells ---
1574
- const startRowIndex = targetInfo.rowInex;
1575
- const cellIndex = targetInfo.logicalCellIndex;
1576
- const cellEndIndex = cellIndex + copyInfo.logicalCellCnt - 1;
1577
- const unmergeCells = [];
1578
- const un_mergeRowSpanMap = [];
1579
-
1580
- for (let r = 0, len = startRowIndex + copyInfo.rowCnt; r < len; r++) {
1581
- const cells = targetRows[r]?.cells;
1582
- if (!cells) continue;
1583
-
1584
- let logicalIndex = 0;
1585
- let cellIndexInRow = 0;
1586
-
1587
- for (let c = 0; c < cells.length; c++) {
1588
- while (un_mergeRowSpanMap[r]?.[logicalIndex]) {
1589
- logicalIndex++;
1590
- }
1591
-
1592
- const cell = cells[cellIndexInRow++];
1593
- if (!cell) break;
1594
-
1595
- const cs = cell.colSpan || 1;
1596
- const rs = cell.rowSpan || 1;
1597
- const logicalStart = logicalIndex;
1598
- const logicalEnd = logicalIndex + cs - 1;
1599
-
1600
- // rowSpan map
1601
- if (rs > 1 || cs > 1) {
1602
- for (let rsOffset = 1; rsOffset < rs; rsOffset++) {
1603
- const rowIndex = r + rsOffset;
1604
- if (!un_mergeRowSpanMap[rowIndex]) un_mergeRowSpanMap[rowIndex] = [];
1605
- for (let csOffset = 0; csOffset < cs; csOffset++) {
1606
- un_mergeRowSpanMap[rowIndex][logicalIndex + csOffset] = true;
1607
- }
1608
- }
1609
- }
1610
-
1611
- const isOverlap = logicalStart <= cellEndIndex && logicalEnd >= cellIndex;
1612
- if (isOverlap && (cs > 1 || rs > 1)) {
1613
- unmergeCells.push(cell);
1614
- }
1615
-
1616
- logicalIndex += cs;
1617
- }
1618
- }
1619
-
1620
- if (unmergeCells.length > 0) {
1621
- this.unmergeCells(unmergeCells, true);
1622
- targetRows = this._trElements = targetTable.rows;
1623
- }
1624
-
1625
- // --- [merge] cells ---
1626
- const mergeGroups = [];
1627
- const copyCowSpanMap = [];
1628
- const targetRowSpanMap = [];
1629
- for (let r = 0, len = copyInfo.rowCnt; r < len; r++) {
1630
- const cells = copyRows[r]?.cells;
1631
- if (!cells) break;
1632
-
1633
- let copyIndex = 0;
1634
- for (let c = 0; c < cells.length; c++) {
1635
- const cell = cells[c];
1636
- const cs = cell.colSpan || 1;
1637
- const rs = cell.rowSpan || 1;
1638
-
1639
- while (copyCowSpanMap[r]?.[copyIndex]) {
1640
- copyIndex++;
1641
- }
1642
-
1643
- for (let rsOffset = 1; rsOffset < rs; rsOffset++) {
1644
- const rowIndex = r + rsOffset;
1645
- if (!copyCowSpanMap[rowIndex]) copyCowSpanMap[rowIndex] = [];
1646
- for (let csOffset = 0; csOffset < cs; csOffset++) {
1647
- copyCowSpanMap[rowIndex][copyIndex + csOffset] = true;
1648
- }
1649
- }
1650
-
1651
- if (cs <= 1 && rs <= 1) {
1652
- copyIndex += cs;
1653
- continue;
1654
- }
1655
-
1656
- const cStart = copyIndex + targetInfo.logicalCellIndex;
1657
- const cEnd = cStart + cs - 1;
1658
- const mergeCells = [];
1659
-
1660
- for (let targetR = targetInfo.rowInex + r, tRowCnt = targetR + rs, rowOffset = 0; targetR < tRowCnt; targetR++, rowOffset++) {
1661
- const targetRow = targetRows[targetR];
1662
- const targetCells = targetRow.cells;
1663
-
1664
- let logicalIndex = 0;
1665
- let targetIndex = 0;
1666
-
1667
- while (targetIndex < targetCells.length && logicalIndex <= cEnd) {
1668
- while (targetRowSpanMap[targetR]?.[logicalIndex]) {
1669
- logicalIndex++;
1670
- }
1671
-
1672
- const tCell = targetCells[targetIndex++];
1673
- const tcs = tCell.colSpan || 1;
1674
- const trs = tCell.rowSpan || 1;
1675
- const logicalStart = logicalIndex;
1676
- const logicalEnd = logicalIndex + tcs - 1;
1677
-
1678
- // rowSpan map
1679
- if (trs > 1) {
1680
- for (let rsOffset = 1; rsOffset < trs; rsOffset++) {
1681
- const rIndex = targetR + rsOffset;
1682
- if (!targetRowSpanMap[rIndex]) targetRowSpanMap[rIndex] = [];
1683
- for (let i = 0; i < tcs; i++) {
1684
- targetRowSpanMap[rIndex][logicalIndex + i] = true;
1685
- }
1686
- }
1687
- }
1688
-
1689
- if (logicalEnd >= cStart && logicalStart <= cEnd) {
1690
- mergeCells.push(tCell);
1691
- }
1692
-
1693
- logicalIndex += tcs;
1694
- }
1695
- }
1696
-
1697
- if (mergeCells.length > 0) {
1698
- mergeGroups.push(mergeCells);
1699
- }
1700
-
1701
- copyIndex += cs;
1702
- }
1703
- }
1704
-
1705
- if (mergeGroups.length > 0) {
1706
- for (const mc of mergeGroups) {
1707
- this._ref = null;
1708
- this._trElements = targetTable.rows;
1709
- this.mergeCells(mc, true);
1710
- }
1711
- targetRows = this._trElements = targetTable.rows;
1712
- }
1713
-
1714
- // --- [result] paste cell data ---
1715
- const selectedCells = [];
1716
- const rowSpanMap = [];
1717
- for (let r = 0; r < copyInfo.rowCnt; r++) {
1718
- const tr = targetRows[targetInfo.rowInex + r];
1719
- const cr = copyRows[r];
1720
- if (!tr || !cr) break;
1721
-
1722
- const tCells = tr.cells;
1723
- const cCells = cr.cells;
1724
-
1725
- let tLogicalIndex = 0;
1726
- let tIndex = 0;
1727
- let cIndex = 0;
1728
-
1729
- while (tIndex < tCells.length && cIndex < cCells.length && tLogicalIndex <= cellEndIndex) {
1730
- while (rowSpanMap[r]?.[tLogicalIndex]) {
1731
- tLogicalIndex++;
1732
- }
1733
-
1734
- const tCell = tCells[tIndex++];
1735
- const cCell = cCells[cIndex];
1736
- if (!tCell || !cCell) break;
1737
-
1738
- const tcs = tCell.colSpan || 1;
1739
- const trs = tCell.rowSpan || 1;
1740
-
1741
- // rowSpan map
1742
- if (trs > 1) {
1743
- for (let rs = 1; rs < trs; rs++) {
1744
- const rr = r + rs;
1745
- if (!rowSpanMap[rr]) rowSpanMap[rr] = [];
1746
- for (let cs = 0; cs < tcs; cs++) {
1747
- rowSpanMap[rr][tLogicalIndex + cs] = true;
1748
- }
1749
- }
1750
- }
1751
-
1752
- if (tLogicalIndex >= cellIndex && tLogicalIndex + tcs - 1 <= cellEndIndex) {
1753
- tCell.innerHTML = cCell.innerHTML;
1754
- selectedCells.push(tCell);
1755
- cIndex++;
1756
- }
1757
-
1758
- tLogicalIndex += tcs;
1759
- }
1760
- }
1761
-
1762
- // replace table
1763
- originTable.replaceWith(targetTable);
1764
- this._closeTableSelectInfo();
1765
- this.setTableInfo(targetTable);
1766
-
1767
- // select cell
1768
- this.selectCells(selectedCells);
1769
- this._setMergeSplitButton();
1770
- this._setUnMergeButton();
1771
- this.#focusEdge(selectedCells[0]);
1772
-
1773
- // history push
1774
- this._historyPush();
1775
- }
1776
-
1777
- /**
1778
- * @description Inserts a new row into the table at the specified index to it.
1779
- * @param {HTMLTableElement} table The table element to insert the row into.
1780
- * @param {number} rowIndex The index at which to insert the new row.
1781
- * @param {number} cellCnt The number of cells to create in the new row.
1782
- * @returns {HTMLTableRowElement} The newly inserted row element.
1783
- */
1784
- insertBodyRow(table, rowIndex, cellCnt) {
1785
- const newRow = table.insertRow(rowIndex);
1786
- newRow.innerHTML = CreateCellsString('td', cellCnt);
1787
- return newRow;
1788
- }
1789
-
1790
- /**
1791
- * @description Merges the selected table cells into one cell by combining their contents and adjusting their row and column spans.
1792
- * - This method removes the selected cells, consolidates their contents, and applies the appropriate row and column spans to the merged cell.
1793
- * @param {HTMLTableCellElement[]} selectedCells Cells array
1794
- * @param {boolean} [skipPostProcess=false] - If true, skips table cloning, cell re-selection, history stack push, and rendering.
1795
- */
1796
- mergeCells(selectedCells, skipPostProcess = false) {
1797
- const originTable = selectedCells[0].closest('table');
1798
- const { cloneTable, clonedSelectedCells } = skipPostProcess ? { cloneTable: originTable, clonedSelectedCells: selectedCells } : this.#cloneTable(originTable, selectedCells);
1799
-
1800
- this.setTableInfo(cloneTable);
1801
- selectedCells = clonedSelectedCells;
1802
- this._ref = null;
1803
- this._setMultiCells(selectedCells[0], dom.query.findVisualLastCell(selectedCells));
1804
-
1805
- const ref = this._ref;
1806
- const mergeCell = selectedCells[0];
1807
-
1808
- let emptyRowFirst = null;
1809
- let emptyRowLast = null;
1810
- const cs = ref.ce - ref.cs + 1;
1811
- let rs = ref.re - ref.rs + 1;
1812
- let mergeHTML = '';
1813
- let row = null;
1814
-
1815
- for (let i = 1, len = selectedCells.length, cell, ch; i < len; i++) {
1816
- cell = selectedCells[i];
1817
- if (row !== cell.parentNode) row = /** @type {HTMLTableRowElement} */ (cell.parentNode);
1818
-
1819
- ch = cell.children;
1820
- for (let c = 0, cLen = ch.length; c < cLen; c++) {
1821
- if (this.format.isLine(ch[c]) && dom.check.isZeroWidth(ch[c].textContent)) {
1822
- dom.utils.removeItem(ch[c]);
1823
- }
1824
- }
1825
-
1826
- mergeHTML += cell.innerHTML;
1827
- dom.utils.removeItem(cell);
1828
-
1829
- if (row.cells.length === 0) {
1830
- if (!emptyRowFirst) emptyRowFirst = row;
1831
- else emptyRowLast = row;
1832
- rs -= 1;
1833
- }
1834
- }
1835
-
1836
- if (emptyRowFirst) {
1837
- const rows = this._trElements;
1838
- const rowIndexFirst = dom.utils.getArrayIndex(rows, emptyRowFirst);
1839
- const rowIndexLast = dom.utils.getArrayIndex(rows, emptyRowLast || emptyRowFirst);
1840
- const removeRows = [];
1841
-
1842
- for (let i = 0, cells; i <= rowIndexLast; i++) {
1843
- cells = rows[i].cells;
1844
- if (cells.length === 0) {
1845
- removeRows.push(rows[i]);
1846
- continue;
1847
- }
1848
-
1849
- for (let c = 0, cLen = cells.length, cell, rs2; c < cLen; c++) {
1850
- cell = cells[c];
1851
- rs2 = cell.rowSpan - 1;
1852
- if (rs2 > 0 && i + rs2 >= rowIndexFirst) {
1853
- cell.rowSpan -= numbers.getOverlapRangeAtIndex(rowIndexFirst, rowIndexLast, i, i + rs2);
1854
- }
1855
- }
1856
- }
1857
-
1858
- for (let i = 0, len = removeRows.length; i < len; i++) {
1859
- dom.utils.removeItem(removeRows[i]);
1860
- }
1861
- }
1862
-
1863
- mergeCell.innerHTML += mergeHTML;
1864
- mergeCell.colSpan = cs;
1865
- mergeCell.rowSpan = rs;
1866
-
1867
- if (skipPostProcess) return;
1868
-
1869
- // replace table
1870
- originTable.replaceWith(cloneTable);
1871
- this._closeTableSelectInfo();
1872
-
1873
- this._setMergeSplitButton();
1874
- this._setController(mergeCell);
1875
-
1876
- this.#focusEdge(mergeCell);
1877
-
1878
- // history push
1879
- this._historyPush();
1880
- }
1881
-
1882
- /**
1883
- * @description Unmerges a table cell that has been merged using rowspan and/or colspan.
1884
- * @param {HTMLTableCellElement[]} selectedCells - Cells array
1885
- * @param {boolean} [skipPostProcess=false] - If true, skips table cloning, cell re-selection, history stack push, and rendering.
1886
- */
1887
- unmergeCells(selectedCells, skipPostProcess = false) {
1888
- if (!selectedCells?.length) return;
1889
-
1890
- const originTable = selectedCells[0].closest('table');
1891
- const { cloneTable, clonedSelectedCells } = skipPostProcess ? { cloneTable: originTable, clonedSelectedCells: selectedCells } : this.#cloneTable(originTable, selectedCells);
1892
-
1893
- this._ref = null;
1894
- this.setTableInfo(cloneTable);
1895
- selectedCells = clonedSelectedCells;
1896
-
1897
- let firstCell = selectedCells[0];
1898
- let lastCell = dom.query.findVisualLastCell(selectedCells);
1899
- let newLastCell = null;
1900
-
1901
- const table = firstCell.closest('table');
1902
- const rows = table.rows;
1903
-
1904
- for (const cell of selectedCells) {
1905
- const tr = /** @type {HTMLTableRowElement} */ (cell.parentElement);
1906
- const rowIndex = tr.rowIndex;
1907
- const colIndex = cell.cellIndex;
1908
- const rowspan = cell.rowSpan;
1909
- const colspan = cell.colSpan;
1910
-
1911
- if (rowspan === 1 && colspan === 1) continue;
1912
-
1913
- this.setCellInfo(cell, true);
1914
-
1915
- const originalHTML = cell.innerHTML;
1916
- cell.remove();
1917
-
1918
- for (let r = 0; r < rowspan; r++) {
1919
- const targetRow = rows[rowIndex + r];
1920
-
1921
- for (let c = 0; c < colspan; c++) {
1922
- const newCell = CreateCellsHTML('td');
1923
-
1924
- if (r === 0 && c === 0) {
1925
- if (firstCell === cell) firstCell = newCell;
1926
- if (lastCell === cell) lastCell = newCell;
1927
- newCell.innerHTML = originalHTML;
1928
- targetRow.insertBefore(newCell, targetRow.cells[colIndex]);
1929
- } else {
1930
- targetRow.insertBefore(newCell, targetRow.cells[colIndex + c]);
1931
- newLastCell = newCell;
1932
- }
1933
- }
1934
- }
1935
- }
1936
-
1937
- this._selectedCells = null;
1938
-
1939
- if (skipPostProcess) return;
1940
-
1941
- // replace table
1942
- originTable.replaceWith(cloneTable);
1943
- this._closeTableSelectInfo();
1944
- this.setTableInfo(cloneTable);
1945
-
1946
- // set info
1947
- if (firstCell !== lastCell) {
1948
- lastCell = !newLastCell || lastCell.closest('tr').rowIndex > newLastCell.closest('tr').rowIndex || lastCell.cellIndex > newLastCell.cellIndex ? lastCell : newLastCell;
1949
- this._setMultiCells(firstCell, lastCell);
1950
- this._selectedCells = Array.from(table.querySelectorAll('.se-selected-table-cell'));
1951
- } else {
1952
- this.setCellInfo(lastCell, true);
1953
- }
1954
-
1955
- this._fixedCell = firstCell;
1956
- this._selectedCell = lastCell;
1957
- dom.utils.addClass(lastCell, 'se-selected-cell-focus');
1958
-
1959
- this._setUnMergeButton();
1960
- this.controller_cell.resetPosition(lastCell);
1961
-
1962
- // history push
1963
- this._historyPush();
1964
- }
1965
-
1966
- /**
1967
- * @description Find merged cells
1968
- * @param {HTMLTableCellElement[]} cells - Cells array
1969
- */
1970
- findMergedCells(cells) {
1971
- const mergedCells = [];
1972
- cells?.forEach((cell) => {
1973
- if (cell && (cell.rowSpan > 1 || cell.colSpan > 1)) {
1974
- mergedCells.push(cell);
1975
- }
1976
- });
1977
- return mergedCells;
1978
- }
1979
-
1980
- /**
1981
- * @description Toggles the visibility of the table header (`<thead>`). If the header is present, it is removed; if absent, it is added.
1982
- */
1983
- toggleHeader() {
1984
- const btn = this.headerButton;
1985
- const active = dom.utils.hasClass(btn, 'active');
1986
- const table = this._element;
1987
-
1988
- if (!active) {
1989
- const header = dom.utils.createElement('THEAD');
1990
- header.innerHTML = '<tr>' + CreateCellsString('th', this._logical_cellCnt) + '</tr>';
1991
- table.insertBefore(header, table.firstElementChild);
1992
- } else {
1993
- dom.utils.removeItem(table.querySelector('thead'));
1994
- }
1995
-
1996
- dom.utils.toggleClass(btn, 'active');
1997
-
1998
- if (/TH/i.test(this._tdElement.nodeName)) {
1999
- this._closeController();
2000
- } else {
2001
- this._setCellControllerPosition(this._tdElement, false);
2002
- }
2003
- }
2004
-
2005
- /**
2006
- * @description Toggles the visibility of the table caption (`<caption>`). If the caption is present, it is removed; if absent, it is added.
2007
- */
2008
- toggleCaption() {
2009
- const btn = this.captionButton;
2010
- const active = dom.utils.hasClass(btn, 'active');
2011
- const table = this._element;
2012
-
2013
- if (!active) {
2014
- const caption = dom.utils.createElement('CAPTION', { class: `se-table-caption-${this.captionPosition}` });
2015
- caption.innerHTML = '<div><br></div>';
2016
- table.insertBefore(caption, table.firstElementChild);
2017
- } else {
2018
- dom.utils.removeItem(table.querySelector('caption'));
2019
- }
2020
-
2021
- dom.utils.toggleClass(btn, 'active');
2022
- this._setCellControllerPosition(this._tdElement, false);
2023
- }
2024
-
2025
- /**
2026
- * @private
2027
- * @description Updates table styles.
2028
- * @param {string} styles - Styles to update.
2029
- * @param {boolean} ondisplay - Whether to update display.
2030
- */
2031
- _setTableStyle(styles, ondisplay) {
2032
- if (styles.includes('width')) {
2033
- const targets = this._figure;
2034
- if (!targets) return;
2035
-
2036
- let sizeIcon, text;
2037
- if (!this._maxWidth) {
2038
- sizeIcon = this.icons.expansion;
2039
- text = this.maxText;
2040
- if (!ondisplay) targets.style.width = 'min-content';
2041
- } else {
2042
- sizeIcon = this.icons.reduction;
2043
- text = this.minText;
2044
- if (!ondisplay) targets.style.width = '100%';
2045
- }
2046
-
2047
- dom.utils.changeElement(this.resizeButton.firstElementChild, sizeIcon);
2048
- dom.utils.changeTxt(this.resizeText, text);
2049
- }
2050
-
2051
- if (styles.includes('column')) {
2052
- if (!this._fixedColumn) {
2053
- dom.utils.removeClass(this._element, 'se-table-layout-fixed');
2054
- dom.utils.addClass(this._element, 'se-table-layout-auto');
2055
- dom.utils.removeClass(this.columnFixedButton, 'active');
2056
- } else {
2057
- dom.utils.removeClass(this._element, 'se-table-layout-auto');
2058
- dom.utils.addClass(this._element, 'se-table-layout-fixed');
2059
- dom.utils.addClass(this.columnFixedButton, 'active');
2060
- }
2061
- }
2062
- }
2063
-
2064
- /**
2065
- * @private
2066
- * @description Sets the merge/split button visibility.
2067
- */
2068
- _setMergeSplitButton() {
2069
- if (!this._ref) {
2070
- this.splitButton.style.display = 'block';
2071
- this.mergeButton.style.display = 'none';
2072
- } else {
2073
- this.splitButton.style.display = 'none';
2074
- this.mergeButton.style.display = 'block';
2075
- }
2076
- }
2077
-
2078
- /**
2079
- * @private
2080
- * @description Sets the unmerge button visibility.
2081
- */
2082
- _setUnMergeButton() {
2083
- if (this.findMergedCells(!this._selectedCells?.length ? [this._fixedCell] : this._selectedCells).length > 0) {
2084
- this.unmergeButton.disabled = false;
2085
- } else {
2086
- this.unmergeButton.disabled = true;
2087
- }
2088
- }
2089
-
2090
- /**
2091
- * @private
2092
- * @description Sets the controller position for a cell.
2093
- * @param {HTMLTableCellElement} tdElement - The target table cell.
2094
- */
2095
- _setController(tdElement) {
2096
- if (!this.selection.get().isCollapsed && !this._selectedCell) {
2097
- this._deleteStyleSelectedCells();
2098
- return;
2099
- }
2100
-
2101
- this._setUnMergeButton();
2102
-
2103
- this._tdElement = tdElement;
2104
- if (this._fixedCell === tdElement) dom.utils.addClass(tdElement, 'se-selected-cell-focus');
2105
- if (!this._selectedCells?.length) this._selectedCells = [tdElement];
2106
- const tableElement = this._selectedTable || this._element || dom.query.getParentElement(tdElement, 'TABLE');
2107
- this.component.select(tableElement, Table.key, { isInput: true });
2108
- }
2109
-
2110
- /**
2111
- * @private
2112
- * @description Sets the position of the cell controller.
2113
- * @param {HTMLTableCellElement} tdElement - The target table cell.
2114
- * @param {boolean} reset - Whether to reset the controller position.
2115
- */
2116
- _setCellControllerPosition(tdElement, reset) {
2117
- this.setCellInfo(tdElement, reset);
2118
- this.controller_cell.resetPosition(this.cellControllerTop ? dom.query.getParentElement(tdElement, dom.check.isTable) : tdElement);
2119
- }
2120
-
2121
- /**
2122
- * @private
2123
- * @description Adds a new entry to the history stack.
2124
- */
2125
- _historyPush() {
2126
- this._deleteStyleSelectedCells();
2127
- this.history.push(false);
2128
- this._recallStyleSelectedCells();
2129
- }
2130
-
2131
- /**
2132
- * @private
2133
- * @description Opens the figure.
2134
- * @param {Node} target - The target figure element.
2135
- */
2136
- _figureOpen(target) {
2137
- this.figure.open(target, { nonResizing: true, nonSizeInfo: true, nonBorder: true, figureTarget: true, __fileManagerInfo: false });
2138
- }
2139
-
2140
- /**
2141
- * @private
2142
- * @description Starts resizing a table cell.
2143
- * @param {HTMLElement} col The column element.
2144
- * @param {number} startX The starting X position.
2145
- * @param {number} startWidth The initial width of the column.
2146
- * @param {boolean} isLeftEdge Whether the resizing is on the left edge.
2147
- */
2148
- _startCellResizing(col, startX, startWidth, isLeftEdge) {
2149
- this._setResizeLinePosition(this._figure, this._tdElement, this._resizeLinePrev, isLeftEdge);
2150
- this._resizeLinePrev.style.display = 'block';
2151
- const prevValue = col.style.width;
2152
- const nextCol = /** @type {HTMLElement} */ (col.nextElementSibling);
2153
- const nextColPrevValue = nextCol.style.width;
2154
- const realWidth = dom.utils.hasClass(this._element, 'se-table-layout-fixed') ? nextColPrevValue : converter.getWidthInPercentage(col);
2155
-
2156
- if (_DragHandle.get('__dragHandler')) _DragHandle.get('__dragHandler').style.display = 'none';
2157
- this._addResizeGlobalEvents(
2158
- this._cellResize.bind(
2159
- this,
2160
- col,
2161
- nextCol,
2162
- this._figure,
2163
- this._tdElement,
2164
- this._resizeLine,
2165
- isLeftEdge,
2166
- startX,
2167
- startWidth,
2168
- numbers.get(prevValue, CELL_DECIMAL_END),
2169
- numbers.get(realWidth, CELL_DECIMAL_END),
2170
- this._element.offsetWidth
2171
- ),
2172
- () => {
2173
- this.__removeGlobalEvents();
2174
- this.history.push(true);
2175
- this.component.select(this._element, Table.key, { isInput: true });
2176
- },
2177
- (e) => {
2178
- this._stopResize(col, prevValue, 'width', e);
2179
- this._stopResize(nextCol, nextColPrevValue, 'width', e);
2180
- }
2181
- );
2182
- }
2183
-
2184
- /**
2185
- * @private
2186
- * @description Resizes a table cell.
2187
- * @param {HTMLElement} col The column element.
2188
- * @param {HTMLElement} nextCol The next column element.
2189
- * @param {HTMLElement} figure The table figure element.
2190
- * @param {HTMLElement} tdEl The table cell element.
2191
- * @param {HTMLElement} resizeLine The resize line element.
2192
- * @param {boolean} isLeftEdge Whether the resizing is on the left edge.
2193
- * @param {number} startX The starting X position.
2194
- * @param {number} startWidth The initial width of the column.
2195
- * @param {number} prevWidthPercent The previous width percentage.
2196
- * @param {number} nextColWidthPercent The next column's width percentage.
2197
- * @param {number} tableWidth The total width of the table.
2198
- * @param {MouseEvent} e The mouse event.
2199
- */
2200
- _cellResize(col, nextCol, figure, tdEl, resizeLine, isLeftEdge, startX, startWidth, prevWidthPercent, nextColWidthPercent, tableWidth, e) {
2201
- const deltaX = e.clientX - startX;
2202
- const newWidthPx = startWidth + deltaX;
2203
- const newWidthPercent = (newWidthPx / tableWidth) * 100;
2204
-
2205
- if (newWidthPercent > 0) {
2206
- col.style.width = `${newWidthPercent}%`;
2207
- const delta = prevWidthPercent - newWidthPercent;
2208
- nextCol.style.width = `${nextColWidthPercent + delta}%`;
2209
- this._setResizeLinePosition(figure, tdEl, resizeLine, isLeftEdge);
2210
- }
2211
- }
2212
-
2213
- /**
2214
- * @private
2215
- * @description Starts resizing a table row.
2216
- * @param {HTMLElement} row The table row element.
2217
- * @param {number} startY The starting Y position.
2218
- * @param {number} startHeight The initial height of the row.
2219
- */
2220
- _startRowResizing(row, startY, startHeight) {
2221
- this._setResizeRowPosition(this._figure, row, this._resizeLinePrev);
2222
- this._resizeLinePrev.style.display = 'block';
2223
- const prevValue = row.style.height;
2224
-
2225
- this._addResizeGlobalEvents(
2226
- this._rowResize.bind(this, row, this._figure, this._resizeLine, startY, startHeight),
2227
- () => {
2228
- this.__removeGlobalEvents();
2229
- this.history.push(true);
2230
- },
2231
- this._stopResize.bind(this, row, prevValue, 'height')
2232
- );
2233
- }
2234
-
2235
- /**
2236
- * @private
2237
- * @description Resizes a table row.
2238
- * @param {HTMLElement} row The table row element.
2239
- * @param {HTMLElement} figure The table figure element.
2240
- * @param {HTMLElement} resizeLine The resize line element.
2241
- * @param {number} startY The starting Y position.
2242
- * @param {number} startHeight The initial height of the row.
2243
- * @param {MouseEvent} e The mouse event.
2244
- */
2245
- _rowResize(row, figure, resizeLine, startY, startHeight, e) {
2246
- const deltaY = e.clientY - startY;
2247
- const newHeightPx = startHeight + deltaY;
2248
- row.style.height = `${newHeightPx}px`;
2249
- this._setResizeRowPosition(figure, row, resizeLine);
2250
- }
2251
-
2252
- /**
2253
- * @private
2254
- * @description Starts resizing the table figure.
2255
- * @param {number} startX The starting X position.
2256
- * @param {boolean} isLeftEdge Whether the resizing is on the left edge.
2257
- */
2258
- _startFigureResizing(startX, isLeftEdge) {
2259
- const figure = this._figure;
2260
- this._setResizeLinePosition(figure, figure, this._resizeLinePrev, isLeftEdge);
2261
- this._resizeLinePrev.style.display = 'block';
2262
- const realWidth = converter.getWidthInPercentage(figure);
2263
-
2264
- if (_DragHandle.get('__dragHandler')) _DragHandle.get('__dragHandler').style.display = 'none';
2265
- this._addResizeGlobalEvents(
2266
- this._figureResize.bind(this, figure, this._resizeLine, isLeftEdge, startX, figure.offsetWidth, numbers.get(realWidth, CELL_DECIMAL_END)),
2267
- () => {
2268
- this.__removeGlobalEvents();
2269
- // figure reopen
2270
- this.component.select(this._element, Table.key, { isInput: true });
2271
- },
2272
- this._stopResize.bind(this, figure, figure.style.width, 'width')
2273
- );
2274
- }
2275
-
2276
- /**
2277
- * @private
2278
- * @description Resizes the table figure.
2279
- * @param {HTMLElement} figure The table figure element.
2280
- * @param {HTMLElement} resizeLine The resize line element.
2281
- * @param {boolean} isLeftEdge Whether the resizing is on the left edge.
2282
- * @param {number} startX The starting X position.
2283
- * @param {number} startWidth The initial width of the figure.
2284
- * @param {number} constNum A constant number used for width calculation.
2285
- * @param {MouseEvent} e The mouse event.
2286
- */
2287
- _figureResize(figure, resizeLine, isLeftEdge, startX, startWidth, constNum, e) {
2288
- const deltaX = isLeftEdge ? startX - e.clientX : e.clientX - startX;
2289
- const newWidthPx = startWidth + deltaX;
2290
- const newWidthPercent = (newWidthPx / startWidth) * constNum;
2291
-
2292
- if (newWidthPercent > 0) {
2293
- figure.style.width = `${newWidthPercent}%`;
2294
- this._setResizeLinePosition(figure, figure, resizeLine, isLeftEdge);
2295
- }
2296
- }
2297
-
2298
- /**
2299
- * @private
2300
- * @description Sets the resize line position.
2301
- * @param {HTMLElement} figure The table figure element.
2302
- * @param {HTMLElement} target The target element.
2303
- * @param {HTMLElement} resizeLine The resize line element.
2304
- * @param {boolean} isLeftEdge Whether the resizing is on the left edge.
2305
- */
2306
- _setResizeLinePosition(figure, target, resizeLine, isLeftEdge) {
2307
- const tdOffset = this.offset.getLocal(target);
2308
- const tableOffset = this.offset.getLocal(figure);
2309
- resizeLine.style.left = `${tdOffset.left + (isLeftEdge ? 0 : target.offsetWidth)}px`;
2310
- resizeLine.style.top = `${tableOffset.top}px`;
2311
- resizeLine.style.height = `${figure.offsetHeight}px`;
2312
- }
2313
-
2314
- /**
2315
- * @private
2316
- * @description Sets the resize row position.
2317
- * @param {HTMLElement} figure The table figure element.
2318
- * @param {HTMLElement} target The target row element.
2319
- * @param {HTMLElement} resizeLine The resize line element.
2320
- */
2321
- _setResizeRowPosition(figure, target, resizeLine) {
2322
- const rowOffset = this.offset.getLocal(target);
2323
- const tableOffset = this.offset.getLocal(figure);
2324
- resizeLine.style.top = `${rowOffset.top + target.offsetHeight}px`;
2325
- resizeLine.style.left = `${tableOffset.left}px`;
2326
- resizeLine.style.width = `${figure.offsetWidth}px`;
2327
- }
2328
-
2329
- /**
2330
- * @private
2331
- * @description Stops resizing the table.
2332
- * @param {HTMLElement} target The target element.
2333
- * @param {string} prevValue The previous style value.
2334
- * @param {string} styleProp The CSS property being changed.
2335
- * @param {KeyboardEvent} e The keyboard event.
2336
- */
2337
- _stopResize(target, prevValue, styleProp, e) {
2338
- if (!keyCodeMap.isEsc(e.code)) return;
2339
- this.__removeGlobalEvents();
2340
- target.style[styleProp] = prevValue;
2341
- // figure reopen
2342
- if (styleProp === 'width') {
2343
- this.component.select(this._element, Table.key, { isInput: true });
2344
- }
2345
- }
2346
-
2347
- /**
2348
- * @private
2349
- * @description Deletes styles from selected table cells.
2350
- */
2351
- _deleteStyleSelectedCells() {
2352
- dom.utils.removeClass([this._fixedCell, this._selectedCell], 'se-selected-cell-focus');
2353
- const table = this._fixedCell?.closest('table');
2354
- if (table) {
2355
- const selectedCells = table.querySelectorAll('.se-selected-table-cell');
2356
- for (let i = 0, len = selectedCells.length; i < len; i++) {
2357
- dom.utils.removeClass(selectedCells[i], 'se-selected-table-cell');
2358
- }
2359
- }
2360
- }
2361
-
2362
- /**
2363
- * @private
2364
- * @description Restores styles for selected table cells.
2365
- */
2366
- _recallStyleSelectedCells() {
2367
- if (this._selectedCells) {
2368
- const selectedCells = this._selectedCells;
2369
- for (let i = 0, len = selectedCells.length; i < len; i++) {
2370
- dom.utils.addClass(selectedCells[i], 'se-selected-table-cell');
2371
- }
2372
- }
2373
- }
2374
-
2375
- /**
2376
- * @private
2377
- * @description Adds global event listeners for resizing.
2378
- * @param {(...args: *) => void} resizeFn The function handling the resize event.
2379
- * @param {(...args: *) => void} stopFn The function handling the stop event.
2380
- * @param {(...args: *) => void} keyDownFn The function handling the keydown event.
2381
- */
2382
- _addResizeGlobalEvents(resizeFn, stopFn, keyDownFn) {
2383
- this.__globalEvents.resize = this.eventManager.addGlobalEvent('mousemove', resizeFn, false);
2384
- this.__globalEvents.resizeStop = this.eventManager.addGlobalEvent('mouseup', stopFn, false);
2385
- this.__globalEvents.resizeKeyDown = this.eventManager.addGlobalEvent('keydown', keyDownFn, false);
2386
- this._resizing = true;
2387
- }
2388
-
2389
- /**
2390
- * @private
2391
- * @description Enables or disables editor mode.
2392
- * @param {boolean} enabled Whether to enable or disable the editor.
2393
- */
2394
- _toggleEditor(enabled) {
2395
- const wysiwyg = this.editor.frameContext.get('wysiwyg');
2396
- wysiwyg.setAttribute('contenteditable', enabled.toString());
2397
- if (enabled) dom.utils.removeClass(wysiwyg, 'se-disabled');
2398
- else dom.utils.addClass(wysiwyg, 'se-disabled');
2399
- }
2400
-
2401
- /**
2402
- * @private
2403
- * @description Updates control properties.
2404
- * @param {string} type The type of control property.
2405
- */
2406
- _setCtrlProps(type) {
2407
- this._typeCache = type;
2408
- const isTable = type === 'table';
2409
- const targets = isTable ? [this._element] : this._selectedCells;
2410
- if (!targets || targets.length === 0) return;
2411
-
2412
- const { border_format, border_color, border_style, border_width, back_color, font_color, cell_alignment, cell_alignment_vertical, cell_alignment_table_text, font_bold, font_underline, font_italic, font_strike } = this.propTargets;
2413
- const { border, backgroundColor, color, textAlign, verticalAlign, fontWeight, textDecoration, fontStyle } = _w.getComputedStyle(targets[0]);
2414
- const cellBorder = this._getBorderStyle(border);
2415
-
2416
- /** @type {HTMLElement} */ (cell_alignment.querySelector('[data-value="justify"]')).style.display = isTable ? 'none' : '';
2417
- cell_alignment_table_text.style.display = isTable ? '' : 'none';
2418
- if (isTable) cell_alignment_vertical.style.display = 'none';
2419
- else cell_alignment_vertical.style.display = '';
2420
-
2421
- let b_color = converter.rgb2hex(cellBorder.c),
2422
- b_style = cellBorder.s,
2423
- b_width = cellBorder.w,
2424
- backColor = converter.rgb2hex(backgroundColor),
2425
- fontColor = converter.rgb2hex(color),
2426
- bold = /.+/.test(fontWeight),
2427
- underline = /underline/i.test(textDecoration),
2428
- strike = /line-through/i.test(textDecoration),
2429
- italic = /italic/i.test(fontStyle),
2430
- align = isTable ? this._figure?.style.float : textAlign,
2431
- align_v = verticalAlign;
2432
- this._propsCache = [];
2433
-
2434
- const tempColorStyles = _w.getComputedStyle(this.eventManager.__focusTemp);
2435
- for (let i = 0, t, isBreak; (t = targets[i]); i++) {
2436
- // eslint-disable-next-line no-shadow
2437
- const { cssText, border, backgroundColor, color, textAlign, verticalAlign, fontWeight, textDecoration, fontStyle } = t.style;
2438
- this._propsCache.push([t, cssText]);
2439
- if (isBreak) continue;
2440
-
2441
- const { c, s, w } = this._getBorderStyle(border);
2442
-
2443
- // colors
2444
- let hexBackColor = backgroundColor;
2445
- let hexColor = color;
2446
- if (hexBackColor) {
2447
- this.eventManager.__focusTemp.style.backgroundColor = hexBackColor;
2448
- hexBackColor = tempColorStyles.backgroundColor;
2449
- }
2450
- if (hexColor) {
2451
- this.eventManager.__focusTemp.style.color = hexColor;
2452
- hexColor = tempColorStyles.color;
2453
- }
2454
-
2455
- if (b_color && cellBorder.c !== c) b_color = '';
2456
- if (b_style && cellBorder.s !== s) b_style = '';
2457
- if (b_width && cellBorder.w !== w) b_width = '';
2458
- if (backColor !== converter.rgb2hex(hexBackColor)) backColor = '';
2459
- if (fontColor !== converter.rgb2hex(hexColor)) fontColor = '';
2460
- if (align !== (isTable ? this._figure?.style.float : textAlign)) align = '';
2461
- if (align_v && align_v !== verticalAlign) align_v = '';
2462
- if (bold && bold !== /.+/.test(fontWeight)) bold = false;
2463
- if (underline && underline !== /underline/i.test(textDecoration)) underline = false;
2464
- if (strike && strike !== /line-through/i.test(textDecoration)) strike = false;
2465
- if (italic && italic !== /italic/i.test(fontStyle)) italic = false;
2466
- if (!b_color || !b_style || !b_width || !backColor || !fontColor) {
2467
- isBreak = true;
2468
- }
2469
- }
2470
-
2471
- // border - format
2472
- border_format.firstElementChild.innerHTML = this.icons[BORDER_FORMATS[targets.length === 1 ? 'outside' : 'all']];
2473
- border_format.setAttribute('se-border-format', 'all');
2474
- dom.utils.removeClass(border_format, 'active');
2475
-
2476
- // border - styles
2477
- b_style = b_style || BORDER_LIST[0];
2478
- border_style.textContent = b_style;
2479
- border_color.style.borderColor = border_color.value = b_color;
2480
- border_width.value = b_width;
2481
- this._disableBorderProps(b_style === BORDER_LIST[0]);
2482
-
2483
- // back, font color
2484
- back_color.value = back_color.style.borderColor = backColor;
2485
- font_color.value = font_color.style.borderColor = fontColor;
2486
-
2487
- // font style
2488
- if (bold) dom.utils.addClass(font_bold, 'on');
2489
- if (underline) dom.utils.addClass(font_underline, 'on');
2490
- if (strike) dom.utils.addClass(font_strike, 'on');
2491
- if (italic) dom.utils.addClass(font_italic, 'on');
2492
-
2493
- // align
2494
- this._setAlignProps(cell_alignment, (this._propsAlignCache = align), true);
2495
- this._setAlignProps(cell_alignment_vertical, (this._propsVerticalAlignCache = align_v), true);
2496
- }
2497
-
2498
- /**
2499
- * @private
2500
- * @description Sets text alignment properties.
2501
- * @param {Element} el The element to apply alignment to.
2502
- * @param {string} align The alignment value.
2503
- * @param {boolean} reset Whether to reset the alignment.
2504
- */
2505
- _setAlignProps(el, align, reset) {
2506
- dom.utils.removeClass(el.querySelectorAll('button'), 'on');
2507
-
2508
- if (!reset && el.getAttribute('se-cell-align') === align) {
2509
- el.setAttribute('se-cell-align', '');
2510
- return;
2511
- }
2512
-
2513
- dom.utils.addClass(el.querySelector(`[data-value="${align}"]`), 'on');
2514
- el.setAttribute('se-cell-align', align);
2515
- }
2516
-
2517
- /**
2518
- * @private
2519
- * @description Disables or enables border properties.
2520
- * @param {boolean} disabled Whether to disable or enable border properties.
2521
- */
2522
- _disableBorderProps(disabled) {
2523
- const { border_color, border_width, palette_border_button } = this.propTargets;
2524
- if (disabled) {
2525
- border_color.disabled = true;
2526
- border_width.disabled = true;
2527
- palette_border_button.disabled = true;
2528
- border_width.disabled = true;
2529
- } else {
2530
- border_color.disabled = false;
2531
- border_width.disabled = false;
2532
- palette_border_button.disabled = false;
2533
- border_width.disabled = false;
2534
- }
2535
- }
2536
-
2537
- /**
2538
- * @private
2539
- * @description Gets the border style.
2540
- * @param {string} borderStyle The border style string.
2541
- * @returns {{w: string, s: string, c: string}} The parsed border style object.
2542
- * - w: The border width.
2543
- * - s: The border style.
2544
- * - c: The border color.
2545
- */
2546
- _getBorderStyle(borderStyle) {
2547
- const parts = borderStyle.split(/\s(?![^()]*\))/);
2548
- let w = '',
2549
- s = '',
2550
- c = '';
2551
-
2552
- if (parts.length === 3) {
2553
- w = parts[0];
2554
- s = parts[1];
2555
- c = parts[2];
2556
- } else if (parts.length === 2) {
2557
- if (/\d/.test(parts[0])) {
2558
- w = parts[0];
2559
- s = parts[1];
2560
- } else {
2561
- s = parts[0];
2562
- c = parts[1];
2563
- }
2564
- } else if (parts.length === 1) {
2565
- if (/\d/.test(parts[0])) {
2566
- w = parts[0];
2567
- } else {
2568
- s = parts[0];
2569
- }
2570
- }
2571
-
2572
- return { w, s, c: converter.rgb2hex(c) };
2573
- }
2574
-
2575
- /**
2576
- * @private
2577
- * @description Applies properties to table cells.
2578
- * @param {HTMLButtonElement} target The target element.
2579
- */
2580
- _submitProps(target) {
2581
- try {
2582
- target.disabled = true;
2583
-
2584
- const isTable = this.controller_table.form.contains(this.controller_props.currentTarget);
2585
- const targets = isTable ? [this._element] : this._selectedCells;
2586
- const tr = /** @type {HTMLTableCellElement} */ (targets[0]);
2587
- const trStyles = _w.getComputedStyle(tr);
2588
- const { border_format, border_color, border_style, border_width, back_color, font_color, cell_alignment, cell_alignment_vertical } = this.propTargets;
2589
-
2590
- const borderFormat = border_format.getAttribute('se-border-format') || '';
2591
- const hasFormat = borderFormat !== 'all';
2592
- const borderStyle = (border_style.textContent === 'none' ? '' : border_style.textContent) || '';
2593
- const isNoneFormat = borderFormat === 'none' || !borderStyle;
2594
-
2595
- const cellAlignment = cell_alignment.getAttribute('se-cell-align') || '';
2596
- const cellAlignmentVertical = cell_alignment_vertical.getAttribute('se-cell-align') || '';
2597
- const borderColor = isNoneFormat ? '' : border_color.value.trim() || trStyles.borderColor;
2598
- let borderWidth = isNoneFormat ? '' : border_width.value.trim() || trStyles.borderWidth;
2599
- borderWidth = borderWidth + (numbers.is(borderWidth) ? DEFAULT_BORDER_UNIT : '');
2600
- const backColor = back_color.value.trim();
2601
- const fontColor = font_color.value.trim();
2602
- const hasBorder = hasFormat && !isNoneFormat && borderWidth;
2603
- const borderCss = `${borderWidth} ${borderStyle} ${borderColor}`;
2604
- const cells = {
2605
- left: [],
2606
- top: [],
2607
- right: [],
2608
- bottom: [],
2609
- middle: [],
2610
- all: null
2611
- };
2612
-
2613
- if (!isTable) {
2614
- const trRow = /** @type {HTMLTableRowElement} */ (tr.parentElement);
2615
- // --- target cells roof
2616
- let { rs, re, cs, ce } = this._ref || {
2617
- rs: trRow.rowIndex || 0,
2618
- re: trRow.rowIndex || 0,
2619
- cs: tr.cellIndex || 0,
2620
- ce: tr.cellIndex || 0
2621
- };
2622
- const mergeInfo = new Array(re - rs + 1).fill(0).map(() => new Array(ce - cs + 1).fill(0));
2623
- const cellStartIndex = cs;
2624
- re -= rs;
2625
- rs -= rs;
2626
- ce -= cs;
2627
- cs -= cs;
2628
- let prevRow = /** @type {HTMLElement} */ (trRow);
2629
- for (let i = 0, cellCnt = 0, len = targets.length, e, es, rowIndex = 0, cellIndex, colspan, rowspan; i < len; i++, cellCnt++) {
2630
- e = /** @type {HTMLTableCellElement} */ (targets[i]);
2631
- colspan = e.colSpan;
2632
- rowspan = e.rowSpan;
2633
- cellIndex = e.cellIndex - cellStartIndex;
2634
-
2635
- if (prevRow !== e.parentElement) {
2636
- rowIndex++;
2637
- cellCnt = 0;
2638
- prevRow = e.parentElement;
2639
- }
2640
-
2641
- let c = 0;
2642
- while (c <= cellIndex) {
2643
- cellIndex += mergeInfo[rowIndex][c] || 0;
2644
- c++;
2645
- }
2646
-
2647
- /* eslint-disable @typescript-eslint/no-unused-vars */
2648
- try {
2649
- if (rowspan > 1) {
2650
- const rowspanNum = rowspan - 1;
2651
- for (let r = rowIndex; r <= rowIndex + rowspanNum; r++) {
2652
- mergeInfo[r][cellIndex] += colspan - (rowIndex === r ? 1 : 0);
2653
- }
2654
- } else if (colspan > 1) {
2655
- mergeInfo[rowIndex][cellIndex] += colspan - 1;
2656
- }
2657
- } catch (err) {
2658
- // ignore error
2659
- }
2660
- /* eslint-disable @typescript-eslint/no-unused-vars */
2661
-
2662
- const isBottom = rowIndex + rowspan - 1 === re;
2663
- if (rowIndex === rs) cells.top.push(e);
2664
- if (rowIndex === re || isBottom) cells.bottom.push(e);
2665
- if (cellIndex === cs) cells.left.push(e);
2666
- if (cellIndex === ce || cellIndex + colspan - 1 === ce) cells.right.push(e);
2667
- if (!isBottom && rowIndex !== rs && rowIndex !== re && cellIndex !== cs && cellIndex !== ce) cells.middle.push(e);
2668
-
2669
- // --- set styles
2670
- es = e.style;
2671
- // alignment
2672
- es.textAlign = cellAlignment;
2673
- es.verticalAlign = cellAlignmentVertical;
2674
- // back
2675
- es.backgroundColor = backColor;
2676
- // font
2677
- es.color = fontColor;
2678
- // font style
2679
- this._setFontStyle(es);
2680
- // border
2681
- if (hasBorder) continue;
2682
- // border - all || none
2683
- if (isNoneFormat) {
2684
- es.border = es.borderLeft = es.borderTop = es.borderRight = es.borderBottom = '';
2685
- } else {
2686
- es.border = borderCss;
2687
- }
2688
- }
2689
-
2690
- if (cells.middle.length === 0) {
2691
- cells.middle = targets;
2692
- }
2693
- } else {
2694
- // -- table styles
2695
- const es = tr.style;
2696
- // alignment
2697
- if (this._figure) {
2698
- this._figure.style.float = cellAlignment;
2699
- this._figure.style.verticalAlign = cellAlignmentVertical;
2700
- }
2701
- // back
2702
- es.backgroundColor = backColor;
2703
- // font
2704
- es.color = fontColor;
2705
- // font style
2706
- this._setFontStyle(es);
2707
- // border
2708
- if (!hasBorder) {
2709
- // border - all || none
2710
- if (isNoneFormat) {
2711
- es.border = es.borderLeft = es.borderTop = es.borderRight = es.borderBottom = '';
2712
- } else {
2713
- es.border = borderCss;
2714
- }
2715
- }
2716
-
2717
- cells.left = cells.top = cells.right = cells.bottom = targets;
2718
- }
2719
-
2720
- cells.all = targets;
2721
-
2722
- // border format
2723
- if (hasBorder) {
2724
- this._setBorderStyles(cells, borderFormat, borderCss);
2725
- }
2726
-
2727
- this._historyPush();
2728
-
2729
- // set cells style
2730
- this.controller_props.close();
2731
- if (this._tdElement) {
2732
- this._recallStyleSelectedCells();
2733
- this.setCellInfo(this._tdElement, true);
2734
- dom.utils.addClass(this._tdElement, 'se-selected-cell-focus');
2735
- }
2736
- } catch (err) {
2737
- console.warn('[SUNEDITOR.plugins.table.setProps.error]', err);
2738
- } finally {
2739
- target.disabled = false;
2740
- }
2741
- }
2742
-
2743
- /**
2744
- * @private
2745
- * @description Sets font styles.
2746
- * @param {CSSStyleDeclaration} styles The style object to modify.
2747
- */
2748
- _setFontStyle(styles) {
2749
- const { font_bold, font_italic, font_strike, font_underline } = this.propTargets;
2750
- styles.fontWeight = dom.utils.hasClass(font_bold, 'on') ? 'bold' : '';
2751
- styles.fontStyle = dom.utils.hasClass(font_italic, 'on') ? 'italic' : '';
2752
- styles.textDecoration = ((dom.utils.hasClass(font_strike, 'on') ? 'line-through ' : '') + (dom.utils.hasClass(font_underline, 'on') ? 'underline' : '')).trim();
2753
- }
2754
-
2755
- /**
2756
- * @private
2757
- * @description Sets border format and styles.
2758
- * @param {{left: Node[], top: Node[], right: Node[], bottom: Node[], all: Node[]}} cells The table cells categorized by border positions.
2759
- * @param {string} borderKey Border style ("all"|"inside"|"horizon"|"vertical"|"outside"|"left"|"top"|"right"|"bottom")
2760
- * @param {string} s The border style value.
2761
- */
2762
- _setBorderStyles(cells, borderKey, s) {
2763
- const { left, top, right, bottom, all } = cells;
2764
- switch (borderKey) {
2765
- case 'inside':
2766
- if (all.length === 1) return;
2767
- dom.utils.setStyle(
2768
- all.filter((c) => !bottom.includes(c)),
2769
- BORDER_NS.b,
2770
- s
2771
- );
2772
- dom.utils.setStyle(
2773
- all.filter((c) => !right.includes(c)),
2774
- BORDER_NS.r,
2775
- s
2776
- );
2777
- break;
2778
- case 'horizon':
2779
- if (all.length === 1) return;
2780
- dom.utils.setStyle(
2781
- all.filter((c) => !bottom.includes(c)),
2782
- BORDER_NS.b,
2783
- s
2784
- );
2785
- break;
2786
- case 'vertical':
2787
- if (all.length === 1) return;
2788
- dom.utils.setStyle(
2789
- all.filter((c) => !right.includes(c)),
2790
- BORDER_NS.r,
2791
- s
2792
- );
2793
- break;
2794
- case 'outside':
2795
- dom.utils.setStyle(left, BORDER_NS.l, s);
2796
- dom.utils.setStyle(top, BORDER_NS.t, s);
2797
- dom.utils.setStyle(right, BORDER_NS.r, s);
2798
- dom.utils.setStyle(bottom, BORDER_NS.b, s);
2799
- break;
2800
- case 'left':
2801
- dom.utils.setStyle(left, BORDER_NS.l, s);
2802
- break;
2803
- case 'top':
2804
- dom.utils.setStyle(top, BORDER_NS.t, s);
2805
- break;
2806
- case 'right':
2807
- dom.utils.setStyle(right, BORDER_NS.r, s);
2808
- break;
2809
- case 'bottom':
2810
- dom.utils.setStyle(bottom, BORDER_NS.b, s);
2811
- break;
2812
- }
2813
- }
2814
-
2815
- /**
2816
- * @private
2817
- * @description Selects multiple table cells and applies selection styles.
2818
- * @param {Node} startCell The first cell in the selection.
2819
- * @param {Node} endCell The last cell in the selection.
2820
- */
2821
- _setMultiCells(startCell, endCell) {
2822
- const rows = this._selectedTable.rows;
2823
- this._deleteStyleSelectedCells();
2824
-
2825
- dom.utils.addClass(startCell, 'se-selected-table-cell');
2826
-
2827
- if (startCell === endCell) {
2828
- if (!this._shift) return;
2829
- }
2830
-
2831
- let findSelectedCell = true;
2832
- let spanIndex = [];
2833
- let rowSpanArr = [];
2834
- const ref = (this._ref = { _i: 0, cs: null, ce: null, rs: null, re: null });
2835
-
2836
- for (let i = 0, len = rows.length, cells, colSpan; i < len; i++) {
2837
- cells = rows[i].cells;
2838
- colSpan = 0;
2839
-
2840
- for (let c = 0, cLen = cells.length, cell, logcalIndex, cs, rs; c < cLen; c++) {
2841
- cell = cells[c];
2842
- cs = cell.colSpan - 1;
2843
- rs = cell.rowSpan - 1;
2844
- logcalIndex = c + colSpan;
2845
-
2846
- if (spanIndex.length > 0) {
2847
- for (let r = 0, arr; r < spanIndex.length; r++) {
2848
- arr = spanIndex[r];
2849
- if (arr.row > i) continue;
2850
- if (logcalIndex >= arr.index) {
2851
- colSpan += arr.cs;
2852
- logcalIndex += arr.cs;
2853
- arr.rs -= 1;
2854
- arr.row = i + 1;
2855
- if (arr.rs < 1) {
2856
- spanIndex.splice(r, 1);
2857
- r--;
2858
- }
2859
- } else if (c === cLen - 1) {
2860
- arr.rs -= 1;
2861
- arr.row = i + 1;
2862
- if (arr.rs < 1) {
2863
- spanIndex.splice(r, 1);
2864
- r--;
2865
- }
2866
- }
2867
- }
2868
- }
2869
-
2870
- if (findSelectedCell) {
2871
- if (cell === startCell || cell === endCell) {
2872
- ref.cs = ref.cs !== null && ref.cs < logcalIndex ? ref.cs : logcalIndex;
2873
- ref.ce = ref.ce !== null && ref.ce > logcalIndex + cs ? ref.ce : logcalIndex + cs;
2874
- ref.rs = ref.rs !== null && ref.rs < i ? ref.rs : i;
2875
- ref.re = ref.re !== null && ref.re > i + rs ? ref.re : i + rs;
2876
- ref._i += 1;
2877
- }
2878
-
2879
- if (ref._i === 2) {
2880
- findSelectedCell = false;
2881
- spanIndex = [];
2882
- rowSpanArr = [];
2883
- i = -1;
2884
- break;
2885
- }
2886
- } else if (numbers.getOverlapRangeAtIndex(ref.cs, ref.ce, logcalIndex, logcalIndex + cs) && numbers.getOverlapRangeAtIndex(ref.rs, ref.re, i, i + rs)) {
2887
- const newCs = ref.cs < logcalIndex ? ref.cs : logcalIndex;
2888
- const newCe = ref.ce > logcalIndex + cs ? ref.ce : logcalIndex + cs;
2889
- const newRs = ref.rs < i ? ref.rs : i;
2890
- const newRe = ref.re > i + rs ? ref.re : i + rs;
2891
-
2892
- if (ref.cs !== newCs || ref.ce !== newCe || ref.rs !== newRs || ref.re !== newRe) {
2893
- ref.cs = newCs;
2894
- ref.ce = newCe;
2895
- ref.rs = newRs;
2896
- ref.re = newRe;
2897
- i = -1;
2898
-
2899
- spanIndex = [];
2900
- rowSpanArr = [];
2901
- break;
2902
- }
2903
-
2904
- dom.utils.addClass(cell, 'se-selected-table-cell');
2905
- }
2906
-
2907
- if (rs > 0) {
2908
- rowSpanArr.push({
2909
- index: logcalIndex,
2910
- cs: cs + 1,
2911
- rs: rs,
2912
- row: -1
2913
- });
2914
- }
2915
-
2916
- colSpan += cell.colSpan - 1;
2917
- }
2918
-
2919
- spanIndex = spanIndex.concat(rowSpanArr).sort((a, b) => {
2920
- return a.index - b.index;
2921
- });
2922
- rowSpanArr = [];
2923
- }
2924
- }
2925
-
2926
- /**
2927
- * @private
2928
- * @description Resets the table picker display.
2929
- */
2930
- _resetTablePicker() {
2931
- if (!this.tableHighlight) return;
2932
-
2933
- const highlight = this.tableHighlight.style;
2934
- const unHighlight = this.tableUnHighlight.style;
2935
-
2936
- highlight.width = '1em';
2937
- highlight.height = '1em';
2938
- unHighlight.width = '10em';
2939
- unHighlight.height = '10em';
2940
-
2941
- dom.utils.changeTxt(this.tableDisplay, '1 x 1');
2942
- this.menu.dropdownOff();
2943
- }
2944
-
2945
- /**
2946
- * @private
2947
- * @description Resets the alignment properties for table cells.
2948
- */
2949
- _resetPropsAlign() {
2950
- const { cell_alignment } = this.propTargets;
2951
- const left = cell_alignment.querySelector('[data-value="left"]');
2952
- const right = cell_alignment.querySelector('[data-value="right"]');
2953
- const l_parent = left.parentElement;
2954
- const r_parent = right.parentElement;
2955
- l_parent.appendChild(right);
2956
- r_parent.appendChild(left);
2957
- }
2958
-
2959
- /**
2960
- * @private
2961
- * @description Handles color selection from the color palette.
2962
- * @param {Node} button The button triggering the color palette.
2963
- * @param {string} type The type of color selection.
2964
- * @param {HTMLInputElement} color Color text input element.
2965
- */
2966
- _onColorPalette(button, type, color) {
2967
- if (this.controller_colorPicker.isOpen && type === this.sliderType) {
2968
- this.controller_colorPicker.close();
2969
- } else {
2970
- this.sliderType = type;
2971
- dom.utils.addClass(button, 'on');
2972
- this.colorPicker.init(color?.value || '', button);
2973
- this.controller_colorPicker.open(button, null, { isWWTarget: false, initMethod: null, addOffset: null });
2974
- }
2975
- }
2976
-
2977
- /**
2978
- * @private
2979
- * @description Closes table-related controllers.
2980
- */
2981
- _closeController() {
2982
- this.controller_table.close();
2983
- this.controller_cell.close();
2984
- }
2985
-
2986
- /**
2987
- * @private
2988
- * @description Closes table-related controllers and table figure
2989
- */
2990
- _closeTableSelectInfo() {
2991
- this.component.deselect();
2992
- this._closeController();
2993
- }
2994
-
2995
- /**
2996
- * @private
2997
- * @description Hides the resize line if it is visible.
2998
- */
2999
- __hideResizeLine() {
3000
- if (this._resizeLine) {
3001
- this._resizeLine.style.display = 'none';
3002
- this._resizeLine = null;
3003
- }
3004
- }
3005
-
3006
- /**
3007
- * @private
3008
- * @description Removes global event listeners and resets resize-related properties.
3009
- */
3010
- __removeGlobalEvents() {
3011
- this._toggleEditor(true);
3012
- this._resizing = false;
3013
- this.ui.disableBackWrapper();
3014
- this.__hideResizeLine();
3015
- if (this._resizeLinePrev) {
3016
- this._resizeLinePrev.style.display = 'none';
3017
- this._resizeLinePrev = null;
3018
- }
3019
- const globalEvents = this.__globalEvents;
3020
- for (const k in globalEvents) {
3021
- if (globalEvents[k]) globalEvents[k] = this.eventManager.removeGlobalEvent(globalEvents[k]);
3022
- }
3023
- }
3024
-
3025
- /**
3026
- * @description Clone a table element and map selected cells to the cloned table
3027
- * @param {HTMLTableElement} table <table> element
3028
- * @param {HTMLTableCellElement[]} selectedCells Selected cells array
3029
- * @returns {{ cloneTable: HTMLTableElement, clonedSelectedCells: HTMLTableCellElement[] }}
3030
- */
3031
- #cloneTable(table, selectedCells) {
3032
- /** @type {HTMLTableElement} */
3033
- const cloneTable = dom.utils.clone(table, true);
3034
-
3035
- const originalCells = Array.from(table.querySelectorAll('td, th'));
3036
- const clonedCells = Array.from(cloneTable.querySelectorAll('td, th'));
3037
-
3038
- const clonedSelectedCells = /** @type {HTMLTableCellElement[]} */ (
3039
- selectedCells
3040
- .map((cell) => {
3041
- const index = originalCells.indexOf(cell);
3042
- return index > -1 ? clonedCells[index] : null;
3043
- })
3044
- .filter((cell) => cell !== null)
3045
- );
3046
-
3047
- return {
3048
- cloneTable,
3049
- clonedSelectedCells
3050
- };
3051
- }
3052
-
3053
- /**
3054
- * @description Selects cells in a table, handling single and multi-cell selection, and managing shift key behavior for extended selection.
3055
- * @param {HTMLTableCellElement} tdElement The target table cell (`<td>`) element that is being selected.
3056
- * @param {boolean} shift A flag indicating whether the shift key is held down for multi-cell selection.
3057
- * If `true`, the selection will extend to include adjacent cells, otherwise it selects only the provided cell.
3058
- */
3059
- #StyleSelectCells(tdElement, shift) {
3060
- this.__s = shift;
3061
- if (!this._shift && !this._ref) this.__removeGlobalEvents();
3062
-
3063
- this._shift = shift;
3064
- this._fixedCell = tdElement;
3065
- if (!this._selectedCells?.length) this._selectedCells = [tdElement];
3066
- this._fixedCellName = tdElement.nodeName;
3067
- this._selectedTable = dom.query.getParentElement(tdElement, 'TABLE');
3068
-
3069
- this._deleteStyleSelectedCells();
3070
- dom.utils.addClass(tdElement, 'se-selected-cell-focus');
3071
-
3072
- if (!shift) {
3073
- this.__globalEvents.on = this.eventManager.addGlobalEvent('mousemove', this._bindMultiOn, false);
3074
- } else {
3075
- this.__globalEvents.shiftOff = this.eventManager.addGlobalEvent('keyup', this._bindShiftOff, false);
3076
- this.__globalEvents.on = this.eventManager.addGlobalEvent('mousedown', this._bindMultiOn, false);
3077
- }
3078
-
3079
- this.__globalEvents.off = this.eventManager.addGlobalEvent('mouseup', this._bindMultiOff, false);
3080
- this.__globalEvents.touchOff = this.eventManager.addGlobalEvent('touchmove', this._bindTouchOff, false);
3081
- }
3082
-
3083
- /**
3084
- * @description Splits a table cell either vertically or horizontally.
3085
- * @param {"vertical"|"horizontal"} direction The direction to split the cell.
3086
- */
3087
- #OnSplitCells(direction) {
3088
- const vertical = direction === 'vertical';
3089
- const currentCell = this._tdElement;
3090
- const rows = this._trElements;
3091
- const currentRow = this._trElement;
3092
- const index = this._logical_cellIndex;
3093
- const rowIndex = this._rowIndex;
3094
- const newCell = CreateCellsHTML(currentCell.nodeName);
3095
-
3096
- // vertical
3097
- if (vertical) {
3098
- const currentColSpan = currentCell.colSpan;
3099
- newCell.rowSpan = currentCell.rowSpan;
3100
-
3101
- // colspan > 1
3102
- if (currentColSpan > 1) {
3103
- newCell.colSpan = Math.floor(currentColSpan / 2);
3104
- currentCell.colSpan = currentColSpan - newCell.colSpan;
3105
- currentRow.insertBefore(newCell, currentCell.nextElementSibling);
3106
- } else {
3107
- // colspan - 1
3108
- let rowSpanArr = [];
3109
- let spanIndex = [];
3110
-
3111
- for (let i = 0, len = this._rowCnt, cells, colSpan; i < len; i++) {
3112
- cells = rows[i].cells;
3113
- colSpan = 0;
3114
- for (let c = 0, cLen = cells.length, cell, cs, rs, logcalIndex; c < cLen; c++) {
3115
- cell = cells[c];
3116
- cs = cell.colSpan - 1;
3117
- rs = cell.rowSpan - 1;
3118
- logcalIndex = c + colSpan;
3119
-
3120
- if (spanIndex.length > 0) {
3121
- for (let r = 0, arr; r < spanIndex.length; r++) {
3122
- arr = spanIndex[r];
3123
- if (arr.row > i) continue;
3124
- if (logcalIndex >= arr.index) {
3125
- colSpan += arr.cs;
3126
- logcalIndex += arr.cs;
3127
- arr.rs -= 1;
3128
- arr.row = i + 1;
3129
- if (arr.rs < 1) {
3130
- spanIndex.splice(r, 1);
3131
- r--;
3132
- }
3133
- } else if (c === cLen - 1) {
3134
- arr.rs -= 1;
3135
- arr.row = i + 1;
3136
- if (arr.rs < 1) {
3137
- spanIndex.splice(r, 1);
3138
- r--;
3139
- }
3140
- }
3141
- }
3142
- }
3143
-
3144
- if (logcalIndex <= index && rs > 0) {
3145
- rowSpanArr.push({
3146
- index: logcalIndex,
3147
- cs: cs + 1,
3148
- rs: rs,
3149
- row: -1
3150
- });
3151
- }
3152
-
3153
- if (cell !== currentCell && logcalIndex <= index && logcalIndex + cs >= index + currentColSpan - 1) {
3154
- cell.colSpan += 1;
3155
- break;
3156
- }
3157
-
3158
- if (logcalIndex > index) break;
3159
-
3160
- colSpan += cs;
3161
- }
3162
-
3163
- spanIndex = spanIndex.concat(rowSpanArr).sort(function (a, b) {
3164
- return a.index - b.index;
3165
- });
3166
- rowSpanArr = [];
3167
- }
3168
-
3169
- currentRow.insertBefore(newCell, currentCell.nextElementSibling);
3170
- }
3171
- } else {
3172
- // horizontal
3173
- const currentRowSpan = currentCell.rowSpan;
3174
- newCell.colSpan = currentCell.colSpan;
3175
-
3176
- // rowspan > 1
3177
- if (currentRowSpan > 1) {
3178
- newCell.rowSpan = Math.floor(currentRowSpan / 2);
3179
- const newRowSpan = currentRowSpan - newCell.rowSpan;
3180
-
3181
- const rowSpanArr = [];
3182
- const nextRowIndex = dom.utils.getArrayIndex(rows, currentRow) + newRowSpan;
3183
-
3184
- for (let i = 0, cells, colSpan; i < nextRowIndex; i++) {
3185
- cells = rows[i].cells;
3186
- colSpan = 0;
3187
- for (let c = 0, cLen = cells.length, cell, cs, logcalIndex; c < cLen; c++) {
3188
- logcalIndex = c + colSpan;
3189
- if (logcalIndex >= index) break;
3190
-
3191
- cell = cells[c];
3192
- cs = cell.rowSpan - 1;
3193
- if (cs > 0 && cs + i >= nextRowIndex && logcalIndex < index) {
3194
- rowSpanArr.push({
3195
- index: logcalIndex,
3196
- cs: cell.colSpan
3197
- });
3198
- }
3199
- colSpan += cell.colSpan - 1;
3200
- }
3201
- }
3202
-
3203
- const nextRow = rows[nextRowIndex];
3204
- const nextCells = nextRow.cells;
3205
- let rs = rowSpanArr.shift();
3206
-
3207
- for (let c = 0, cLen = nextCells.length, colSpan = 0, cell, cs, logcalIndex, insertIndex; c < cLen; c++) {
3208
- logcalIndex = c + colSpan;
3209
- cell = nextCells[c];
3210
- cs = cell.colSpan - 1;
3211
- insertIndex = logcalIndex + cs + 1;
3212
-
3213
- if (rs && insertIndex >= rs.index) {
3214
- colSpan += rs.cs;
3215
- insertIndex += rs.cs;
3216
- rs = rowSpanArr.shift();
3217
- }
3218
-
3219
- if (insertIndex >= index || c === cLen - 1) {
3220
- nextRow.insertBefore(newCell, cell.nextElementSibling);
3221
- break;
3222
- }
3223
-
3224
- colSpan += cs;
3225
- }
3226
-
3227
- currentCell.rowSpan = newRowSpan;
3228
- } else {
3229
- // rowspan - 1
3230
- newCell.rowSpan = currentCell.rowSpan;
3231
- const newRow = dom.utils.createElement('TR');
3232
- newRow.appendChild(newCell);
3233
-
3234
- for (let i = 0, cells; i < rowIndex; i++) {
3235
- cells = rows[i].cells;
3236
- if (cells.length === 0) return;
3237
-
3238
- for (let c = 0, cLen = cells.length; c < cLen; c++) {
3239
- if (i + cells[c].rowSpan - 1 >= rowIndex) {
3240
- cells[c].rowSpan += 1;
3241
- }
3242
- }
3243
- }
3244
-
3245
- const physicalIndex = this._physical_cellIndex;
3246
- const cells = currentRow.cells;
3247
-
3248
- for (let c = 0, cLen = cells.length; c < cLen; c++) {
3249
- if (c === physicalIndex) continue;
3250
- cells[c].rowSpan += 1;
3251
- }
3252
-
3253
- currentRow.parentNode.insertBefore(newRow, currentRow.nextElementSibling);
3254
- }
3255
- }
3256
-
3257
- this.selectMenu_split.close();
3258
- this.#focusEdge(currentCell);
3259
-
3260
- this._deleteStyleSelectedCells();
3261
- this.history.push(false);
3262
-
3263
- this._setController(currentCell);
3264
- this._selectedCell = this._fixedCell = currentCell;
3265
- if (!this._selectedCells?.length) this._selectedCells = [currentCell];
3266
- }
3267
-
3268
- /**
3269
- * @description Handles column operations such as insert and delete.
3270
- * @param {"insert-left"|"insert-right"|"delete"} command The column operation to perform.
3271
- */
3272
- #OnColumnEdit(command) {
3273
- switch (command) {
3274
- case 'insert-left':
3275
- this.editTable('cell', 'left');
3276
- break;
3277
- case 'insert-right':
3278
- this.editTable('cell', 'right');
3279
- break;
3280
- case 'delete':
3281
- this.editTable('cell', null);
3282
- }
3283
-
3284
- this._historyPush();
3285
- }
3286
-
3287
- /**
3288
- * @description Handles row operations such as insert and delete.
3289
- * @param {"insert-above"|"insert-below"|"delete"} command The row operation to perform.
3290
- */
3291
- #OnRowEdit(command) {
3292
- switch (command) {
3293
- case 'insert-above':
3294
- this.editTable('row', 'up');
3295
- break;
3296
- case 'insert-below':
3297
- this.editTable('row', 'down');
3298
- break;
3299
- case 'delete':
3300
- this.editTable('row', null);
3301
- }
3302
-
3303
- this._historyPush();
3304
- }
3305
-
3306
- /**
3307
- * @description Handles mouse movement within the table picker.
3308
- * @param {MouseEvent} e The mouse event.
3309
- */
3310
- #OnMouseMoveTablePicker(e) {
3311
- e.stopPropagation();
3312
-
3313
- let x = Math.ceil(e.offsetX / 18);
3314
- let y = Math.ceil(e.offsetY / 18);
3315
- x = x < 1 ? 1 : x;
3316
- y = y < 1 ? 1 : y;
3317
-
3318
- if (this.options.get('_rtl')) {
3319
- this.tableHighlight.style.left = x * 18 - 13 + 'px';
3320
- x = 11 - x;
3321
- }
3322
-
3323
- this.tableHighlight.style.width = x + 'em';
3324
- this.tableHighlight.style.height = y + 'em';
3325
-
3326
- const x_u = x < 5 ? 5 : x > 8 ? 10 : x + 2;
3327
- const y_u = y < 5 ? 5 : y > 8 ? 10 : y + 2;
3328
- this.tableUnHighlight.style.width = x_u + 'em';
3329
- this.tableUnHighlight.style.height = y_u + 'em';
3330
-
3331
- dom.utils.changeTxt(this.tableDisplay, x + ' x ' + y);
3332
- this._tableXY = [x, y];
3333
- }
3334
-
3335
- /**
3336
- * @description Executes the selected action when the table picker is clicked.
3337
- */
3338
- #OnClickTablePicker() {
3339
- this.action();
3340
- }
3341
-
3342
- /**
3343
- * @description Handles multi-selection of table cells.
3344
- * @param {MouseEvent} e The mouse event.
3345
- */
3346
- #OnCellMultiSelect(e) {
3347
- this.editor._preventBlur = true;
3348
- const target = /** @type {HTMLTableCellElement} */ (dom.query.getParentElement(dom.query.getEventTarget(e), dom.check.isTableCell));
3349
-
3350
- if (this._shift) {
3351
- if (target === this._fixedCell) {
3352
- this._shift = false;
3353
- this._deleteStyleSelectedCells();
3354
- this._toggleEditor(true);
3355
- this.__removeGlobalEvents();
3356
- return;
3357
- } else {
3358
- this._toggleEditor(false);
3359
- }
3360
- } else if (!this._ref) {
3361
- if (target === this._fixedCell) return;
3362
- else this._toggleEditor(false);
3363
- }
3364
-
3365
- if (!target || target === this._selectedCell || this._fixedCellName !== target.nodeName || this._selectedTable !== dom.query.getParentElement(target, 'TABLE')) {
3366
- return;
3367
- }
3368
-
3369
- this._setMultiCells(this._fixedCell, (this._selectedCell = target));
3370
- }
3371
-
3372
- /**
3373
- * @description Stops multi-selection of table cells.
3374
- * @param {MouseEvent} e The mouse event.
3375
- */
3376
- #OffCellMultiSelect(e) {
3377
- e.stopPropagation();
3378
-
3379
- if (!this._shift) {
3380
- this._toggleEditor(true);
3381
- this.__removeGlobalEvents();
3382
- } else if (this.__globalEvents.touchOff) {
3383
- this.__globalEvents.touchOff = this.eventManager.removeGlobalEvent(this.__globalEvents.touchOff);
3384
- }
3385
-
3386
- if (!this._fixedCell || !this._selectedTable) return;
3387
-
3388
- this._setMergeSplitButton();
3389
- this._selectedCells = Array.from(this._selectedTable.querySelectorAll('.se-selected-table-cell'));
3390
-
3391
- if (this._shift) return;
3392
-
3393
- if (this._fixedCell && this._selectedCell) {
3394
- this.#focusEdge(this._fixedCell);
3395
- if (this._fixedCell === this._selectedCell) {
3396
- dom.utils.removeClass(this._fixedCell, 'se-selected-table-cell');
3397
- }
3398
- }
3399
-
3400
- const displayCell = this._selectedCells?.length > 0 ? this._selectedCell : this._fixedCell;
3401
- this._setController(displayCell);
3402
- }
3403
-
3404
- /**
3405
- * @description Handles the removal of shift-based selection.
3406
- */
3407
- #OffCellShift() {
3408
- if (!this._ref) {
3409
- this._closeController();
3410
- } else {
3411
- this.__removeGlobalEvents();
3412
- this._toggleEditor(true);
3413
-
3414
- this.#focusEdge(this._fixedCell);
3415
-
3416
- const displayCell = this._selectedCells?.length > 0 ? this._selectedCell : this._fixedCell;
3417
- this._setController(displayCell);
3418
- }
3419
- }
3420
-
3421
- /**
3422
- * @description Handles the removal of touch-based selection.
3423
- */
3424
- #OffCellTouch() {
3425
- this.close();
3426
- }
3427
-
3428
- /**
3429
- * @description Focus cell
3430
- * @param {HTMLElement} cell Target node
3431
- */
3432
- #focusEdge(cell) {
3433
- if (!env.isMobile) this.editor.focusEdge(cell);
3434
- }
3435
- }
3436
-
3437
- /**
3438
- * @private
3439
- * @description Checks if the given node is a resizable table element.
3440
- * @param {Node} node The DOM node to check.
3441
- * @returns {boolean} True if the node is a table-related resizable element.
3442
- */
3443
- function IsResizeEls(node) {
3444
- return /^(TD|TH|TR)$/i.test(node?.nodeName);
3445
- }
3446
-
3447
- /**
3448
- * @private
3449
- * @description Checks if a table cell is at its edge based on the mouse event.
3450
- * @param {MouseEvent} event The mouse event.
3451
- * @param {Element} tableCell The table cell to check.
3452
- * @returns {Object} An object containing edge detection details.
3453
- */
3454
- function CheckCellEdge(event, tableCell) {
3455
- const startX = event.clientX;
3456
- const startWidth = numbers.get(_w.getComputedStyle(tableCell).width, CELL_DECIMAL_END);
3457
- const rect = tableCell.getBoundingClientRect();
3458
- const offsetX = Math.round(startX - rect.left);
3459
- const isLeft = offsetX <= CELL_SELECT_MARGIN;
3460
- const is = isLeft || startWidth - offsetX <= CELL_SELECT_MARGIN;
3461
-
3462
- return {
3463
- is,
3464
- isLeft,
3465
- startX
3466
- };
3467
- }
3468
-
3469
- /**
3470
- * @private
3471
- * @description Checks if a row is at its edge based on the mouse event.
3472
- * @param {MouseEvent} event The mouse event.
3473
- * @param {Element} tableCell The table row cell to check.
3474
- * @returns {Object} An object containing row edge detection details.
3475
- */
3476
- function CheckRowEdge(event, tableCell) {
3477
- const startY = event.clientY;
3478
- const startHeight = numbers.get(_w.getComputedStyle(tableCell).height, CELL_DECIMAL_END);
3479
- const rect = tableCell.getBoundingClientRect();
3480
- const is = Math.ceil(startHeight + rect.top - startY) <= ROW_SELECT_MARGIN;
3481
-
3482
- return {
3483
- is,
3484
- startY
3485
- };
3486
- }
3487
-
3488
- /**
3489
- * @private
3490
- * @description Creates table cells as elements strings.
3491
- * @param {string} nodeName The tag name of the cell (TD or TH).
3492
- * @param {number} cnt The number of cells to create.
3493
- * @returns {string} The created cells.
3494
- */
3495
- function CreateCellsString(nodeName, cnt) {
3496
- nodeName = nodeName.toLowerCase();
3497
- return `<${nodeName}><div><br></div></${nodeName}>`.repeat(cnt);
3498
- }
3499
-
3500
- /**
3501
- * @private
3502
- * @description Creates table cells as element HTML.
3503
- * @param {string} nodeName The tag name of the cell (TD or TH).
3504
- * @returns {HTMLTableCellElement} The created cells.
3505
- */
3506
- function CreateCellsHTML(nodeName) {
3507
- nodeName = nodeName.toLowerCase();
3508
- return /** @type {HTMLTableCellElement} */ (dom.utils.createElement(nodeName, null, '<div><br></div>'));
3509
- }
3510
-
3511
- /**
3512
- * @private
3513
- * @description Gets the maximum number of columns in a table.
3514
- * @param {HTMLTableElement} table The table element.
3515
- * @returns {number} The maximum number of columns in the table.
3516
- */
3517
- function GetMaxColumns(table) {
3518
- const rows = table.rows;
3519
- let maxColumns = 0;
3520
-
3521
- for (let i = 0, len = rows.length; i < len; i++) {
3522
- const cells = rows[i].cells;
3523
- let columnCount = 0;
3524
-
3525
- for (let j = 0, jLen = cells.length; j < jLen; j++) {
3526
- columnCount += cells[j].colSpan;
3527
- }
3528
-
3529
- maxColumns = Math.max(maxColumns, columnCount);
3530
- }
3531
-
3532
- return maxColumns;
3533
- }
3534
-
3535
- /**
3536
- * @private
3537
- * @description Handles border style changes in table properties.
3538
- * @param {string} command The border style command.
3539
- */
3540
- function OnPropsBorderEdit(command) {
3541
- this.propTargets.border_style.textContent = command;
3542
- this._disableBorderProps(command === BORDER_LIST[0]);
3543
- this.selectMenu_props_border.close();
3544
- }
3545
-
3546
- /**
3547
- * @private
3548
- * @description Handles border format changes in table properties.
3549
- * @param {string} defaultCommand The default border format command.
3550
- * @param {string} command The new border format command.
3551
- */
3552
- function OnPropsBorderFormatEdit(defaultCommand, command) {
3553
- const { border_format } = this.propTargets;
3554
-
3555
- border_format.setAttribute('se-border-format', command);
3556
- border_format.firstElementChild.innerHTML = this.icons[BORDER_FORMATS[command]];
3557
- if (command !== defaultCommand) dom.utils.addClass(border_format, 'active');
3558
- else dom.utils.removeClass(border_format, 'active');
3559
-
3560
- this.selectMenu_props_border_format.close();
3561
- this.selectMenu_props_border_format_oneCell.close();
3562
- }
3563
-
3564
- /**
3565
- * @description Creates the table properties controller.
3566
- * @param {ClipboardEvent} e - Event object
3567
- * @param {HTMLElement} container - The container element
3568
- * @param {NodeListOf<HTMLTableCellElement>} selectedCells - The selected table cells
3569
- */
3570
- function SetClipboardSelectedTableCells(e, container, selectedCells) {
3571
- e.preventDefault();
3572
- e.stopPropagation();
3573
-
3574
- const originalTable = selectedCells[0].closest('table');
3575
- const tempTable = originalTable.cloneNode(false);
3576
- const tbody = dom.utils.createElement('tbody');
3577
- tempTable.appendChild(tbody);
3578
-
3579
- const cellPositions = new Map();
3580
- selectedCells.forEach((cell) => {
3581
- cellPositions.set(cell, true);
3582
- });
3583
-
3584
- const rows = originalTable.rows;
3585
- const rowCount = rows.length;
3586
- const colCount = Array.from(rows[0].cells).reduce((sum, cell) => sum + (cell.colSpan || 1), 0);
3587
- const matrix = Array.from({ length: rowCount }, () => Array(colCount).fill(null));
3588
-
3589
- // build matrix
3590
- for (let r = 0, realRow = 0; r < rowCount; r++, realRow++) {
3591
- const cells = rows[r].cells;
3592
- for (let c = 0, realCol = 0, cLen = cells.length; c < cLen; c++) {
3593
- while (matrix[realRow][realCol]) realCol++;
3594
- const cell = cells[c];
3595
- const rowspan = cell.rowSpan || 1;
3596
- const colspan = cell.colSpan || 1;
3597
- for (let i = 0; i < rowspan; i++) {
3598
- for (let j = 0; j < colspan; j++) {
3599
- matrix[realRow + i][realCol + j] = cell;
3600
- }
3601
- }
3602
- realCol += colspan;
3603
- }
3604
- }
3605
-
3606
- // construct new table
3607
- for (let r = 0; r < rowCount; r++) {
3608
- let newRow;
3609
- for (let c = 0; c < colCount; c++) {
3610
- const cell = matrix[r][c];
3611
- if (!cell || !cellPositions.has(cell)) continue;
3612
-
3613
- if (!newRow) {
3614
- newRow = dom.utils.createElement('tr');
3615
- tbody.appendChild(newRow);
3616
- }
3617
-
3618
- if (newRow.lastChild && matrix[r][c - 1] === cell) continue;
3619
- if (r > 0 && matrix[r - 1][c] === cell) continue;
3620
-
3621
- const clonedCell = cell.cloneNode(true);
3622
-
3623
- // recalculate rowspan and colspan
3624
- let rowspan = 1;
3625
- let colspan = 1;
3626
- while (r + rowspan < rowCount && matrix[r + rowspan][c] === cell) rowspan++;
3627
- while (c + colspan < colCount && matrix[r][c + colspan] === cell) colspan++;
3628
-
3629
- if (rowspan > 1) clonedCell.rowSpan = rowspan;
3630
- if (colspan > 1) clonedCell.colSpan = colspan;
3631
-
3632
- newRow.appendChild(clonedCell);
3633
- }
3634
- }
3635
-
3636
- const figure = dom.utils.createElement('figure');
3637
- figure.className = container.className;
3638
- figure.appendChild(tempTable);
3639
-
3640
- const htmlContent = `<html><body><!--StartFragment-->${figure.outerHTML}<!--EndFragment--></body></html>`;
3641
- e.clipboardData.setData('text/html', htmlContent);
3642
- }
3643
-
3644
- function _CellFormZIndex(value) {
3645
- this.controller_cell.bringToTop(value);
3646
- }
3647
-
3648
- /** --------------------- HTML Create --------------------- */
3649
- // init element
3650
- function CreateSplitMenu(lang) {
3651
- const menus = dom.utils.createElement(
3652
- 'DIV',
3653
- null,
3654
- /*html*/ `
3655
- <div title="${lang.verticalSplit}" aria-label="${lang.verticalSplit}">
3656
- ${lang.verticalSplit}
3657
- </div>
3658
- <div title="${lang.horizontalSplit}" aria-label="${lang.horizontalSplit}">
3659
- ${lang.horizontalSplit}
3660
- </div>`
3661
- );
3662
-
3663
- return { items: ['vertical', 'horizontal'], menus: menus.querySelectorAll('div') };
3664
- }
3665
-
3666
- function CreateColumnMenu(lang, icons) {
3667
- const menus = dom.utils.createElement(
3668
- 'DIV',
3669
- null,
3670
- /*html*/ `
3671
- <div title="${lang.insertColumnBefore}" aria-label="${lang.insertColumnBefore}">
3672
- <span class="se-list-icon">${icons.insert_column_left}</span><span class="se-txt">${lang.insertColumnBefore}</span>
3673
- </div>
3674
- <div title="${lang.insertColumnAfter}" aria-label="${lang.insertColumnAfter}">
3675
- <span class="se-list-icon">${icons.insert_column_right}</span><span class="se-txt">${lang.insertColumnAfter}</span>
3676
- </div>
3677
- <div title="${lang.deleteColumn}" aria-label="${lang.deleteColumn}">
3678
- <span class="se-list-icon">${icons.delete_column}</span><span class="se-txt">${lang.deleteColumn}</span>
3679
- </div>`
3680
- );
3681
-
3682
- return { items: ['insert-left', 'insert-right', 'delete'], menus: menus.querySelectorAll('div') };
3683
- }
3684
-
3685
- function CreateRowMenu(lang, icons) {
3686
- const menus = dom.utils.createElement(
3687
- 'DIV',
3688
- null,
3689
- /*html*/ `
3690
- <div title="${lang.insertRowAbove}" aria-label="${lang.insertRowAbove}">
3691
- <span class="se-list-icon">${icons.insert_row_above}</span><span class="se-txt">${lang.insertRowAbove}</span>
3692
- </div>
3693
- <div title="${lang.insertRowBelow}" aria-label="${lang.insertRowBelow}">
3694
- <span class="se-list-icon">${icons.insert_row_below}</span><span class="se-txt">${lang.insertRowBelow}</span>
3695
- </div>
3696
- <div title="${lang.deleteRow}" aria-label="${lang.deleteRow}">
3697
- <span class="se-list-icon">${icons.delete_row}</span><span class="se-txt">${lang.deleteRow}</span>
3698
- </div>`
3699
- );
3700
-
3701
- return { items: ['insert-above', 'insert-below', 'delete'], menus: menus.querySelectorAll('div') };
3702
- }
3703
-
3704
- function CreateBorderMenu() {
3705
- let html = '';
3706
-
3707
- for (let i = 0, len = BORDER_LIST.length, s; i < len; i++) {
3708
- s = BORDER_LIST[i];
3709
- html += /*html*/ `
3710
- <div title="${s}" aria-label="${s}" style="padding: 0 12px;">
3711
- <span class="se-txt">${s}</span>
3712
- </div>`;
3713
- }
3714
-
3715
- const menus = dom.utils.createElement('DIV', null, html);
3716
- return { items: BORDER_LIST, menus: menus.querySelectorAll('div') };
3717
- }
3718
-
3719
- function CreateBorderFormatMenu(langs, icons, indideFormats) {
3720
- const items = [];
3721
- let html = '';
3722
-
3723
- for (const k in BORDER_FORMATS) {
3724
- if (indideFormats.includes(k)) continue;
3725
- const s = BORDER_FORMATS[k];
3726
- items.push(k);
3727
- html += /*html*/ `
3728
- <button type="button" class="se-btn se-tooltip">
3729
- ${icons[s]}
3730
- <span class="se-tooltip-inner">
3731
- <span class="se-tooltip-text">${langs[s]}</span>
3732
- </span>
3733
- </button>`;
3734
- }
3735
-
3736
- const menus = dom.utils.createElement('DIV', null, html);
3737
- return { items, menus: menus.querySelectorAll('button') };
3738
- }
3739
-
3740
- function CreateHTML() {
3741
- const html = /*html*/ `
3742
- <div class="se-table-size">
3743
- <div class="se-table-size-picker se-controller-table-picker"></div>
3744
- <div class="se-table-size-highlighted"></div>
3745
- <div class="se-table-size-unhighlighted"></div>
3746
- </div>
3747
- <div class="se-table-size-display">1 x 1</div>`;
3748
-
3749
- return dom.utils.createElement('DIV', { class: 'se-dropdown se-selector-table' }, html);
3750
- }
3751
-
3752
- function CreateHTML_controller_table({ lang, icons }) {
3753
- const html = /*html*/ `
3754
- <div class="se-arrow se-arrow-down se-visible-hidden"></div>
3755
- <div class="se-btn-group">
3756
- <button type="button" data-command="openTableProperties" class="se-btn se-tooltip">
3757
- ${icons.table_properties}
3758
- <span class="se-tooltip-inner">
3759
- <span class="se-tooltip-text">${lang.tableProperties}</span>
3760
- </span>
3761
- </button>
3762
- <button type="button" data-command="layout" class="se-btn se-tooltip _se_table_fixed_column">
3763
- ${icons.fixed_column_width}
3764
- <span class="se-tooltip-inner">
3765
- <span class="se-tooltip-text">${lang.fixedColumnWidth}</span>
3766
- </span>
3767
- </button>
3768
- <button type="button" data-command="header" class="se-btn se-tooltip _se_table_header">
3769
- ${icons.table_header}
3770
- <span class="se-tooltip-inner">
3771
- <span class="se-tooltip-text">${lang.tableHeader}</span>
3772
- </span>
3773
- </button>
3774
- <button type="button" data-command="caption" class="se-btn se-tooltip _se_table_caption">
3775
- ${icons.caption}
3776
- <span class="se-tooltip-inner">
3777
- <span class="se-tooltip-text">${lang.caption}</span>
3778
- </span>
3779
- </button>
3780
- <button type="button" data-command="resize" class="se-btn se-tooltip _se_table_resize">
3781
- ${icons.reduction}
3782
- <span class="se-tooltip-inner">
3783
- <span class="se-tooltip-text">${lang.minSize}</span>
3784
- </span>
3785
- </button>
3786
- <button type="button" data-command="copy" class="se-btn se-tooltip">
3787
- ${icons.copy}
3788
- <span class="se-tooltip-inner">
3789
- <span class="se-tooltip-text">${lang.copy}</span>
3790
- </span>
3791
- </button>
3792
- <button type="button" data-command="remove" class="se-btn se-tooltip">
3793
- ${icons.delete}
3794
- <span class="se-tooltip-inner">
3795
- <span class="se-tooltip-text">${lang.remove}</span>
3796
- </span>
3797
- </button>
3798
- </div>`;
3799
-
3800
- return dom.utils.createElement('DIV', { class: 'se-controller se-controller-table' }, html);
3801
- }
3802
-
3803
- /**
3804
- * @param {__se__EditorCore} editor
3805
- * @returns {{ html: HTMLElement, splitButton: HTMLButtonElement, columnButton: HTMLButtonElement, rowButton: HTMLButtonElement, mergeButton: HTMLButtonElement, unmergeButton: HTMLButtonElement }}
3806
- */
3807
- function CreateHTML_controller_cell({ lang, icons }, cellControllerTop) {
3808
- const html = /*html*/ `
3809
- <div class="se-arrow se-arrow-${cellControllerTop ? 'down se-visible-hidden' : 'up'}"></div>
3810
- <div class="se-btn-group">
3811
- <button type="button" data-command="openCellProperties" class="se-btn se-tooltip">
3812
- ${icons.cell_properties}
3813
- <span class="se-tooltip-inner">
3814
- <span class="se-tooltip-text">${lang.cellProperties}</span>
3815
- </span>
3816
- </button>
3817
- <button type="button" data-command="oncolumn" class="se-btn se-tooltip">
3818
- ${icons.table_column}
3819
- <span class="se-tooltip-inner">
3820
- <span class="se-tooltip-text">${lang.column}</span>
3821
- </span>
3822
- </button>
3823
- <button type="button" data-command="onrow" class="se-btn se-tooltip">
3824
- ${icons.table_row}
3825
- <span class="se-tooltip-inner">
3826
- <span class="se-tooltip-text">${lang.row}</span>
3827
- </span>
3828
- </button>
3829
- <button type="button" data-command="merge" class="se-btn se-tooltip" style="display: none;">
3830
- ${icons.merge_cell}
3831
- <span class="se-tooltip-inner">
3832
- <span class="se-tooltip-text">${lang.mergeCells}</span>
3833
- </span>
3834
- </button>
3835
- <button type="button" data-command="onsplit" class="se-btn se-tooltip">
3836
- ${icons.split_cell}
3837
- <span class="se-tooltip-inner">
3838
- <span class="se-tooltip-text">${lang.splitCells}</span>
3839
- </span>
3840
- </button>
3841
- <button type="button" data-command="unmerge" class="se-btn se-tooltip">
3842
- ${icons.unmerge_cell}
3843
- <span class="se-tooltip-inner">
3844
- <span class="se-tooltip-text">${lang.unmergeCells}</span>
3845
- </span>
3846
- </button>
3847
- </div>`;
3848
-
3849
- const content = dom.utils.createElement('DIV', { class: 'se-controller se-controller-table-cell' }, html);
3850
-
3851
- return {
3852
- html: content,
3853
- splitButton: content.querySelector('[data-command="onsplit"]'),
3854
- columnButton: content.querySelector('[data-command="oncolumn"]'),
3855
- rowButton: content.querySelector('[data-command="onrow"]'),
3856
- mergeButton: content.querySelector('[data-command="merge"]'),
3857
- unmergeButton: content.querySelector('[data-command="unmerge"]')
3858
- };
3859
- }
3860
-
3861
- /**
3862
- * @typedef {Object} TableCtrlProps
3863
- * @property {HTMLElement} html
3864
- * @property {HTMLElement} controller_props_title
3865
- * @property {HTMLButtonElement} borderButton
3866
- * @property {HTMLButtonElement} borderFormatButton
3867
- * @property {HTMLElement} cell_alignment
3868
- * @property {HTMLElement} cell_alignment_vertical
3869
- * @property {HTMLElement} cell_alignment_table_text
3870
- * @property {HTMLButtonElement} border_style
3871
- * @property {HTMLInputElement} border_color
3872
- * @property {HTMLInputElement} border_width
3873
- * @property {HTMLInputElement} back_color
3874
- * @property {HTMLInputElement} font_color
3875
- * @property {HTMLButtonElement} palette_border_button
3876
- * @property {HTMLButtonElement} font_bold
3877
- * @property {HTMLButtonElement} font_underline
3878
- * @property {HTMLButtonElement} font_italic
3879
- * @property {HTMLButtonElement} font_strike
3880
- *
3881
- * @param {__se__EditorCore} editor - Editor instance
3882
- * @returns {TableCtrlProps}
3883
- */
3884
- function CreateHTML_controller_properties({ lang, icons, options }) {
3885
- const alignItems = options.get('_rtl') ? ['right', 'center', 'left', 'justify'] : ['left', 'center', 'right', 'justify'];
3886
- let alignHtml = '';
3887
- for (let i = 0, item, text; i < alignItems.length; i++) {
3888
- item = alignItems[i];
3889
- text = lang['align' + item.charAt(0).toUpperCase() + item.slice(1)];
3890
- alignHtml += /*html*/ `
3891
- <button type="button" class="se-btn se-tooltip" data-command="props_align" data-value="${item}" title="${text}" aria-label="${text}">
3892
- ${icons['align_' + item]}
3893
- <span class="se-tooltip-inner">
3894
- <span class="se-tooltip-text">${text}</span>
3895
- </span>
3896
- </button>`;
3897
- }
3898
-
3899
- // vertical align html
3900
- const verticalAligns = ['top', 'middle', 'bottom'];
3901
- let verticalAlignHtml = '';
3902
- for (let i = 0, item, text; i < verticalAligns.length; i++) {
3903
- item = verticalAligns[i];
3904
- text = lang['align' + item.charAt(0).toUpperCase() + item.slice(1)];
3905
- verticalAlignHtml += /*html*/ `
3906
- <button type="button" class="se-btn se-tooltip" data-command="props_align_vertical" data-value="${item}" title="${text}" aria-label="${text}">
3907
- ${icons['align_' + item]}
3908
- <span class="se-tooltip-inner">
3909
- <span class="se-tooltip-text">${text}</span>
3910
- </span>
3911
- </button>`;
3912
- }
3913
-
3914
- const html = /*html*/ `
3915
- <div class="se-controller-content">
3916
- <div class="se-controller-header">
3917
- <button type="button" data-command="close_props" class="se-btn se-close-btn close" title="${lang.close}" aria-label="${lang.close}">${icons.cancel}</button>
3918
- <span class="se-controller-title">${lang.tableProperties}</span>
3919
- </div>
3920
- <div class="se-controller-body">
3921
-
3922
- <label>${lang.border}</label>
3923
- <div class="se-form-group se-form-w0">
3924
- <button type="button" data-command="props_onborder_format" class="se-btn se-tooltip">
3925
- ${icons[BORDER_FORMATS.all]}
3926
- <span class="se-tooltip-inner">
3927
- <span class="se-tooltip-text">${lang.border}</span>
3928
- </span>
3929
- </button>
3930
- <button type="button" data-command="props_onborder_style" class="se-btn se-btn-select se-tooltip se-border-style">
3931
- <span class="se-txt"></span>
3932
- ${icons.arrow_down}
3933
- <span class="se-tooltip-inner">
3934
- <span class="se-tooltip-text">${lang.border}</span>
3935
- </span>
3936
- </button>
3937
- <input type="text" class="se-color-input __se_border_color" placeholder="${lang.color}" />
3938
- <button type="button" data-command="props_onpalette" data-value="border" class="se-btn se-tooltip">
3939
- ${icons.color_palette}
3940
- <span class="se-tooltip-inner">
3941
- <span class="se-tooltip-text">${lang.colorPicker}</span>
3942
- </span>
3943
- </button>
3944
- <input type="text" class="se-input-control __se__border_size" placeholder="${lang.width}" />
3945
- </div>
3946
-
3947
- <label>${lang.color}</label>
3948
- <div class="se-form-group se-form-w0">
3949
- <button type="button" data-command="props_onpalette" data-value="font" class="se-btn se-tooltip">
3950
- ${icons.font_color}
3951
- <span class="se-tooltip-inner">
3952
- <span class="se-tooltip-text">${lang.fontColor}</span>
3953
- </span>
3954
- </button>
3955
- <input type="text" class="se-color-input __se_font_color" placeholder="${lang.fontColor}" />
3956
- <button type="button" data-command="props_onpalette" data-value="back" class="se-btn se-tooltip">
3957
- ${icons.background_color}
3958
- <span class="se-tooltip-inner">
3959
- <span class="se-tooltip-text">${lang.backgroundColor}</span>
3960
- </span>
3961
- </button>
3962
- <input type="text" class="se-color-input __se_back_color" placeholder="${lang.backgroundColor}" />
3963
- </div>
3964
-
3965
- <label>${lang.font}</label>
3966
- <div class="se-form-group se-form-w0">
3967
- <button type="button" data-command="props_font_style" data-value="bold" class="se-btn se-tooltip">
3968
- ${icons.bold}
3969
- <span class="se-tooltip-inner">
3970
- <span class="se-tooltip-text">${lang.bold}</span>
3971
- </span>
3972
- </button>
3973
- <button type="button" data-command="props_font_style" data-value="underline" class="se-btn se-tooltip">
3974
- ${icons.underline}
3975
- <span class="se-tooltip-inner">
3976
- <span class="se-tooltip-text">${lang.underline}</span>
3977
- </span>
3978
- </button>
3979
- <button type="button" data-command="props_font_style" data-value="italic" class="se-btn se-tooltip">
3980
- ${icons.italic}
3981
- <span class="se-tooltip-inner">
3982
- <span class="se-tooltip-text">${lang.italic}</span>
3983
- </span>
3984
- </button>
3985
- <button type="button" data-command="props_font_style" data-value="strike" class="se-btn se-tooltip">
3986
- ${icons.strike}
3987
- <span class="se-tooltip-inner">
3988
- <span class="se-tooltip-text">${lang.strike}</span>
3989
- </span>
3990
- </button>
3991
- </div>
3992
-
3993
- <div class="se-table-props-align">
3994
- <label>${lang.align} <span class="__se__a_table_t">( ${lang.table} )</span></label>
3995
- <div class="se-form-group se-form-w0 se-list-inner">
3996
- <div class="__se__a_h">
3997
- ${alignHtml}
3998
- </div>
3999
- <div class="__se__a_v">
4000
- ${verticalAlignHtml}
4001
- </div>
4002
- </div>
4003
- </div>
4004
- </div>
4005
- <div class="se-form-group se-form-w0 se-form-flex-btn">
4006
- <button type="button" class="se-btn se-btn-success" data-command="props_submit" title="${lang.submitButton}" aria-label="${lang.submitButton}">${icons.checked}</button>
4007
- <button type="button" class="se-btn se-btn-danger" data-command="revert" title="${lang.revert}" aria-label="${lang.revert}">${icons.revert}</button>
4008
- </div>
4009
- </div>`;
4010
-
4011
- const content = dom.utils.createElement('DIV', { class: 'se-controller se-table-props' }, html);
4012
-
4013
- return {
4014
- html: content,
4015
- controller_props_title: content.querySelector('.se-controller-title'),
4016
- borderButton: content.querySelector('[data-command="props_onborder_style"]'),
4017
- borderFormatButton: content.querySelector('[data-command="props_onborder_format"]'),
4018
- cell_alignment: content.querySelector('.se-table-props-align .__se__a_h'),
4019
- cell_alignment_vertical: content.querySelector('.se-table-props-align .__se__a_v'),
4020
- cell_alignment_table_text: content.querySelector('.se-table-props-align .__se__a_table_t'),
4021
- border_style: content.querySelector('[data-command="props_onborder_style"] .se-txt'),
4022
- border_color: content.querySelector('.__se_border_color'),
4023
- border_width: content.querySelector('.__se__border_size'),
4024
- back_color: content.querySelector('.__se_back_color'),
4025
- font_color: content.querySelector('.__se_font_color'),
4026
- palette_border_button: content.querySelector('[data-command="props_onpalette"][data-value="border"]'),
4027
- font_bold: content.querySelector('[data-command="props_font_style"][data-value="bold"]'),
4028
- font_underline: content.querySelector('[data-command="props_font_style"][data-value="underline"]'),
4029
- font_italic: content.querySelector('[data-command="props_font_style"][data-value="italic"]'),
4030
- font_strike: content.querySelector('[data-command="props_font_style"][data-value="strike"]')
4031
- };
4032
- }
4033
-
4034
- export default Table;